feat(dev-infra): standard CLI commands using yargs (#36326)

Creates a standard model for CLI commands provided by ng-dev.
Allows for us to have any of the tools/scripts extend to be
included in the ng-dev command, or be standalone using the same
yargs parser.

PR Close #36326
This commit is contained in:
Joey Perrott 2020-03-26 10:45:09 -07:00 committed by Kara Erickson
parent 326240eb91
commit 43006bcc45
9 changed files with 114 additions and 40 deletions

View File

@ -10,8 +10,11 @@ ts_library(
deps = [
"//dev-infra/commit-message",
"//dev-infra/pullapprove",
"//dev-infra/ts-circular-dependencies",
"//dev-infra/utils:config",
"@npm//@types/node",
"@npm//@types/yargs",
"@npm//yargs",
],
)

View File

@ -6,26 +6,17 @@
* 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 {readFileSync} from 'fs';
import {join} from 'path';
import {verify} from './pullapprove/verify';
import {validateCommitMessage} from './commit-message/validate';
import {getRepoBaseDir} from './utils/config';
import * as yargs from 'yargs';
import {tsCircularDependenciesBuilder} from './ts-circular-dependencies/index';
import {buildPullapproveParser} from './pullapprove/cli';
import {buildCommitMessageParser} from './commit-message/cli';
const args = process.argv.slice(2);
// TODO(josephperrott): Set up proper cli flag/command handling
switch (args[0]) {
case 'pullapprove:verify':
verify();
break;
case 'commit-message:pre-commit-validate':
const commitMessage = readFileSync(join(getRepoBaseDir(), '.git/COMMIT_EDITMSG'), 'utf8');
if (validateCommitMessage(commitMessage)) {
console.info('√ Valid commit message');
}
break;
default:
console.info('No commands were matched');
}
yargs.scriptName('ng-dev')
.demandCommand()
.recommendCommands()
.command('ts-circular-deps <command>', '', tsCircularDependenciesBuilder)
.command('pullapprove <command>', '', buildPullapproveParser)
.command('commit-message <command>', '', buildCommitMessageParser)
.wrap(120)
.strict()
.parse();

View File

@ -4,15 +4,19 @@ load("@npm_bazel_typescript//:index.bzl", "ts_library")
ts_library(
name = "commit-message",
srcs = [
"cli.ts",
"config.ts",
"validate.ts",
"validate-file.ts",
],
module_name = "@angular/dev-infra-private/commit-message",
visibility = ["//dev-infra:__subpackages__"],
deps = [
"//dev-infra/utils:config",
"@npm//@types/node",
"@npm//@types/yargs",
"@npm//tslib",
"@npm//yargs",
],
)

View File

@ -0,0 +1,20 @@
/**
* @license
* Copyright Google Inc. 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 * as yargs from 'yargs';
import {validateFile} from './validate-file';
/** Build the parser for the commit-message commands. */
export function buildCommitMessageParser(localYargs: yargs.Argv) {
return localYargs.help().strict().command(
'pre-commit-validate', 'Validate the most recent commit message', {},
() => { validateFile('.git/COMMIT_EDITMSG'); });
}
if (require.main == module) {
buildCommitMessageParser(yargs).parse();
}

View File

@ -0,0 +1,21 @@
/**
* @license
* Copyright Google Inc. 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 {readFileSync} from 'fs';
import {join} from 'path';
import {getRepoBaseDir} from '../utils/config';
import {validateCommitMessage} from './validate';
/** Validate commit message at the provided file path. */
export function validateFile(filePath: string) {
const commitMessage = readFileSync(join(getRepoBaseDir(), filePath), 'utf8');
if (validateCommitMessage(commitMessage)) {
console.info('√ Valid commit message');
}
}

View File

@ -3,6 +3,7 @@ load("@npm_bazel_typescript//:index.bzl", "ts_library")
ts_library(
name = "pullapprove",
srcs = [
"cli.ts",
"group.ts",
"logging.ts",
"parse-yaml.ts",
@ -16,9 +17,11 @@ ts_library(
"@npm//@types/node",
"@npm//@types/shelljs",
"@npm//@types/yaml",
"@npm//@types/yargs",
"@npm//minimatch",
"@npm//shelljs",
"@npm//tslib",
"@npm//yaml",
"@npm//yargs",
],
)

View File

@ -0,0 +1,19 @@
/**
* @license
* Copyright Google Inc. 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 * as yargs from 'yargs';
import {verify} from './verify';
/** Build the parser for the pullapprove commands. */
export function buildPullapproveParser(localYargs: yargs.Argv) {
return localYargs.help().strict().demandCommand().command(
'verify', 'Verify the pullapprove config', {}, () => verify());
}
if (require.main === module) {
buildPullapproveParser(yargs).parse();
}

View File

@ -19,22 +19,30 @@ import {compareGoldens, convertReferenceChainToGolden, Golden} from './golden';
import {convertPathToForwardSlash} from './file_system';
import {loadTestConfig, CircularDependenciesTestConfig} from './config';
if (require.main === module) {
const {_: command, config: configArg, warnings} =
yargs.help()
.strict()
.command('check', 'Checks if the circular dependencies have changed.')
.command('approve', 'Approves the current circular dependencies.')
.demandCommand()
.option(
'config',
{type: 'string', demandOption: true, description: 'Path to the configuration file.'})
.option('warnings', {type: 'boolean', description: 'Prints all warnings.'})
.argv;
const configPath = isAbsolute(configArg) ? configArg : resolve(configArg);
const config = loadTestConfig(configPath);
const isApprove = command.includes('approve');
process.exit(main(isApprove, config, warnings));
export function tsCircularDependenciesBuilder(localYargs: yargs.Argv) {
return localYargs.help()
.strict()
.demandCommand()
.option(
'config',
{type: 'string', demandOption: true, description: 'Path to the configuration file.'})
.option('warnings', {type: 'boolean', description: 'Prints all warnings.'})
.command(
'check', 'Checks if the circular dependencies have changed.', {},
(argv: yargs.Arguments) => {
const {config: configArg, warnings} = argv;
const configPath = isAbsolute(configArg) ? configArg : resolve(configArg);
const config = loadTestConfig(configPath);
process.exit(main(false, config, warnings));
})
.command(
'approve', 'Approves the current circular dependencies.', {}, (argv: yargs.Arguments) => {
const {config: configArg, warnings} = argv;
const configPath = isAbsolute(configArg) ? configArg : resolve(configArg);
const config = loadTestConfig(configPath);
process.exit(main(true, config, warnings));
});
}
/**
@ -126,3 +134,7 @@ function getRelativePath(baseDir: string, path: string) {
function convertReferenceChainToString(chain: ReferenceChain<string>) {
return chain.join(' → ');
}
if (require.main === module) {
tsCircularDependenciesBuilder(yargs).parse();
}

View File

@ -35,9 +35,10 @@
"tslint": "tsc -p tools/tsconfig.json && tslint -c tslint.json \"+(packages|modules|scripts|tools)/**/*.+(js|ts)\"",
"public-api:check": "node goldens/public-api/manage.js test",
"public-api:update": "node goldens/public-api/manage.js accept",
"ts-circular-deps": "ts-node dev-infra/ts-circular-dependencies/index.ts --config ./packages/circular-deps-test.conf.js",
"ts-circular-deps": "ts-node --transpile-only -- dev-infra/ts-circular-dependencies/index.ts --config ./packages/circular-deps-test.conf.js",
"ts-circular-deps:check": "yarn -s ts-circular-deps check",
"ts-circular-deps:approve": "yarn -s ts-circular-deps approve"
"ts-circular-deps:approve": "yarn -s ts-circular-deps approve",
"ng-dev": "ts-node --transpile-only -- dev-infra/cli.ts"
},
"// 1": "dependencies are used locally and by bazel",
"dependencies": {