From 4afad03312772d3f29e87b46701ee8adbdba6c3a Mon Sep 17 00:00:00 2001 From: Joey Perrott Date: Tue, 25 May 2021 09:44:52 -0700 Subject: [PATCH] feat(dev-infra): add `ng-dev build-and-link` command (#42319) Add a command to build the release output without stamping for release and link via `yarn link` the generated builds to a project provided. PR Close #42319 --- dev-infra/BUILD.bazel | 1 + dev-infra/cli.ts | 2 + dev-infra/misc/BUILD.bazel | 16 +++++++ dev-infra/misc/build-and-link/cli.ts | 69 +++++++++++++++++++++++++++ dev-infra/misc/cli.ts | 15 ++++++ dev-infra/ng-dev.js | 70 ++++++++++++++++++++++++++-- 6 files changed, 169 insertions(+), 4 deletions(-) create mode 100644 dev-infra/misc/BUILD.bazel create mode 100644 dev-infra/misc/build-and-link/cli.ts create mode 100644 dev-infra/misc/cli.ts diff --git a/dev-infra/BUILD.bazel b/dev-infra/BUILD.bazel index b3ca536634..5cd5d2c63f 100644 --- a/dev-infra/BUILD.bazel +++ b/dev-infra/BUILD.bazel @@ -12,6 +12,7 @@ ts_library( "//dev-infra/caretaker", "//dev-infra/commit-message", "//dev-infra/format", + "//dev-infra/misc", "//dev-infra/ngbot", "//dev-infra/pr", "//dev-infra/pullapprove", diff --git a/dev-infra/cli.ts b/dev-infra/cli.ts index 979bcde5b0..6bfd94274e 100644 --- a/dev-infra/cli.ts +++ b/dev-infra/cli.ts @@ -17,6 +17,7 @@ import {buildPullapproveParser} from './pullapprove/cli'; import {buildReleaseParser} from './release/cli'; import {tsCircularDependenciesBuilder} from './ts-circular-dependencies/index'; import {captureLogOutputForCommand} from './utils/console'; +import {buildMiscParser} from './misc/cli'; yargs.scriptName('ng-dev') .middleware(captureLogOutputForCommand) @@ -29,6 +30,7 @@ yargs.scriptName('ng-dev') .command('release ', '', buildReleaseParser) .command('ts-circular-deps ', '', tsCircularDependenciesBuilder) .command('caretaker ', '', buildCaretakerParser) + .command('misc ', '', buildMiscParser) .command('ngbot ', false, buildNgbotParser) .wrap(120) .strict() diff --git a/dev-infra/misc/BUILD.bazel b/dev-infra/misc/BUILD.bazel new file mode 100644 index 0000000000..5e538b23f2 --- /dev/null +++ b/dev-infra/misc/BUILD.bazel @@ -0,0 +1,16 @@ +load("@npm//@bazel/typescript:index.bzl", "ts_library") + +ts_library( + name = "misc", + srcs = glob(["**/*.ts"]), + module_name = "@angular/dev-infra-private/misc/", + visibility = ["//dev-infra:__subpackages__"], + deps = [ + "//dev-infra/release/build", + "//dev-infra/release/config", + "//dev-infra/utils", + "@npm//@types/node", + "@npm//@types/yargs", + "@npm//chalk", + ], +) diff --git a/dev-infra/misc/build-and-link/cli.ts b/dev-infra/misc/build-and-link/cli.ts new file mode 100644 index 0000000000..d32fd4a021 --- /dev/null +++ b/dev-infra/misc/build-and-link/cli.ts @@ -0,0 +1,69 @@ +/** + * @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 {green} from 'chalk'; +import {lstatSync, stat, Stats} from 'fs'; +import {isAbsolute, join, resolve} from 'path'; +import {Arguments, Argv, CommandModule} from 'yargs'; + +import {buildReleaseOutput} from '../../release/build/index'; +import {error, info, red} from '../../utils/console'; +import {exec} from '../../utils/shelljs'; + + +/** Command line options. */ +export interface BuildAndLinkOptions { + projectRoot: string; +} + +/** Yargs command builder for the command. */ +function builder(argv: Argv): Argv { + return argv.positional('projectRoot', { + type: 'string', + normalize: true, + coerce: (path: string) => resolve(path), + demandOption: true, + }); +} + +/** Yargs command handler for the command. */ +async function handler({projectRoot}: Arguments) { + try { + if (!lstatSync(projectRoot).isDirectory()) { + error(red(` ✘ The 'projectRoot' must be a directory: ${projectRoot}`)); + process.exit(1); + } + } catch { + error(red(` ✘ Could not find the 'projectRoot' provided: ${projectRoot}`)); + process.exit(1); + } + + const releaseOutputs = await buildReleaseOutput(false); + + if (releaseOutputs === null) { + error(red(` ✘ Could not build release output. Please check output above.`)); + process.exit(1); + } + info(green(` ✓ Built release output.`)); + + for (const {outputPath, name} of releaseOutputs) { + exec(`yarn link --cwd ${outputPath}`); + exec(`yarn link --cwd ${projectRoot} ${name}`); + } + + info(green(` ✓ Linked release packages in provided project.`)); +} + +/** CLI command module. */ +export const BuildAndLinkCommandModule: CommandModule<{}, BuildAndLinkOptions> = { + builder, + handler, + command: 'build-and-link ', + describe: + 'Builds the release output, registers the outputs as linked, and links via yarn to the provided project', +}; diff --git a/dev-infra/misc/cli.ts b/dev-infra/misc/cli.ts new file mode 100644 index 0000000000..64b2b785a4 --- /dev/null +++ b/dev-infra/misc/cli.ts @@ -0,0 +1,15 @@ +/** + * @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 * as yargs from 'yargs'; + +import {BuildAndLinkCommandModule} from './build-and-link/cli'; + +/** Build the parser for the misc commands. */ +export function buildMiscParser(localYargs: yargs.Argv) { + return localYargs.help().strict().command(BuildAndLinkCommandModule); +} diff --git a/dev-infra/ng-dev.js b/dev-infra/ng-dev.js index 30cf3e2fe4..ecab957b60 100755 --- a/dev-infra/ng-dev.js +++ b/dev-infra/ng-dev.js @@ -5152,10 +5152,10 @@ function getReleaseConfig(config = getConfig()) { * pollute the stdout in such cases, we launch a child process for building the release packages * and redirect all stdout output to the stderr channel (which can be read in the terminal). */ -function buildReleaseOutput() { +function buildReleaseOutput(stampForRelease = false) { return tslib.__awaiter(this, void 0, void 0, function* () { return new Promise(resolve => { - const buildProcess = child_process.fork(require.resolve('./build-worker'), [], { + const buildProcess = child_process.fork(require.resolve('./build-worker'), [`${stampForRelease}`], { // The stdio option is set to redirect any "stdout" output directly to the "stderr" file // descriptor. An additional "ipc" file descriptor is created to support communication with // the build process. https://nodejs.org/api/child_process.html#child_process_options_stdio. @@ -5180,17 +5180,23 @@ function buildReleaseOutput() { */ /** Yargs command builder for configuring the `ng-dev release build` command. */ function builder$7(argv) { - return argv.option('json', { + return argv + .option('json', { type: 'boolean', description: 'Whether the built packages should be printed to stdout as JSON.', default: false, + }) + .option('stampForRelease', { + type: 'boolean', + description: 'Whether the built packages should be stamped for release.', + default: false, }); } /** Yargs command handler for building a release. */ function handler$7(args) { return tslib.__awaiter(this, void 0, void 0, function* () { const { npmPackages } = getReleaseConfig(); - let builtPackages = yield buildReleaseOutput(); + let builtPackages = yield buildReleaseOutput(args.stampForRelease); // If package building failed, print an error and exit with an error code. if (builtPackages === null) { error(red(` ✘ Could not build release output. Please check output above.`)); @@ -7888,6 +7894,61 @@ function convertReferenceChainToString(chain) { return chain.join(' → '); } +/** + * @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 + */ +/** Yargs command builder for the command. */ +function builder$c(argv) { + return argv.positional('projectRoot', { + type: 'string', + normalize: true, + coerce: (path$1) => path.resolve(path$1), + demandOption: true, + }); +} +/** Yargs command handler for the command. */ +function handler$c({ projectRoot }) { + return tslib.__awaiter(this, void 0, void 0, function* () { + try { + if (!fs.lstatSync(projectRoot).isDirectory()) { + error(red(` ✘ The 'projectRoot' must be a directory: ${projectRoot}`)); + process.exit(1); + } + } + catch (_a) { + error(red(` ✘ Could not find the 'projectRoot' provided: ${projectRoot}`)); + process.exit(1); + } + const releaseOutputs = yield buildReleaseOutput(false); + if (releaseOutputs === null) { + error(red(` ✘ Could not build release output. Please check output above.`)); + process.exit(1); + } + info(chalk.green(` ✓ Built release output.`)); + for (const { outputPath, name } of releaseOutputs) { + exec(`yarn link --cwd ${outputPath}`); + exec(`yarn link --cwd ${projectRoot} ${name}`); + } + info(chalk.green(` ✓ Linked release packages in provided project.`)); + }); +} +/** CLI command module. */ +const BuildAndLinkCommandModule = { + builder: builder$c, + handler: handler$c, + command: 'build-and-link ', + describe: 'Builds the release output, registers the outputs as linked, and links via yarn to the provided project', +}; + +/** Build the parser for the misc commands. */ +function buildMiscParser(localYargs) { + return localYargs.help().strict().command(BuildAndLinkCommandModule); +} + yargs.scriptName('ng-dev') .middleware(captureLogOutputForCommand) .demandCommand() @@ -7899,6 +7960,7 @@ yargs.scriptName('ng-dev') .command('release ', '', buildReleaseParser) .command('ts-circular-deps ', '', tsCircularDependenciesBuilder) .command('caretaker ', '', buildCaretakerParser) + .command('misc ', '', buildMiscParser) .command('ngbot ', false, buildNgbotParser) .wrap(120) .strict()