From 4f28192d62b59a4a45f7f27890e9fb356e2cf885 Mon Sep 17 00:00:00 2001 From: Joey Perrott Date: Fri, 28 Aug 2020 11:45:01 -0700 Subject: [PATCH] refactor(dev-infra): use a mixin to require a `github-token` for an ng-dev command (#38630) Creates a mixin for requiring a github token to be provided to a command. This mixin allows for a centralized management of the requirement and handling of the github-token. PR Close #38630 --- dev-infra/pr/checkout/cli.ts | 22 ++++----------------- dev-infra/pr/merge/cli.ts | 28 ++++++++------------------- dev-infra/pr/merge/index.ts | 6 ++---- dev-infra/pr/rebase/cli.ts | 28 ++++++--------------------- dev-infra/utils/yargs.ts | 37 ++++++++++++++++++++++++++++++++++++ 5 files changed, 57 insertions(+), 64 deletions(-) create mode 100644 dev-infra/utils/yargs.ts diff --git a/dev-infra/pr/checkout/cli.ts b/dev-infra/pr/checkout/cli.ts index de9d8b59f8..0aabc8f5c6 100644 --- a/dev-infra/pr/checkout/cli.ts +++ b/dev-infra/pr/checkout/cli.ts @@ -8,35 +8,21 @@ import {Arguments, Argv, CommandModule} from 'yargs'; -import {error} from '../../utils/console'; +import {addGithubTokenFlag} from '../../utils/yargs'; import {checkOutPullRequestLocally} from '../common/checkout-pr'; export interface CheckoutOptions { prNumber: number; - 'github-token'?: string; + githubToken: string; } -/** URL to the Github page where personal access tokens can be generated. */ -export const GITHUB_TOKEN_GENERATE_URL = `https://github.com/settings/tokens`; - /** Builds the checkout pull request command. */ function builder(yargs: Argv) { - return yargs.positional('prNumber', {type: 'number', demandOption: true}).option('github-token', { - type: 'string', - description: 'Github token. If not set, token is retrieved from the environment variables.' - }); + return addGithubTokenFlag(yargs).positional('prNumber', {type: 'number', demandOption: true}); } /** Handles the checkout pull request command. */ -async function handler({prNumber, 'github-token': token}: Arguments) { - const githubToken = token || process.env.GITHUB_TOKEN || process.env.TOKEN; - if (!githubToken) { - error('No Github token set. Please set the `GITHUB_TOKEN` environment variable.'); - error('Alternatively, pass the `--github-token` command line flag.'); - error(`You can generate a token here: ${GITHUB_TOKEN_GENERATE_URL}`); - process.exitCode = 1; - return; - } +async function handler({prNumber, githubToken}: Arguments) { const prCheckoutOptions = {allowIfMaintainerCannotModify: true, branchName: `pr-${prNumber}`}; await checkOutPullRequestLocally(prNumber, githubToken, prCheckoutOptions); } diff --git a/dev-infra/pr/merge/cli.ts b/dev-infra/pr/merge/cli.ts index 785b9fb2da..d5b6ac4f46 100644 --- a/dev-infra/pr/merge/cli.ts +++ b/dev-infra/pr/merge/cli.ts @@ -8,36 +8,24 @@ import {Arguments, Argv} from 'yargs'; -import {error, red, yellow} from '../../utils/console'; +import {addGithubTokenFlag} from '../../utils/yargs'; -import {GITHUB_TOKEN_GENERATE_URL, mergePullRequest} from './index'; +import {mergePullRequest} from './index'; /** The options available to the merge command via CLI. */ export interface MergeCommandOptions { - 'github-token'?: string; + githubToken: string; 'pr-number': number; } /** Builds the options for the merge command. */ export function buildMergeCommand(yargs: Argv): Argv { - return yargs.help() - .strict() - .positional('pr-number', {demandOption: true, type: 'number'}) - .option('github-token', { - type: 'string', - description: 'Github token. If not set, token is retrieved from the environment variables.' - }); + return addGithubTokenFlag(yargs).help().strict().positional( + 'pr-number', {demandOption: true, type: 'number'}); } /** Handles the merge command. i.e. performs the merge of a specified pull request. */ -export async function handleMergeCommand(args: Arguments) { - const githubToken = args['github-token'] || process.env.GITHUB_TOKEN || process.env.TOKEN; - if (!githubToken) { - error(red('No Github token set. Please set the `GITHUB_TOKEN` environment variable.')); - error(red('Alternatively, pass the `--github-token` command line flag.')); - error(yellow(`You can generate a token here: ${GITHUB_TOKEN_GENERATE_URL}`)); - process.exit(1); - } - - await mergePullRequest(args['pr-number'], githubToken); +export async function handleMergeCommand( + {'pr-number': pr, githubToken}: Arguments) { + await mergePullRequest(pr, githubToken); } diff --git a/dev-infra/pr/merge/index.ts b/dev-infra/pr/merge/index.ts index 816aa679d2..4a6f5a5fd5 100644 --- a/dev-infra/pr/merge/index.ts +++ b/dev-infra/pr/merge/index.ts @@ -11,13 +11,11 @@ import {getConfig, getRepoBaseDir} from '../../utils/config'; import {error, green, info, promptConfirm, red, yellow} from '../../utils/console'; import {GitClient} from '../../utils/git'; import {GithubApiRequestError} from '../../utils/git/github'; +import {GITHUB_TOKEN_GENERATE_URL} from '../../utils/yargs'; -import {loadAndValidateConfig, MergeConfig, MergeConfigWithRemote} from './config'; +import {loadAndValidateConfig, MergeConfigWithRemote} from './config'; import {MergeResult, MergeStatus, PullRequestMergeTask} from './task'; -/** URL to the Github page where personal access tokens can be generated. */ -export const GITHUB_TOKEN_GENERATE_URL = `https://github.com/settings/tokens`; - /** * Merges a given pull request based on labels configured in the given merge configuration. diff --git a/dev-infra/pr/rebase/cli.ts b/dev-infra/pr/rebase/cli.ts index d06ace794a..98c44bf7f5 100644 --- a/dev-infra/pr/rebase/cli.ts +++ b/dev-infra/pr/rebase/cli.ts @@ -8,39 +8,23 @@ import {Arguments, Argv} from 'yargs'; -import {error} from '../../utils/console'; +import {addGithubTokenFlag} from '../../utils/yargs'; import {rebasePr} from './index'; -/** URL to the Github page where personal access tokens can be generated. */ -export const GITHUB_TOKEN_GENERATE_URL = `https://github.com/settings/tokens`; - /** The options available to the rebase command via CLI. */ export interface RebaseCommandOptions { - 'github-token'?: string; + githubToken: string; prNumber: number; } /** Builds the rebase pull request command. */ export function buildRebaseCommand(yargs: Argv): Argv { - return yargs - .option('github-token', { - type: 'string', - description: 'Github token. If not set, token is retrieved from the environment variables.' - }) - .positional('prNumber', {type: 'number', demandOption: true}); + return addGithubTokenFlag(yargs).positional('prNumber', {type: 'number', demandOption: true}); } - /** Handles the rebase pull request command. */ -export async function handleRebaseCommand(args: Arguments) { - const githubToken = args['github-token'] || process.env.GITHUB_TOKEN || process.env.TOKEN; - if (!githubToken) { - error('No Github token set. Please set the `GITHUB_TOKEN` environment variable.'); - error('Alternatively, pass the `--github-token` command line flag.'); - error(`You can generate a token here: ${GITHUB_TOKEN_GENERATE_URL}`); - process.exit(1); - } - - await rebasePr(args.prNumber, githubToken); +export async function handleRebaseCommand( + {prNumber, githubToken}: Arguments) { + await rebasePr(prNumber, githubToken); } diff --git a/dev-infra/utils/yargs.ts b/dev-infra/utils/yargs.ts new file mode 100644 index 0000000000..bc42985aea --- /dev/null +++ b/dev-infra/utils/yargs.ts @@ -0,0 +1,37 @@ +/** + * @license + * Copyright Google LLC All Rights Reserved. + * + * Use of this source code is governed by an MIT-style license that can be + * found in the LICENSE file at https://angular.io/license + */ + +import {Argv} from 'yargs'; +import {error, red, yellow} from './console'; + +export type ArgvWithGithubToken = Argv<{githubToken: string}>; + +export function addGithubTokenFlag(yargs: Argv): ArgvWithGithubToken { + return yargs + // 'github-token' is casted to 'githubToken' to properly set up typings to reflect the key in + // the Argv object being camelCase rather than kebob case due to the `camel-case-expansion` + // config: https://github.com/yargs/yargs-parser#camel-case-expansion + .option('github-token' as 'githubToken', { + type: 'string', + description: 'Github token. If not set, token is retrieved from the environment variables.', + coerce: (token: string) => { + const githubToken = token || process.env.GITHUB_TOKEN || process.env.TOKEN; + if (!githubToken) { + error(red('No Github token set. Please set the `GITHUB_TOKEN` environment variable.')); + error(red('Alternatively, pass the `--github-token` command line flag.')); + error(yellow(`You can generate a token here: ${GITHUB_TOKEN_GENERATE_URL}`)); + process.exit(1); + } + return githubToken; + }, + }) + .default('github-token' as 'githubToken', '', ''); +} + +/** URL to the Github page where personal access tokens can be generated. */ +export const GITHUB_TOKEN_GENERATE_URL = 'https://github.com/settings/tokens/new';