UNPKG

@angular-devkit/architect-cli

Version:
222 lines (217 loc) 9.04 kB
#!/usr/bin/env node "use strict"; /** * @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.dev/license */ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; var desc = Object.getOwnPropertyDescriptor(m, k); if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { desc = { enumerable: true, get: function() { return m[k]; } }; } Object.defineProperty(o, k2, desc); }) : (function(o, m, k, k2) { if (k2 === undefined) k2 = k; o[k2] = m[k]; })); var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { Object.defineProperty(o, "default", { enumerable: true, value: v }); }) : function(o, v) { o["default"] = v; }); var __importStar = (this && this.__importStar) || (function () { var ownKeys = function(o) { ownKeys = Object.getOwnPropertyNames || function (o) { var ar = []; for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k; return ar; }; return ownKeys(o); }; return function (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]); __setModuleDefault(result, mod); return result; }; })(); Object.defineProperty(exports, "__esModule", { value: true }); const architect_1 = require("@angular-devkit/architect"); const node_1 = require("@angular-devkit/architect/node"); const core_1 = require("@angular-devkit/core"); const node_2 = require("@angular-devkit/core/node"); const ansiColors = __importStar(require("ansi-colors")); const node_fs_1 = require("node:fs"); const path = __importStar(require("node:path")); const yargs_parser_1 = __importStar(require("yargs-parser")); const progress_1 = require("../src/progress"); function findUp(names, from) { if (!Array.isArray(names)) { names = [names]; } const root = path.parse(from).root; let currentDir = from; while (currentDir && currentDir !== root) { for (const name of names) { const p = path.join(currentDir, name); if ((0, node_fs_1.existsSync)(p)) { return p; } } currentDir = path.dirname(currentDir); } return null; } /** * Show usage of the CLI tool, and exit the process. */ function usage(logger, exitCode = 0) { logger.info(core_1.tags.stripIndent ` architect [project][:target][:configuration] [options, ...] Run a project target. If project/target/configuration are not specified, the workspace defaults will be used. Options: --help Show available options for project target. Shows this message instead when ran without the run argument. Any additional option is passed the target, overriding existing options. `); return process.exit(exitCode); } function _targetStringFromTarget({ project, target, configuration }) { return `${project}:${target}${configuration !== undefined ? ':' + configuration : ''}`; } // Create a separate instance to prevent unintended global changes to the color configuration const colors = ansiColors.create(); async function _executeTarget(parentLogger, workspace, root, argv, registry) { const architectHost = new node_1.WorkspaceNodeModulesArchitectHost(workspace, root); const architect = new architect_1.Architect(architectHost, registry); // Split a target into its parts. const { _: [targetStr = ''], help, ...options } = argv; const [project, target, configuration] = targetStr.toString().split(':'); const targetSpec = { project, target, configuration }; const logger = new core_1.logging.Logger('jobs'); const logs = []; logger.subscribe((entry) => logs.push({ ...entry, message: `${entry.name}: ` + entry.message })); // Camelize options as yargs will return the object in kebab-case when camel casing is disabled. const camelCasedOptions = {}; for (const [key, value] of Object.entries(options)) { if (/[A-Z]/.test(key)) { throw new Error(`Unknown argument ${key}. Did you mean ${(0, yargs_parser_1.decamelize)(key)}?`); } camelCasedOptions[(0, yargs_parser_1.camelCase)(key)] = value; } const run = await architect.scheduleTarget(targetSpec, camelCasedOptions, { logger }); const bars = new progress_1.MultiProgressBar(':name :bar (:current/:total) :status'); run.progress.subscribe((update) => { const data = bars.get(update.id) || { id: update.id, builder: update.builder, target: update.target, status: update.status || '', name: ((update.target ? _targetStringFromTarget(update.target) : update.builder.name) + ' '.repeat(80)).substring(0, 40), }; if (update.status !== undefined) { data.status = update.status; } switch (update.state) { case architect_1.BuilderProgressState.Error: data.status = 'Error: ' + update.error; bars.update(update.id, data); break; case architect_1.BuilderProgressState.Stopped: data.status = 'Done.'; bars.complete(update.id); bars.update(update.id, data, update.total, update.total); break; case architect_1.BuilderProgressState.Waiting: bars.update(update.id, data); break; case architect_1.BuilderProgressState.Running: bars.update(update.id, data, update.current, update.total); break; } bars.render(); }); // Wait for full completion of the builder. try { const result = await run.lastOutput; if (result.success) { parentLogger.info(colors.green('SUCCESS')); } else { parentLogger.info(colors.red('FAILURE')); } parentLogger.info('Result: ' + JSON.stringify({ ...result, info: undefined }, null, 4)); parentLogger.info('\nLogs:'); logs.forEach((l) => parentLogger.next(l)); logs.splice(0); await run.stop(); bars.terminate(); return result.success ? 0 : 1; } catch (err) { parentLogger.info(colors.red('ERROR')); parentLogger.info('\nLogs:'); logs.forEach((l) => parentLogger.next(l)); parentLogger.fatal('Exception:'); parentLogger.fatal((err instanceof Error && err.stack) || `${err}`); return 2; } } async function main(args) { /** Parse the command line. */ const argv = (0, yargs_parser_1.default)(args, { boolean: ['help'], configuration: { 'dot-notation': false, 'boolean-negation': true, 'strip-aliased': true, 'camel-case-expansion': false, }, }); /** Create the DevKit Logger used through the CLI. */ const logger = (0, node_2.createConsoleLogger)(argv['verbose'], process.stdout, process.stderr, { info: (s) => s, debug: (s) => s, warn: (s) => colors.bold.yellow(s), error: (s) => colors.bold.red(s), fatal: (s) => colors.bold.red(s), }); // Check the target. const targetStr = argv._[0] || ''; if (!targetStr || argv.help) { // Show architect usage if there's no target. usage(logger); } // Load workspace configuration file. const currentPath = process.cwd(); const configFileNames = ['angular.json', '.angular.json', 'workspace.json', '.workspace.json']; const configFilePath = findUp(configFileNames, currentPath); if (!configFilePath) { logger.fatal(`Workspace configuration file (${configFileNames.join(', ')}) cannot be found in ` + `'${currentPath}' or in parent directories.`); return 3; } const root = path.dirname(configFilePath); const registry = new core_1.schema.CoreSchemaRegistry(); registry.addPostTransform(core_1.schema.transforms.addUndefinedDefaults); // Show usage of deprecated options registry.useXDeprecatedProvider((msg) => logger.warn(msg)); const { workspace } = await core_1.workspaces.readWorkspace(configFilePath, core_1.workspaces.createWorkspaceHost(new node_2.NodeJsSyncHost())); // Clear the console. process.stdout.write('\u001Bc'); return await _executeTarget(logger, workspace, root, argv, registry); } main(process.argv.slice(2)).then((code) => { process.exit(code); }, (err) => { // eslint-disable-next-line no-console console.error('Error: ' + err.stack || err.message || err); process.exit(-1); });