@sentry/wizard
Version:
Sentry wizard helping you to configure your project
149 lines (134 loc) • 5.07 kB
text/typescript
import * as fs from 'fs';
import type { Answers } from 'inquirer';
import * as _ from 'lodash';
import * as path from 'path';
import type { Args } from '../Constants';
import { addToGitignore } from './Git';
import { green, l, nl, red } from './Logging';
const SENTRYCLIRC_FILENAME = '.sentryclirc';
const GITIGNORE_FILENAME = '.gitignore';
const PROPERTIES_FILENAME = 'sentry.properties';
export interface SentryCliProps {
[s: string]: string;
}
type SentryCliConfig = Record<string, SentryCliProps>;
export class SentryCli {
// eslint-disable-next-line @typescript-eslint/typedef
private _resolve = require.resolve;
public constructor(protected _argv: Args) {}
public setResolveFunction(resolve: (path: string) => string): void {
this._resolve = resolve as any;
}
public convertAnswersToProperties(answers: Answers): SentryCliProps {
const props: SentryCliProps = {};
props['defaults/url'] = this._argv.url;
props['defaults/org'] = _.get(answers, 'config.organization.slug', null);
props['defaults/project'] = _.get(answers, 'config.project.slug', null);
props['auth/token'] = _.get(answers, 'config.auth.token', null);
try {
const cliPath = this._resolve('@sentry/cli/bin/sentry-cli', {
paths: [process.cwd()],
});
props['cli/executable'] = path
.relative(process.cwd(), cliPath)
.replace(/\\/g, '\\\\');
} catch (e) {
// we do nothing and leave everyting as it is
}
return props;
}
/** Create the contents of a `sentry.properties` file */
public dumpProperties(props: SentryCliProps): string {
const rv = [];
for (let key in props) {
// eslint-disable-next-line no-prototype-builtins
if (props.hasOwnProperty(key)) {
const value = props[key];
key = key.replace(/\//g, '.');
if (value === undefined || value === null) {
// comment that property out since it has no value
rv.push(`#${key}=`);
} else {
rv.push(`${key}=${value}`);
}
}
}
// eslint-disable-next-line prefer-template
return rv.join('\n') + '\n';
}
public dumpConfig(config: SentryCliConfig): string {
const dumpedSections: string[] = [];
for (const sectionName in config) {
// eslint-disable-next-line no-prototype-builtins
if (config.hasOwnProperty(sectionName)) {
const props = this.dumpProperties(config[sectionName]);
const section = `[${sectionName}]\n${props}`;
dumpedSections.push(section);
}
}
return dumpedSections.join('\n');
}
/**
* Creates `.sentryclirc` and `sentry.properties` files with the CLI properties
* obtained from the user answers (or from logging into Sentry).
* The `.sentryclirc` only contains the auth token and will be added to the
* user's `.gitignore` file. The properties file contains the rest of the
* properties (org, project, etc.).
*
* @param sentryCli instance of the Sentry CLI
* @param cliProps the properties to write to the files
*/
public async createSentryCliConfig(cliProps: SentryCliProps): Promise<void> {
const { 'auth/token': authToken, ...cliPropsToWrite } = cliProps;
/**
* To not commit the auth token to the VCS, instead of adding it to the
* properties file (like the rest of props), it's added to the Sentry CLI
* config, which is added to the gitignore. This way makes the properties
* file safe to commit without exposing any auth tokens.
*/
if (authToken) {
try {
await fs.promises.appendFile(
SENTRYCLIRC_FILENAME,
this.dumpConfig({ auth: { token: authToken } }),
);
green(`✓ Successfully added the auth token to ${SENTRYCLIRC_FILENAME}`);
} catch {
red(
`⚠ Could not add the auth token to ${SENTRYCLIRC_FILENAME}, ` +
`please add it to identify your user account:\n${authToken}`,
);
nl();
}
} else {
red(
`⚠ Did not find an auth token, please add your token to ${SENTRYCLIRC_FILENAME}`,
);
l(
'To generate an auth token, visit https://sentry.io/settings/account/api/auth-tokens/',
);
l(
'To learn how to configure Sentry CLI, visit ' +
'https://docs.sentry.io/platforms/javascript/guides/nextjs/manual-setup/#configure-sentry-cli',
);
}
await addToGitignore(
SENTRYCLIRC_FILENAME,
`⚠ Could not add ${SENTRYCLIRC_FILENAME} to ${GITIGNORE_FILENAME}, ` +
'please add it to not commit your auth key.',
);
try {
await fs.promises.writeFile(
`./${PROPERTIES_FILENAME}`,
this.dumpProperties(cliPropsToWrite),
);
green('✓ Successfully created sentry.properties');
} catch {
red(`⚠ Could not add org and project data to ${PROPERTIES_FILENAME}`);
l(
'See docs for a manual setup: https://docs.sentry.io/platforms/javascript/guides/nextjs/manual-setup/#configure-sentry-cli',
);
}
nl();
}
}