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:
Marcus Eide
2023-03-08 16:00:42 +01:00
committed by Philipp Hugenroth
parent 8e254c06bc
commit b590c95ed8
6 changed files with 167 additions and 136 deletions
@@ -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;
};
+19 -13
View File
@@ -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,
};
}
+43 -44
View File
@@ -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();
}