cli: Remember provider selection from auth setup when setting up software templates
Signed-off-by: Marcus Eide <eide@spotify.com>
This commit is contained in:
committed by
Philipp Hugenroth
parent
8e254c06bc
commit
b590c95ed8
@@ -23,7 +23,7 @@ import { updateConfigFile } from '../../config';
|
||||
import { APP_CONFIG_FILE, PATCH_FOLDER } from '../../files';
|
||||
import { patch } from '../patch';
|
||||
|
||||
type Answers = {
|
||||
export type Answers = {
|
||||
clientSecret: string;
|
||||
clientId: string;
|
||||
hasEnterprise: boolean;
|
||||
@@ -76,7 +76,7 @@ const getConfig = (answers: Answers) => {
|
||||
};
|
||||
};
|
||||
|
||||
export const github = async () => {
|
||||
export const github = async (): Promise<Answers> => {
|
||||
Task.log(`
|
||||
To add GitHub authentication, you must create an OAuth App from the GitHub developer settings: ${chalk.blue(
|
||||
'https://github.com/settings/developers',
|
||||
@@ -142,4 +142,6 @@ export const github = async () => {
|
||||
await patch(patchFile);
|
||||
});
|
||||
}
|
||||
|
||||
return answers;
|
||||
};
|
||||
|
||||
@@ -42,14 +42,14 @@ const getConfig = (answers: Answers) => {
|
||||
};
|
||||
};
|
||||
|
||||
type Answers = {
|
||||
export type Answers = {
|
||||
clientSecret: string;
|
||||
clientId: string;
|
||||
hasAudience: boolean;
|
||||
audience?: string;
|
||||
};
|
||||
|
||||
export const gitlab = async () => {
|
||||
export const gitlab = async (): Promise<Answers> => {
|
||||
Task.log(`
|
||||
To add GitLab authentication, you must create an Application from the GitLab Settings: ${chalk.blue(
|
||||
'https://gitlab.com/-/profile/applications',
|
||||
@@ -110,4 +110,6 @@ export const gitlab = async () => {
|
||||
await patch(patchFile);
|
||||
});
|
||||
}
|
||||
|
||||
return answers;
|
||||
};
|
||||
|
||||
@@ -14,44 +14,50 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import chalk from 'chalk';
|
||||
import inquirer from 'inquirer';
|
||||
import { Task } from '../../../lib/tasks';
|
||||
import { github } from './github';
|
||||
import { gitlab } from './gitlab';
|
||||
import { github, Answers as GitHubAnswers } from './github';
|
||||
import { gitlab, Answers as GitLabAnswers } from './gitlab';
|
||||
|
||||
export async function auth(): Promise<void> {
|
||||
export { type GitHubAnswers, type GitLabAnswers };
|
||||
|
||||
export async function auth(): Promise<{
|
||||
provider: string;
|
||||
answers: GitHubAnswers | GitLabAnswers;
|
||||
}> {
|
||||
const answers = await inquirer.prompt<{
|
||||
provider?: string;
|
||||
provider: string;
|
||||
}>([
|
||||
{
|
||||
type: 'list',
|
||||
name: 'provider',
|
||||
message: 'Please select a provider:',
|
||||
message: 'Please select an authentication provider:',
|
||||
choices: ['GitHub', 'GitLab'],
|
||||
},
|
||||
]);
|
||||
|
||||
const { provider } = answers;
|
||||
|
||||
let providerAnswers;
|
||||
switch (provider) {
|
||||
case 'GitHub': {
|
||||
await github();
|
||||
providerAnswers = await github();
|
||||
break;
|
||||
}
|
||||
case 'GitLab': {
|
||||
await gitlab();
|
||||
providerAnswers = await gitlab();
|
||||
break;
|
||||
}
|
||||
default:
|
||||
throw new Error(`Provider ${provider} not implemented yet.`);
|
||||
}
|
||||
|
||||
Task.log();
|
||||
Task.log(`Done setting up ${provider} Authentication!`);
|
||||
Task.log();
|
||||
Task.log(
|
||||
`You can now start your app with ${chalk.inverse(
|
||||
chalk.italic('yarn dev'),
|
||||
)}`,
|
||||
);
|
||||
|
||||
return {
|
||||
provider,
|
||||
answers: providerAnswers,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -16,55 +16,54 @@
|
||||
|
||||
import chalk from 'chalk';
|
||||
import inquirer from 'inquirer';
|
||||
import { Task } from '../../lib/tasks';
|
||||
import { auth } from './auth';
|
||||
import { integrations } from './integrations';
|
||||
|
||||
export async function command(): Promise<void> {
|
||||
try {
|
||||
// TODO(tudi2d): Is there a way to make this cleaner?
|
||||
const answers = await inquirer.prompt<{
|
||||
shouldSetupAuth: boolean;
|
||||
}>([
|
||||
{
|
||||
type: 'confirm',
|
||||
name: 'shouldSetupAuth',
|
||||
message: 'Do you want to set up Authentication for this project?',
|
||||
default: true,
|
||||
},
|
||||
]);
|
||||
const answers = await inquirer.prompt<{
|
||||
shouldSetupAuth: boolean;
|
||||
shouldSetupScaffolder: boolean;
|
||||
}>([
|
||||
{
|
||||
type: 'confirm',
|
||||
name: 'shouldSetupAuth',
|
||||
message: 'Do you want to set up Authentication for this project?',
|
||||
default: true,
|
||||
},
|
||||
{
|
||||
type: 'confirm',
|
||||
name: 'shouldSetupScaffolder',
|
||||
message: 'Do you want to use Software Templates in this project?',
|
||||
default: true,
|
||||
},
|
||||
]);
|
||||
|
||||
if (!answers.shouldSetupAuth) {
|
||||
console.log(
|
||||
chalk.yellow(
|
||||
'If you change your mind, feel free to re-run this command.',
|
||||
),
|
||||
);
|
||||
} else {
|
||||
await auth();
|
||||
}
|
||||
const { shouldSetupAuth, shouldSetupScaffolder } = answers;
|
||||
|
||||
// TODO(tudi2d): Select "Core Features" here such that we can determin if the integrations need to be setup for either Catalog, Scaffollder or both
|
||||
await inquirer
|
||||
.prompt<{
|
||||
setupScaffolder: boolean;
|
||||
}>([
|
||||
{
|
||||
type: 'confirm',
|
||||
name: 'setupScaffolder',
|
||||
message: 'Do you want to setup Sofware Templates?',
|
||||
default: true,
|
||||
},
|
||||
])
|
||||
.then(async ({ setupScaffolder }) =>
|
||||
setupScaffolder
|
||||
? await integrations()
|
||||
: console.log(
|
||||
chalk.yellow(
|
||||
'If you change your mind, feel free to re-run this command.',
|
||||
),
|
||||
),
|
||||
);
|
||||
} catch (err) {
|
||||
process.exit(-1);
|
||||
let providerInfo;
|
||||
if (shouldSetupAuth) {
|
||||
providerInfo = await auth();
|
||||
}
|
||||
|
||||
if (shouldSetupScaffolder) {
|
||||
await integrations(providerInfo);
|
||||
}
|
||||
|
||||
if (!shouldSetupAuth && !shouldSetupScaffolder) {
|
||||
Task.log(
|
||||
chalk.yellow(
|
||||
'If you change your mind, feel free to re-run this command.',
|
||||
),
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
Task.log();
|
||||
Task.log(
|
||||
`You can now start your app with ${chalk.inverse(
|
||||
chalk.italic('yarn dev'),
|
||||
)}`,
|
||||
);
|
||||
Task.log();
|
||||
}
|
||||
|
||||
@@ -19,76 +19,74 @@ import inquirer from 'inquirer';
|
||||
import { Task } from '../../../../lib/tasks';
|
||||
import { updateConfigFile } from '../../config';
|
||||
import { APP_CONFIG_FILE } from '../../files';
|
||||
import { GitHubAnswers } from '../../auth';
|
||||
|
||||
type Answers = {
|
||||
isEnterprise: boolean;
|
||||
host: string;
|
||||
apiBaseUrl?: string;
|
||||
token: string;
|
||||
hasEnterprise: boolean;
|
||||
enterpriseInstanceUrl: string;
|
||||
apiBaseUrl: string;
|
||||
};
|
||||
|
||||
const getConfig = ({ isEnterprise, host, apiBaseUrl, token }: Answers) => ({
|
||||
const getConfig = ({
|
||||
hasEnterprise,
|
||||
apiBaseUrl,
|
||||
host,
|
||||
token,
|
||||
}: {
|
||||
hasEnterprise: boolean;
|
||||
apiBaseUrl: string;
|
||||
host: string;
|
||||
token: string;
|
||||
}) => ({
|
||||
integrations: {
|
||||
github: isEnterprise
|
||||
? [
|
||||
{
|
||||
host,
|
||||
apiBaseUrl,
|
||||
token,
|
||||
},
|
||||
]
|
||||
: [
|
||||
{
|
||||
host,
|
||||
token,
|
||||
},
|
||||
],
|
||||
github: [
|
||||
{
|
||||
host,
|
||||
token,
|
||||
...(hasEnterprise && {
|
||||
apiBaseUrl,
|
||||
}),
|
||||
},
|
||||
],
|
||||
},
|
||||
});
|
||||
|
||||
export const github = async () => {
|
||||
let host = 'github.com';
|
||||
|
||||
export const github = async (providerAnswers?: GitHubAnswers) => {
|
||||
// TODO(tudi2d): Is GitHub Enterprise a valid setup if there is no Authentication?
|
||||
const {
|
||||
isEnterprise,
|
||||
host: _host,
|
||||
apiBaseUrl,
|
||||
} = await inquirer.prompt<{
|
||||
isEnterprise: Answers['isEnterprise'];
|
||||
apiBaseUrl: Answers['apiBaseUrl'];
|
||||
host: Answers['host'];
|
||||
}>([
|
||||
const answers = await inquirer.prompt<Answers>([
|
||||
{
|
||||
type: 'confirm',
|
||||
name: 'isEnterprise',
|
||||
name: 'hasEnterprise',
|
||||
message: 'Are you using GitHub Enterprise?',
|
||||
when: () => typeof providerAnswers === 'undefined',
|
||||
},
|
||||
{
|
||||
type: 'input',
|
||||
name: 'apiBaseUrl',
|
||||
when: ({ isEnterprise: _isEnterprise }) => _isEnterprise,
|
||||
message:
|
||||
'What is your GitHub Enterprise REST API URL (e.g. https://ghe.example.net/api/v3)?',
|
||||
// TODO(tudi2d): Fetch API using OAuth Token if Auth was set up
|
||||
name: 'enterpriseInstanceUrl',
|
||||
message: 'What is your URL for GitHub Enterprise?',
|
||||
when: ({ hasEnterprise }) => hasEnterprise,
|
||||
validate: (input: string) => Boolean(new URL(input)),
|
||||
},
|
||||
{
|
||||
type: 'input',
|
||||
name: 'host',
|
||||
when: ({ isEnterprise: _isEnterprise }) => _isEnterprise,
|
||||
message: 'What is your GitHub Enterprise Host (e.g. ghe.example.net)?',
|
||||
// TODO(tudi2d): validate: Must the host be part of the REST API URL?
|
||||
name: 'apiBaseUrl',
|
||||
message: 'What is your GitHub Enterprise API path?',
|
||||
default: '/api/v3',
|
||||
when: ({ hasEnterprise }) =>
|
||||
hasEnterprise || providerAnswers?.hasEnterprise,
|
||||
// TODO(tudi2d): Fetch API using OAuth Token if Auth was set up
|
||||
},
|
||||
]);
|
||||
|
||||
if (isEnterprise) {
|
||||
host = _host;
|
||||
}
|
||||
const host = new URL(
|
||||
providerAnswers?.enterpriseInstanceUrl ??
|
||||
answers?.enterpriseInstanceUrl ??
|
||||
'http://github.com',
|
||||
);
|
||||
|
||||
Task.log(`
|
||||
To create new repositories in GitHub using Software Templates you first need to create a personal access token: ${chalk.blue(
|
||||
`https://${host}/settings/tokens/new`,
|
||||
`${host.origin}/settings/tokens/new`,
|
||||
)}
|
||||
|
||||
Select the following scopes:
|
||||
@@ -111,9 +109,7 @@ export const github = async () => {
|
||||
)}
|
||||
`);
|
||||
|
||||
const { token } = await inquirer.prompt<{
|
||||
token: Answers['token'];
|
||||
}>([
|
||||
const { token } = await inquirer.prompt<{ token: string }>([
|
||||
{
|
||||
type: 'input',
|
||||
name: 'token',
|
||||
@@ -124,13 +120,13 @@ export const github = async () => {
|
||||
]);
|
||||
|
||||
const config = getConfig({
|
||||
hasEnterprise: providerAnswers?.hasEnterprise ?? answers.hasEnterprise,
|
||||
apiBaseUrl: host.origin + answers.apiBaseUrl,
|
||||
host: host.hostname,
|
||||
token,
|
||||
isEnterprise,
|
||||
host,
|
||||
apiBaseUrl,
|
||||
});
|
||||
|
||||
Task.log('Setting up GitHub Integration for you...');
|
||||
Task.log('Setting up Software Templates using GitHub integration for you...');
|
||||
|
||||
await Task.forItem(
|
||||
'Updating',
|
||||
|
||||
@@ -15,6 +15,8 @@
|
||||
*/
|
||||
|
||||
import inquirer from 'inquirer';
|
||||
import { Task } from '../../../lib/tasks';
|
||||
import { GitHubAnswers, GitLabAnswers } from '../auth';
|
||||
import { github } from './github';
|
||||
|
||||
enum Integration {
|
||||
@@ -23,27 +25,51 @@ enum Integration {
|
||||
|
||||
const Integrations: Integration[] = [Integration.GITHUB];
|
||||
|
||||
export async function integrations(): Promise<void> {
|
||||
await inquirer
|
||||
.prompt<{
|
||||
integration?: Integration;
|
||||
}>([
|
||||
{
|
||||
// TODO(tudi2d): Let's start with one, but it should be multiple choice in the future
|
||||
type: 'list',
|
||||
name: 'integration',
|
||||
message: 'Please select an integration:',
|
||||
choices: Integrations,
|
||||
},
|
||||
])
|
||||
.then(async ({ integration }) => {
|
||||
if (integration) {
|
||||
switch (integration) {
|
||||
case Integration.GITHUB:
|
||||
await github();
|
||||
break;
|
||||
default:
|
||||
}
|
||||
}
|
||||
});
|
||||
export async function integrations(providerInfo?: {
|
||||
provider: string;
|
||||
answers: GitHubAnswers | GitLabAnswers;
|
||||
}): Promise<void> {
|
||||
const answers = await inquirer.prompt<{
|
||||
integration?: Integration;
|
||||
shouldUsePreviousProvider: boolean;
|
||||
}>([
|
||||
{
|
||||
type: 'confirm',
|
||||
name: 'shouldUsePreviousProvider',
|
||||
message: `Do you want to keep using ${providerInfo?.provider} as your provider when setting up Software Templates?`,
|
||||
when: () =>
|
||||
providerInfo?.provider &&
|
||||
Object.values(Integrations).includes(
|
||||
providerInfo!.provider as Integration,
|
||||
),
|
||||
},
|
||||
{
|
||||
// TODO(tudi2d): Let's start with one, but it should be multiple choice in the future
|
||||
type: 'list',
|
||||
name: 'integration',
|
||||
message: 'Please select an integration provider:',
|
||||
choices: Integrations,
|
||||
when: ({ shouldUsePreviousProvider }) => !shouldUsePreviousProvider,
|
||||
},
|
||||
]);
|
||||
|
||||
if (answers.shouldUsePreviousProvider) {
|
||||
answers.integration = providerInfo!.provider as Integration;
|
||||
}
|
||||
|
||||
switch (answers.integration) {
|
||||
case Integration.GITHUB: {
|
||||
const providerAnswers =
|
||||
providerInfo?.provider === 'GitHub'
|
||||
? (providerInfo!.answers as GitHubAnswers)
|
||||
: undefined;
|
||||
await github(providerAnswers);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
}
|
||||
|
||||
Task.log();
|
||||
Task.log(`Done setting up ${answers.integration} Integration!`);
|
||||
Task.log();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user