From 55f802caa65afe8505f0d83b70de525f9aecb045 Mon Sep 17 00:00:00 2001 From: Philipp Hugenroth Date: Mon, 27 Feb 2023 19:00:45 +0100 Subject: [PATCH] Add GitHub integration to Onboard CLI Signed-off-by: Philipp Hugenroth --- packages/cli/src/commands/onboard/command.ts | 64 +++++++++++----- .../onboard/integrations/github/index.ts | 73 +++++++++++++++++++ .../commands/onboard/integrations/index.ts | 49 +++++++++++++ 3 files changed, 168 insertions(+), 18 deletions(-) create mode 100644 packages/cli/src/commands/onboard/integrations/github/index.ts create mode 100644 packages/cli/src/commands/onboard/integrations/index.ts diff --git a/packages/cli/src/commands/onboard/command.ts b/packages/cli/src/commands/onboard/command.ts index 5bad1211ab..1cfaabed12 100644 --- a/packages/cli/src/commands/onboard/command.ts +++ b/packages/cli/src/commands/onboard/command.ts @@ -17,26 +17,54 @@ import chalk from 'chalk'; import inquirer from 'inquirer'; import { auth } from './auth'; +import { integrations } from './integrations'; export async function command(): Promise { - const answers = await inquirer.prompt<{ - shouldSetupAuth: boolean; - }>([ - { - type: 'confirm', - name: 'shouldSetupAuth', - message: 'Do you want to set up Authentication for this project?', - }, - ]); + 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, + }, + ]); - if (!answers.shouldSetupAuth) { - console.log( - chalk.yellow( - 'If you change your mind, feel free to re-run this command.', - ), - ); - process.exit(1); + if (!answers.shouldSetupAuth) { + console.log( + chalk.yellow( + 'If you change your mind, feel free to re-run this command.', + ), + ); + } else { + await auth(); + } + + // 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); } - - await auth(); } diff --git a/packages/cli/src/commands/onboard/integrations/github/index.ts b/packages/cli/src/commands/onboard/integrations/github/index.ts new file mode 100644 index 0000000000..73416699e4 --- /dev/null +++ b/packages/cli/src/commands/onboard/integrations/github/index.ts @@ -0,0 +1,73 @@ +/* + * Copyright 2023 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import chalk from 'chalk'; +import inquirer from 'inquirer'; +import { Task } from '../../../../lib/tasks'; + +export const github = async () => { + const host = 'https://github.com'; + const answers = await inquirer.prompt<{ hasEnterprise: boolean }>([ + { + type: 'confirm', + name: 'hasEnterprise', + message: 'Are you using GitHub Enterprise?', + }, + ]); + + if (answers.hasEnterprise) { + await inquirer.prompt<{ hasEnterprise: boolean }>([ + { + type: 'confirm', + name: 'hasEnterprise', + message: 'Are you using GitHub Enterprise?', + }, + { + type: 'input', + name: 'enterpriseInstanceUrl', + message: 'What is your GitHub Enterprise URL (e.g. ghe.example.net)?', + when: ({ hasEnterprise }) => hasEnterprise, + validate: (input: string) => Boolean(new URL(input)), + }, + ]); + } + + Task.log(` + To create new repositories in GitHub using Software Templates you first need to create a personal access token: ${chalk.blue( + `${host}/settings/tokens/new', + )} + + Select the following scopes: + + Reading software components:${chalk.cyan(` + - "repo"`)} + + Reading organization data:${chalk.cyan(` + - "read:org" + - "read:user" + - "user:email"`)} + + Publishing software templates:${chalk.cyan(` + - "repo" + - "workflow" (if templates include GitHub workflows) + `)} + + You can find the full documentation page here: ${chalk.blue( + 'https://backstage.io/docs/integrations/github/locations', + )} + `, + )}`); +}; diff --git a/packages/cli/src/commands/onboard/integrations/index.ts b/packages/cli/src/commands/onboard/integrations/index.ts new file mode 100644 index 0000000000..2b55ab2bba --- /dev/null +++ b/packages/cli/src/commands/onboard/integrations/index.ts @@ -0,0 +1,49 @@ +/* + * Copyright 2023 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import inquirer from 'inquirer'; +import { github } from './github'; + +enum Integration { + GITHUB = 'GitHub', +} + +const Integrations: Integration[] = [Integration.GITHUB]; + +export async function integrations(): Promise { + await inquirer + .prompt<{ + integration?: Integration; + }>([ + { + // TODO(tudi2d): Should be multiple choice + 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: + } + } + }); +}