@sentry/wizard
Version:
Sentry wizard helping you to configure your project
152 lines (139 loc) • 4.27 kB
text/typescript
import type { Answers } from 'inquirer';
import { prompt } from 'inquirer';
import * as _ from 'lodash';
import { dim } from '../Helper/Logging';
import { getCurrentIntegration } from '../Helper/Wizard';
import { BaseStep } from './BaseStep';
export class PromptForParameters extends BaseStep {
public async emit(answers: Answers): Promise<Answers> {
this.debug(answers);
if (!(await getCurrentIntegration(answers).shouldEmit(answers))) {
return {};
}
if (this._argv.quiet) {
return {};
}
let url = this._getFullUrl(answers);
const organization: any = await prompt([
{
message: 'Organization Slug:',
name: 'slug',
type: 'input',
// eslint-disable-next-line @typescript-eslint/unbound-method
validate: this._validateSlug,
when: this._shouldAsk(answers, 'config.organization.slug', () => {
dim('Please copy/paste your organization slug');
dim(`It can be found in the url ${url}`);
}),
},
]);
url = this._getFullUrl(answers, organization.slug);
const project: any = await prompt([
{
message: 'Project Slug:',
name: 'slug',
type: 'input',
// eslint-disable-next-line @typescript-eslint/unbound-method
validate: this._validateSlug,
when: this._shouldAsk(answers, 'config.project.slug', () => {
dim('Please copy/paste your project slug');
dim(`It can be found in the url ${url}`);
}),
},
]);
url = this._getFullUrl(answers, organization.slug, project.slug);
const dsn = await prompt([
{
message: 'DSN:',
name: 'secret',
type: 'input',
// eslint-disable-next-line @typescript-eslint/unbound-method
validate: this._validateDSN,
when: this._shouldAsk(answers, 'config.dsn.secret', () => {
dim('Please copy/paste your DSN');
dim(`It can be found here: ${url}`);
}),
},
]);
const auth = await prompt([
{
message: 'Auth Token:',
name: 'token',
type: 'input',
// eslint-disable-next-line @typescript-eslint/unbound-method
validate: this._validateAuthToken,
when: this._shouldAsk(answers, 'config.auth.token', () => {
dim('Please copy/paste your auth token');
dim(`It can be found here: ${this._argv.url}api/`);
dim(
'In case there is none yet, create one with [project:releases] permission',
);
}),
},
]);
return {
config: _.merge(_.get(answers, 'config'), {
auth,
dsn,
project,
organization,
}),
};
}
private _getFullUrl(
answers: Answers,
organizationSlug?: string,
projectSlug?: string,
): string {
const baseUrl = this._argv.url;
const orgSlug = _.get(
answers,
'config.organization.slug',
organizationSlug || 'organization_slug',
);
const projSlug = _.get(
answers,
'config.project.slug',
projectSlug || 'project_slug',
);
return `${baseUrl}${orgSlug}/${projSlug}`;
}
private _shouldAsk(
answers: Answers,
configKey: string,
preHook?: () => void,
): boolean {
const shouldAsk = _.get(answers, configKey, null) === null;
if (shouldAsk && preHook) {
preHook();
}
return shouldAsk;
}
private _validateAuthToken(input: string): boolean | string {
if (!input.match(/[0-9a-f]{64}/g)) {
return 'Make sure you copied the correct auth token, it should be 64 hex chars';
}
return true;
}
private _validateSlug(input: string): boolean | string {
if (input.match(/[A-Z]/g)) {
return 'Please copy the slug from the url, it should be all lowercase';
}
if (input.length === 0) {
return "Can't be empty";
}
return true;
}
private _validateDSN(input: string): boolean | string {
const match = input.match(
/^(?:(\w+):)?\/\/(?:(\w+)(:\w+)?@)?([\w.-]+)(?::(\d+))?(\/.*)$/,
);
if (!match) {
return 'Invalid DSN format';
}
if (match[1] !== 'http' && match[1] !== 'https') {
return `Unsupported protocol for DSN: ${match[1]}`;
}
return true;
}
}