refactor(dev-infra): remove usages and dependency on shelljs (#42394)
Remove usages of shelljs and instead use spawn/spawnSync. PR Close #42394
This commit is contained in:
parent
08444c6679
commit
f0d857eff8
|
@ -10,10 +10,8 @@ ts_library(
|
|||
"//packages/benchpress",
|
||||
"@npm//@types/node",
|
||||
"@npm//@types/selenium-webdriver",
|
||||
"@npm//@types/shelljs",
|
||||
"@npm//node-uuid",
|
||||
"@npm//protractor",
|
||||
"@npm//selenium-webdriver",
|
||||
"@npm//shelljs",
|
||||
],
|
||||
)
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
* 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 {mkdir} from 'shelljs';
|
||||
import {mkdirSync} from 'fs';
|
||||
|
||||
export {verifyNoBrowserErrors} from './e2e_util';
|
||||
|
||||
|
@ -61,7 +61,9 @@ function createBenchpressRunner(): Runner {
|
|||
runId = process.env.GIT_SHA + ' ' + runId;
|
||||
}
|
||||
const resultsFolder = './dist/benchmark_results';
|
||||
mkdir('-p', resultsFolder);
|
||||
mkdirSync(resultsFolder, {
|
||||
recursive: true,
|
||||
});
|
||||
const providers: StaticProvider[] = [
|
||||
SeleniumWebDriverAdapter.PROTRACTOR_PROVIDERS,
|
||||
{provide: Options.FORCE_GC, useValue: globalOptions.forceGc},
|
||||
|
|
|
@ -144,6 +144,9 @@ var GitCommandError = /** @class */ (function (_super) {
|
|||
// we sanitize the command that will be part of the error message.
|
||||
_super.call(this, "Command failed: git " + client.sanitizeConsoleOutput(args.join(' '))) || this;
|
||||
_this.args = args;
|
||||
// Set the prototype explicitly because in ES5, the prototype is accidentally lost due to
|
||||
// a limitation in down-leveling.
|
||||
// https://github.com/Microsoft/TypeScript/wiki/FAQ#why-doesnt-extending-built-ins-like-error-array-and-map-work.
|
||||
Object.setPrototypeOf(_this, GitCommandError.prototype);
|
||||
return _this;
|
||||
}
|
||||
|
|
|
@ -13,12 +13,10 @@ ts_library(
|
|||
"@npm//@types/git-raw-commits",
|
||||
"@npm//@types/inquirer",
|
||||
"@npm//@types/node",
|
||||
"@npm//@types/shelljs",
|
||||
"@npm//@types/yargs",
|
||||
"@npm//conventional-commits-parser",
|
||||
"@npm//git-raw-commits",
|
||||
"@npm//inquirer",
|
||||
"@npm//shelljs",
|
||||
"@npm//yargs",
|
||||
],
|
||||
)
|
||||
|
|
|
@ -10,11 +10,9 @@ ts_library(
|
|||
"//dev-infra/utils",
|
||||
"@npm//@types/cli-progress",
|
||||
"@npm//@types/node",
|
||||
"@npm//@types/shelljs",
|
||||
"@npm//@types/yargs",
|
||||
"@npm//cli-progress",
|
||||
"@npm//multimatch",
|
||||
"@npm//shelljs",
|
||||
"@npm//yargs",
|
||||
],
|
||||
)
|
||||
|
|
|
@ -10,7 +10,8 @@ import {GitClient} from '../../utils/git/git-client';
|
|||
import {FormatConfig} from '../config';
|
||||
|
||||
// A callback to determine if the formatter run found a failure in formatting.
|
||||
export type CallbackFunc = (file: string, code: number, stdout: string, stderr: string) => boolean;
|
||||
export type CallbackFunc =
|
||||
(file: string, code: number|NodeJS.Signals, stdout: string, stderr: string) => boolean;
|
||||
|
||||
// The actions a formatter can take.
|
||||
export type FormatterAction = 'check'|'format';
|
||||
|
|
|
@ -26,14 +26,14 @@ export class Buildifier extends Formatter {
|
|||
check: {
|
||||
commandFlags: `${BAZEL_WARNING_FLAG} --lint=warn --mode=check --format=json`,
|
||||
callback:
|
||||
(_: string, code: number, stdout: string) => {
|
||||
(_: string, code: number|NodeJS.Signals, stdout: string) => {
|
||||
return code !== 0 || !(JSON.parse(stdout) as {success: string}).success;
|
||||
},
|
||||
},
|
||||
format: {
|
||||
commandFlags: `${BAZEL_WARNING_FLAG} --lint=fix --mode=fix`,
|
||||
callback:
|
||||
(file: string, code: number, _: string, stderr: string) => {
|
||||
(file: string, code: number|NodeJS.Signals, _: string, stderr: string) => {
|
||||
if (code !== 0) {
|
||||
error(`Error running buildifier on: ${file}`);
|
||||
error(stderr);
|
||||
|
|
|
@ -26,14 +26,14 @@ export class ClangFormat extends Formatter {
|
|||
check: {
|
||||
commandFlags: `--Werror -n -style=file`,
|
||||
callback:
|
||||
(_: string, code: number) => {
|
||||
(_: string, code: number|NodeJS.Signals) => {
|
||||
return code !== 0;
|
||||
},
|
||||
},
|
||||
format: {
|
||||
commandFlags: `-i -style=file`,
|
||||
callback:
|
||||
(file: string, code: number, _: string, stderr: string) => {
|
||||
(file: string, code: number|NodeJS.Signals, _: string, stderr: string) => {
|
||||
if (code !== 0) {
|
||||
error(`Error running clang-format on: ${file}`);
|
||||
error(stderr);
|
||||
|
|
|
@ -7,8 +7,8 @@
|
|||
*/
|
||||
|
||||
import {join} from 'path';
|
||||
import {exec} from 'shelljs';
|
||||
|
||||
import {spawnSync} from '../../utils/child-process';
|
||||
import {error} from '../../utils/console';
|
||||
|
||||
import {Formatter} from './base-formatter';
|
||||
|
@ -27,21 +27,22 @@ export class Prettier extends Formatter {
|
|||
* The configuration path of the prettier config, obtained during construction to prevent needing
|
||||
* to discover it repeatedly for each execution.
|
||||
*/
|
||||
private configPath =
|
||||
this.config['prettier'] ? exec(`${this.binaryFilePath} --find-config-path .`).trim() : '';
|
||||
private configPath = this.config['prettier'] ?
|
||||
spawnSync(this.binaryFilePath, ['--find-config-path', '.']).stdout.trim() :
|
||||
'';
|
||||
|
||||
override actions = {
|
||||
check: {
|
||||
commandFlags: `--config ${this.configPath} --check`,
|
||||
callback:
|
||||
(_: string, code: number, stdout: string) => {
|
||||
(_: string, code: number|NodeJS.Signals, stdout: string) => {
|
||||
return code !== 0;
|
||||
},
|
||||
},
|
||||
format: {
|
||||
commandFlags: `--config ${this.configPath} --write`,
|
||||
callback:
|
||||
(file: string, code: number, _: string, stderr: string) => {
|
||||
(file: string, code: number|NodeJS.Signals, _: string, stderr: string) => {
|
||||
if (code !== 0) {
|
||||
error(`Error running prettier on: ${file}`);
|
||||
error(stderr);
|
||||
|
|
|
@ -9,8 +9,8 @@
|
|||
import {Bar} from 'cli-progress';
|
||||
import * as multimatch from 'multimatch';
|
||||
import {cpus} from 'os';
|
||||
import {exec} from 'shelljs';
|
||||
|
||||
import {spawn, SpawnResult} from '../utils/child-process';
|
||||
import {info} from '../utils/console';
|
||||
|
||||
import {Formatter, FormatterAction, getActiveFormatters} from './formatters/index';
|
||||
|
@ -86,12 +86,11 @@ export function runFormatterInParallel(allFiles: string[], action: FormatterActi
|
|||
// Get the file and formatter for the next command.
|
||||
const {file, formatter} = nextCommand;
|
||||
|
||||
exec(
|
||||
`${formatter.commandFor(action)} ${file}`,
|
||||
{async: true, silent: true},
|
||||
(code, stdout, stderr) => {
|
||||
const [spawnCmd, ...spawnArgs] = [...formatter.commandFor(action).split(' '), file];
|
||||
spawn(spawnCmd, spawnArgs, {suppressErrorOnFailingExitCode: true, mode: 'silent'})
|
||||
.then(({stdout, stderr, status}: SpawnResult) => {
|
||||
// Run the provided callback function.
|
||||
const failed = formatter.callbackFor(action)(file, code, stdout, stderr);
|
||||
const failed = formatter.callbackFor(action)(file, status, stdout, stderr);
|
||||
if (failed) {
|
||||
failures.push({filePath: file, message: stderr});
|
||||
}
|
||||
|
@ -110,8 +109,7 @@ export function runFormatterInParallel(allFiles: string[], action: FormatterActi
|
|||
progressBar.stop();
|
||||
resolve(failures);
|
||||
}
|
||||
},
|
||||
);
|
||||
});
|
||||
// Mark the thread as in use as the command execution has been started.
|
||||
threads[thread] = true;
|
||||
}
|
||||
|
|
|
@ -7,13 +7,13 @@
|
|||
*/
|
||||
|
||||
import {green} from 'chalk';
|
||||
import {lstatSync, stat, Stats} from 'fs';
|
||||
import {isAbsolute, join, resolve} from 'path';
|
||||
import {lstatSync} from 'fs';
|
||||
import {resolve} from 'path';
|
||||
import {Arguments, Argv, CommandModule} from 'yargs';
|
||||
|
||||
import {buildReleaseOutput} from '../../release/build/index';
|
||||
import {spawn} from '../../utils/child-process';
|
||||
import {error, info, red} from '../../utils/console';
|
||||
import {exec} from '../../utils/shelljs';
|
||||
|
||||
|
||||
/** Command line options. */
|
||||
|
@ -52,8 +52,8 @@ async function handler({projectRoot}: Arguments<BuildAndLinkOptions>) {
|
|||
info(green(` ✓ Built release output.`));
|
||||
|
||||
for (const {outputPath, name} of releaseOutputs) {
|
||||
exec(`yarn link --cwd ${outputPath}`);
|
||||
exec(`yarn link --cwd ${projectRoot} ${name}`);
|
||||
await spawn('yarn', ['link', '--cwd', outputPath]);
|
||||
await spawn('yarn', ['link', '--cwd', projectRoot, name]);
|
||||
}
|
||||
|
||||
info(green(` ✓ Linked release packages in provided project.`));
|
||||
|
|
|
@ -22,7 +22,6 @@ var conventionalCommitsParser = require('conventional-commits-parser');
|
|||
var gitCommits_ = require('git-raw-commits');
|
||||
var cliProgress = require('cli-progress');
|
||||
var os = require('os');
|
||||
var shelljs = require('shelljs');
|
||||
var minimatch = require('minimatch');
|
||||
var ejs = require('ejs');
|
||||
var ora = require('ora');
|
||||
|
@ -316,6 +315,9 @@ var GitCommandError = /** @class */ (function (_super) {
|
|||
// we sanitize the command that will be part of the error message.
|
||||
_super.call(this, "Command failed: git " + client.sanitizeConsoleOutput(args.join(' '))) || this;
|
||||
_this.args = args;
|
||||
// Set the prototype explicitly because in ES5, the prototype is accidentally lost due to
|
||||
// a limitation in down-leveling.
|
||||
// https://github.com/Microsoft/TypeScript/wiki/FAQ#why-doesnt-extending-built-ins-like-error-array-and-map-work.
|
||||
Object.setPrototypeOf(_this, GitCommandError.prototype);
|
||||
return _this;
|
||||
}
|
||||
|
@ -2286,6 +2288,113 @@ function buildCommitMessageParser(localYargs) {
|
|||
.command(ValidateRangeModule);
|
||||
}
|
||||
|
||||
/**
|
||||
* @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
|
||||
*/
|
||||
/**
|
||||
* Spawns a given command with the specified arguments inside an interactive shell. All process
|
||||
* stdin, stdout and stderr output is printed to the current console.
|
||||
*
|
||||
* @returns a Promise resolving on success, and rejecting on command failure with the status code.
|
||||
*/
|
||||
function spawnInteractive(command, args, options) {
|
||||
if (options === void 0) { options = {}; }
|
||||
return new Promise(function (resolve, reject) {
|
||||
var commandText = command + " " + args.join(' ');
|
||||
debug("Executing command: " + commandText);
|
||||
var childProcess = child_process.spawn(command, args, tslib.__assign(tslib.__assign({}, options), { shell: true, stdio: 'inherit' }));
|
||||
childProcess.on('exit', function (status) { return status === 0 ? resolve() : reject(status); });
|
||||
});
|
||||
}
|
||||
/**
|
||||
* Spawns a given command with the specified arguments inside a shell. All process stdout
|
||||
* output is captured and returned as resolution on completion. Depending on the chosen
|
||||
* output mode, stdout/stderr output is also printed to the console, or only on error.
|
||||
*
|
||||
* @returns a Promise resolving with captured stdout and stderr on success. The promise
|
||||
* rejects on command failure.
|
||||
*/
|
||||
function spawn(command, args, options) {
|
||||
if (options === void 0) { options = {}; }
|
||||
return new Promise(function (resolve, reject) {
|
||||
var commandText = command + " " + args.join(' ');
|
||||
var outputMode = options.mode;
|
||||
debug("Executing command: " + commandText);
|
||||
var childProcess = child_process.spawn(command, args, tslib.__assign(tslib.__assign({}, options), { shell: true, stdio: 'pipe' }));
|
||||
var logOutput = '';
|
||||
var stdout = '';
|
||||
var stderr = '';
|
||||
// Capture the stdout separately so that it can be passed as resolve value.
|
||||
// This is useful if commands return parsable stdout.
|
||||
childProcess.stderr.on('data', function (message) {
|
||||
stderr += message;
|
||||
logOutput += message;
|
||||
// If console output is enabled, print the message directly to the stderr. Note that
|
||||
// we intentionally print all output to stderr as stdout should not be polluted.
|
||||
if (outputMode === undefined || outputMode === 'enabled') {
|
||||
process.stderr.write(message);
|
||||
}
|
||||
});
|
||||
childProcess.stdout.on('data', function (message) {
|
||||
stdout += message;
|
||||
logOutput += message;
|
||||
// If console output is enabled, print the message directly to the stderr. Note that
|
||||
// we intentionally print all output to stderr as stdout should not be polluted.
|
||||
if (outputMode === undefined || outputMode === 'enabled') {
|
||||
process.stderr.write(message);
|
||||
}
|
||||
});
|
||||
childProcess.on('exit', function (exitCode, signal) {
|
||||
var exitDescription = exitCode !== null ? "exit code \"" + exitCode + "\"" : "signal \"" + signal + "\"";
|
||||
var printFn = outputMode === 'on-error' ? error : debug;
|
||||
var status = statusFromExitCodeAndSignal(exitCode, signal);
|
||||
printFn("Command \"" + commandText + "\" completed with " + exitDescription + ".");
|
||||
printFn("Process output: \n" + logOutput);
|
||||
// On success, resolve the promise. Otherwise reject with the captured stderr
|
||||
// and stdout log output if the output mode was set to `silent`.
|
||||
if (status === 0 || options.suppressErrorOnFailingExitCode) {
|
||||
resolve({ stdout: stdout, stderr: stderr, status: status });
|
||||
}
|
||||
else {
|
||||
reject(outputMode === 'silent' ? logOutput : undefined);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
/**
|
||||
* Spawns a given command with the specified arguments inside a shell synchronously.
|
||||
*
|
||||
* @returns The command's stdout and stderr.
|
||||
*/
|
||||
function spawnSync(command, args, options) {
|
||||
if (options === void 0) { options = {}; }
|
||||
var commandText = command + " " + args.join(' ');
|
||||
debug("Executing command: " + commandText);
|
||||
var _a = child_process.spawnSync(command, args, tslib.__assign(tslib.__assign({}, options), { encoding: 'utf8', shell: true, stdio: 'pipe' })), exitCode = _a.status, signal = _a.signal, stdout = _a.stdout, stderr = _a.stderr;
|
||||
/** The status of the spawn result. */
|
||||
var status = statusFromExitCodeAndSignal(exitCode, signal);
|
||||
if (status === 0 || options.suppressErrorOnFailingExitCode) {
|
||||
return { status: status, stdout: stdout, stderr: stderr };
|
||||
}
|
||||
throw new Error(stderr);
|
||||
}
|
||||
/**
|
||||
* Convert the provided exitCode and signal to a single status code.
|
||||
*
|
||||
* During `exit` node provides either a `code` or `signal`, one of which is guaranteed to be
|
||||
* non-null.
|
||||
*
|
||||
* For more details see: https://nodejs.org/api/child_process.html#child_process_event_exit
|
||||
*/
|
||||
function statusFromExitCodeAndSignal(exitCode, signal) {
|
||||
var _a;
|
||||
return (_a = exitCode !== null && exitCode !== void 0 ? exitCode : signal) !== null && _a !== void 0 ? _a : -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* @license
|
||||
* Copyright Google LLC All Rights Reserved.
|
||||
|
@ -2490,7 +2599,9 @@ class Prettier extends Formatter {
|
|||
* The configuration path of the prettier config, obtained during construction to prevent needing
|
||||
* to discover it repeatedly for each execution.
|
||||
*/
|
||||
this.configPath = this.config['prettier'] ? shelljs.exec(`${this.binaryFilePath} --find-config-path .`).trim() : '';
|
||||
this.configPath = this.config['prettier'] ?
|
||||
spawnSync(this.binaryFilePath, ['--find-config-path', '.']).stdout.trim() :
|
||||
'';
|
||||
this.actions = {
|
||||
check: {
|
||||
commandFlags: `--config ${this.configPath} --check`,
|
||||
|
@ -2593,9 +2704,11 @@ function runFormatterInParallel(allFiles, action) {
|
|||
}
|
||||
// Get the file and formatter for the next command.
|
||||
const { file, formatter } = nextCommand;
|
||||
shelljs.exec(`${formatter.commandFor(action)} ${file}`, { async: true, silent: true }, (code, stdout, stderr) => {
|
||||
const [spawnCmd, ...spawnArgs] = [...formatter.commandFor(action).split(' '), file];
|
||||
spawn(spawnCmd, spawnArgs, { suppressErrorOnFailingExitCode: true, mode: 'silent' })
|
||||
.then(({ stdout, stderr, status }) => {
|
||||
// Run the provided callback function.
|
||||
const failed = formatter.callbackFor(action)(file, code, stdout, stderr);
|
||||
const failed = formatter.callbackFor(action)(file, status, stdout, stderr);
|
||||
if (failed) {
|
||||
failures.push({ filePath: file, message: stderr });
|
||||
}
|
||||
|
@ -3222,21 +3335,6 @@ const CheckoutCommandModule = {
|
|||
describe: 'Checkout a PR from the upstream repo',
|
||||
};
|
||||
|
||||
/**
|
||||
* @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
|
||||
*/
|
||||
/**
|
||||
* Runs an given command as child process. By default, child process
|
||||
* output will not be printed.
|
||||
*/
|
||||
function exec(cmd, opts) {
|
||||
return shelljs.exec(cmd, tslib.__assign(tslib.__assign({ silent: true }, opts), { async: false }));
|
||||
}
|
||||
|
||||
/**
|
||||
* @license
|
||||
* Copyright Google LLC All Rights Reserved.
|
||||
|
@ -3340,8 +3438,10 @@ function discoverNewConflictsForPr(newPrNumber, updatedAfter) {
|
|||
if (err instanceof GitCommandError) {
|
||||
conflicts.push(pr);
|
||||
}
|
||||
else {
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
// Abort any outstanding rebase attempt.
|
||||
git.runGraceful(['rebase', '--abort'], { stdio: 'ignore' });
|
||||
progressBar.increment(1);
|
||||
|
@ -3350,7 +3450,7 @@ function discoverNewConflictsForPr(newPrNumber, updatedAfter) {
|
|||
progressBar.stop();
|
||||
info();
|
||||
info(`Result:`);
|
||||
cleanUpGitState(previousBranchOrRevision);
|
||||
git.checkout(previousBranchOrRevision, true);
|
||||
// If no conflicts are found, exit successfully.
|
||||
if (conflicts.length === 0) {
|
||||
info(`No new conflicting PRs found after #${newPrNumber} merging`);
|
||||
|
@ -3365,17 +3465,6 @@ function discoverNewConflictsForPr(newPrNumber, updatedAfter) {
|
|||
process.exit(1);
|
||||
});
|
||||
}
|
||||
/** Reset git back to the provided branch or revision. */
|
||||
function cleanUpGitState(previousBranchOrRevision) {
|
||||
// Ensure that any outstanding rebases are aborted.
|
||||
exec(`git rebase --abort`);
|
||||
// Ensure that any changes in the current repo state are cleared.
|
||||
exec(`git reset --hard`);
|
||||
// Checkout the original branch from before the run began.
|
||||
exec(`git checkout ${previousBranchOrRevision}`);
|
||||
// Delete the generated branch.
|
||||
exec(`git branch -D ${tempWorkingBranch}`);
|
||||
}
|
||||
|
||||
/**
|
||||
* @license
|
||||
|
@ -5822,88 +5911,6 @@ const ReleaseNotesCommandModule = {
|
|||
describe: 'Generate release notes',
|
||||
};
|
||||
|
||||
/**
|
||||
* @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
|
||||
*/
|
||||
/**
|
||||
* Spawns a given command with the specified arguments inside an interactive shell. All process
|
||||
* stdin, stdout and stderr output is printed to the current console.
|
||||
*
|
||||
* @returns a Promise resolving on success, and rejecting on command failure with the status code.
|
||||
*/
|
||||
function spawnInteractive(command, args, options) {
|
||||
if (options === void 0) { options = {}; }
|
||||
return new Promise(function (resolve, reject) {
|
||||
var commandText = command + " " + args.join(' ');
|
||||
debug("Executing command: " + commandText);
|
||||
var childProcess = child_process.spawn(command, args, tslib.__assign(tslib.__assign({}, options), { shell: true, stdio: 'inherit' }));
|
||||
childProcess.on('exit', function (status) { return status === 0 ? resolve() : reject(status); });
|
||||
});
|
||||
}
|
||||
/**
|
||||
* Spawns a given command with the specified arguments inside a shell. All process stdout
|
||||
* output is captured and returned as resolution on completion. Depending on the chosen
|
||||
* output mode, stdout/stderr output is also printed to the console, or only on error.
|
||||
*
|
||||
* @returns a Promise resolving with captured stdout and stderr on success. The promise
|
||||
* rejects on command failure
|
||||
*/
|
||||
function spawn(command, args, options) {
|
||||
if (options === void 0) { options = {}; }
|
||||
return new Promise(function (resolve, reject) {
|
||||
var commandText = command + " " + args.join(' ');
|
||||
var outputMode = options.mode;
|
||||
debug("Executing command: " + commandText);
|
||||
var childProcess = child_process.spawn(command, args, tslib.__assign(tslib.__assign({}, options), { shell: true, stdio: 'pipe' }));
|
||||
var logOutput = '';
|
||||
var stdout = '';
|
||||
var stderr = '';
|
||||
// Capture the stdout separately so that it can be passed as resolve value.
|
||||
// This is useful if commands return parsable stdout.
|
||||
childProcess.stderr.on('data', function (message) {
|
||||
stderr += message;
|
||||
logOutput += message;
|
||||
// If console output is enabled, print the message directly to the stderr. Note that
|
||||
// we intentionally print all output to stderr as stdout should not be polluted.
|
||||
if (outputMode === undefined || outputMode === 'enabled') {
|
||||
process.stderr.write(message);
|
||||
}
|
||||
});
|
||||
childProcess.stdout.on('data', function (message) {
|
||||
stdout += message;
|
||||
logOutput += message;
|
||||
// If console output is enabled, print the message directly to the stderr. Note that
|
||||
// we intentionally print all output to stderr as stdout should not be polluted.
|
||||
if (outputMode === undefined || outputMode === 'enabled') {
|
||||
process.stderr.write(message);
|
||||
}
|
||||
});
|
||||
childProcess.on('exit', function (exitCode, signal) {
|
||||
var exitDescription = exitCode !== null ? "exit code \"" + exitCode + "\"" : "signal \"" + signal + "\"";
|
||||
var printFn = outputMode === 'on-error' ? error : debug;
|
||||
var status = statusFromExitCodeAndSignal(exitCode, signal);
|
||||
printFn("Command \"" + commandText + "\" completed with " + exitDescription + ".");
|
||||
printFn("Process output: \n" + logOutput);
|
||||
// On success, resolve the promise. Otherwise reject with the captured stderr
|
||||
// and stdout log output if the output mode was set to `silent`.
|
||||
if (status === 0 || options.suppressErrorOnFailingExitCode) {
|
||||
resolve({ stdout: stdout, stderr: stderr, status: status });
|
||||
}
|
||||
else {
|
||||
reject(outputMode === 'silent' ? logOutput : undefined);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
/** Convert the provided exitCode and signal to a single status code. */
|
||||
function statusFromExitCodeAndSignal(exitCode, signal) {
|
||||
return exitCode !== null ? exitCode : signal !== null ? signal : -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* @license
|
||||
* Copyright Google LLC All Rights Reserved.
|
||||
|
@ -7496,20 +7503,17 @@ const ReleaseSetDistTagCommand = {
|
|||
*/
|
||||
function buildEnvStamp(mode) {
|
||||
console.info(`BUILD_SCM_BRANCH ${getCurrentBranch()}`);
|
||||
console.info(`BUILD_SCM_COMMIT_SHA ${getCurrentSha()}`);
|
||||
console.info(`BUILD_SCM_HASH ${getCurrentSha()}`);
|
||||
console.info(`BUILD_SCM_COMMIT_SHA ${getCurrentBranchOrRevision()}`);
|
||||
console.info(`BUILD_SCM_HASH ${getCurrentBranchOrRevision()}`);
|
||||
console.info(`BUILD_SCM_LOCAL_CHANGES ${hasLocalChanges()}`);
|
||||
console.info(`BUILD_SCM_USER ${getCurrentGitUser()}`);
|
||||
console.info(`BUILD_SCM_VERSION ${getSCMVersion(mode)}`);
|
||||
process.exit(0);
|
||||
}
|
||||
/** Run the exec command and return the stdout as a trimmed string. */
|
||||
function exec$1(cmd) {
|
||||
return exec(cmd).trim();
|
||||
process.exit();
|
||||
}
|
||||
/** Whether the repo has local changes. */
|
||||
function hasLocalChanges() {
|
||||
return !!exec$1(`git status --untracked-files=no --porcelain`);
|
||||
const git = GitClient.get();
|
||||
return git.hasUncommittedChanges();
|
||||
}
|
||||
/**
|
||||
* Get the version for generated packages.
|
||||
|
@ -7518,30 +7522,34 @@ function hasLocalChanges() {
|
|||
* In release mode, the version is based on the base package.json version.
|
||||
*/
|
||||
function getSCMVersion(mode) {
|
||||
if (mode === 'release') {
|
||||
const git = GitClient.get();
|
||||
if (mode === 'release') {
|
||||
const packageJsonPath = path.join(git.baseDir, 'package.json');
|
||||
const { version } = require(packageJsonPath);
|
||||
return version;
|
||||
}
|
||||
if (mode === 'snapshot') {
|
||||
const version = exec$1(`git describe --match [0-9]*.[0-9]*.[0-9]* --abbrev=7 --tags HEAD`);
|
||||
const version = git.run(['describe', '--match', '[0-9]*.[0-9]*.[0-9]*', '--abbrev=7', '--tags', 'HEAD'])
|
||||
.stdout.trim();
|
||||
return `${version.replace(/-([0-9]+)-g/, '+$1.sha-')}${(hasLocalChanges() ? '.with-local-changes' : '')}`;
|
||||
}
|
||||
return '0.0.0';
|
||||
}
|
||||
/** Get the current SHA of HEAD. */
|
||||
function getCurrentSha() {
|
||||
return exec$1(`git rev-parse HEAD`);
|
||||
/** Get the current branch or revision of HEAD. */
|
||||
function getCurrentBranchOrRevision() {
|
||||
const git = GitClient.get();
|
||||
return git.getCurrentBranchOrRevision();
|
||||
}
|
||||
/** Get the currently checked out branch. */
|
||||
function getCurrentBranch() {
|
||||
return exec$1(`git symbolic-ref --short HEAD`);
|
||||
const git = GitClient.get();
|
||||
return git.run(['symbolic-ref', '--short', 'HEAD']).stdout.trim();
|
||||
}
|
||||
/** Get the current git user based on the git config. */
|
||||
function getCurrentGitUser() {
|
||||
const userName = exec$1(`git config user.name`);
|
||||
const userEmail = exec$1(`git config user.email`);
|
||||
const git = GitClient.get();
|
||||
const userName = git.run(['config', 'user.name']).stdout.trim();
|
||||
const userEmail = git.run(['config', 'user.email']).stdout.trim();
|
||||
return `${userName} <${userEmail}>`;
|
||||
}
|
||||
|
||||
|
@ -8028,8 +8036,8 @@ function handler$d({ projectRoot }) {
|
|||
}
|
||||
info(chalk.green(` ✓ Built release output.`));
|
||||
for (const { outputPath, name } of releaseOutputs) {
|
||||
exec(`yarn link --cwd ${outputPath}`);
|
||||
exec(`yarn link --cwd ${projectRoot} ${name}`);
|
||||
yield spawn('yarn', ['link', '--cwd', outputPath]);
|
||||
yield spawn('yarn', ['link', '--cwd', projectRoot, name]);
|
||||
}
|
||||
info(chalk.green(` ✓ Linked release packages in provided project.`));
|
||||
});
|
||||
|
|
|
@ -11,7 +11,6 @@ ts_library(
|
|||
"//dev-infra/utils",
|
||||
"@npm//@types/cli-progress",
|
||||
"@npm//@types/node",
|
||||
"@npm//@types/shelljs",
|
||||
"@npm//@types/yargs",
|
||||
"@npm//typed-graphqlify",
|
||||
],
|
||||
|
|
|
@ -13,7 +13,6 @@ import {error, info} from '../../utils/console';
|
|||
import {AuthenticatedGitClient} from '../../utils/git/authenticated-git-client';
|
||||
import {GitCommandError} from '../../utils/git/git-client';
|
||||
import {getPendingPrs} from '../../utils/github';
|
||||
import {exec} from '../../utils/shelljs';
|
||||
|
||||
|
||||
/* Graphql schema for the response body for each pending PR. */
|
||||
|
@ -125,9 +124,10 @@ export async function discoverNewConflictsForPr(newPrNumber: number, updatedAfte
|
|||
} catch (err) {
|
||||
if (err instanceof GitCommandError) {
|
||||
conflicts.push(pr);
|
||||
}
|
||||
} else {
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
// Abort any outstanding rebase attempt.
|
||||
git.runGraceful(['rebase', '--abort'], {stdio: 'ignore'});
|
||||
|
||||
|
@ -138,7 +138,7 @@ export async function discoverNewConflictsForPr(newPrNumber: number, updatedAfte
|
|||
info();
|
||||
info(`Result:`);
|
||||
|
||||
cleanUpGitState(previousBranchOrRevision);
|
||||
git.checkout(previousBranchOrRevision, true);
|
||||
|
||||
// If no conflicts are found, exit successfully.
|
||||
if (conflicts.length === 0) {
|
||||
|
@ -154,15 +154,3 @@ export async function discoverNewConflictsForPr(newPrNumber: number, updatedAfte
|
|||
error.groupEnd();
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
/** Reset git back to the provided branch or revision. */
|
||||
export function cleanUpGitState(previousBranchOrRevision: string) {
|
||||
// Ensure that any outstanding rebases are aborted.
|
||||
exec(`git rebase --abort`);
|
||||
// Ensure that any changes in the current repo state are cleared.
|
||||
exec(`git reset --hard`);
|
||||
// Checkout the original branch from before the run began.
|
||||
exec(`git checkout ${previousBranchOrRevision}`);
|
||||
// Delete the generated branch.
|
||||
exec(`git branch -D ${tempWorkingBranch}`);
|
||||
}
|
||||
|
|
|
@ -17,11 +17,9 @@ ts_library(
|
|||
"//dev-infra/utils",
|
||||
"@npm//@types/minimatch",
|
||||
"@npm//@types/node",
|
||||
"@npm//@types/shelljs",
|
||||
"@npm//@types/yaml",
|
||||
"@npm//@types/yargs",
|
||||
"@npm//minimatch",
|
||||
"@npm//shelljs",
|
||||
"@npm//yaml",
|
||||
"@npm//yargs",
|
||||
],
|
||||
|
|
|
@ -9,8 +9,6 @@
|
|||
import {join} from 'path';
|
||||
import {GitClient} from '../../utils/git/git-client';
|
||||
|
||||
import {exec as _exec} from '../../utils/shelljs';
|
||||
|
||||
export type EnvStampMode = 'snapshot'|'release';
|
||||
|
||||
/**
|
||||
|
@ -25,22 +23,18 @@ export type EnvStampMode = 'snapshot'|'release';
|
|||
*/
|
||||
export function buildEnvStamp(mode: EnvStampMode) {
|
||||
console.info(`BUILD_SCM_BRANCH ${getCurrentBranch()}`);
|
||||
console.info(`BUILD_SCM_COMMIT_SHA ${getCurrentSha()}`);
|
||||
console.info(`BUILD_SCM_HASH ${getCurrentSha()}`);
|
||||
console.info(`BUILD_SCM_COMMIT_SHA ${getCurrentBranchOrRevision()}`);
|
||||
console.info(`BUILD_SCM_HASH ${getCurrentBranchOrRevision()}`);
|
||||
console.info(`BUILD_SCM_LOCAL_CHANGES ${hasLocalChanges()}`);
|
||||
console.info(`BUILD_SCM_USER ${getCurrentGitUser()}`);
|
||||
console.info(`BUILD_SCM_VERSION ${getSCMVersion(mode)}`);
|
||||
process.exit(0);
|
||||
}
|
||||
|
||||
/** Run the exec command and return the stdout as a trimmed string. */
|
||||
function exec(cmd: string) {
|
||||
return _exec(cmd).trim();
|
||||
process.exit();
|
||||
}
|
||||
|
||||
/** Whether the repo has local changes. */
|
||||
function hasLocalChanges() {
|
||||
return !!exec(`git status --untracked-files=no --porcelain`);
|
||||
const git = GitClient.get();
|
||||
return git.hasUncommittedChanges();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -50,34 +44,38 @@ function hasLocalChanges() {
|
|||
* In release mode, the version is based on the base package.json version.
|
||||
*/
|
||||
function getSCMVersion(mode: EnvStampMode) {
|
||||
if (mode === 'release') {
|
||||
const git = GitClient.get();
|
||||
if (mode === 'release') {
|
||||
const packageJsonPath = join(git.baseDir, 'package.json');
|
||||
const {version} = require(packageJsonPath);
|
||||
return version;
|
||||
}
|
||||
if (mode === 'snapshot') {
|
||||
const version = exec(`git describe --match [0-9]*.[0-9]*.[0-9]* --abbrev=7 --tags HEAD`);
|
||||
const version =
|
||||
git.run(['describe', '--match', '[0-9]*.[0-9]*.[0-9]*', '--abbrev=7', '--tags', 'HEAD'])
|
||||
.stdout.trim();
|
||||
return `${version.replace(/-([0-9]+)-g/, '+$1.sha-')}${
|
||||
(hasLocalChanges() ? '.with-local-changes' : '')}`;
|
||||
}
|
||||
return '0.0.0';
|
||||
}
|
||||
|
||||
/** Get the current SHA of HEAD. */
|
||||
function getCurrentSha() {
|
||||
return exec(`git rev-parse HEAD`);
|
||||
/** Get the current branch or revision of HEAD. */
|
||||
function getCurrentBranchOrRevision() {
|
||||
const git = GitClient.get();
|
||||
return git.getCurrentBranchOrRevision();
|
||||
}
|
||||
|
||||
/** Get the currently checked out branch. */
|
||||
function getCurrentBranch() {
|
||||
return exec(`git symbolic-ref --short HEAD`);
|
||||
const git = GitClient.get();
|
||||
return git.run(['symbolic-ref', '--short', 'HEAD']).stdout.trim();
|
||||
}
|
||||
|
||||
/** Get the current git user based on the git config. */
|
||||
function getCurrentGitUser() {
|
||||
const userName = exec(`git config user.name`);
|
||||
const userEmail = exec(`git config user.email`);
|
||||
|
||||
const git = GitClient.get();
|
||||
const userName = git.run(['config', 'user.name']).stdout.trim();
|
||||
const userEmail = git.run(['config', 'user.email']).stdout.trim();
|
||||
return `${userName} <${userEmail}>`;
|
||||
}
|
||||
|
|
|
@ -33,7 +33,6 @@
|
|||
"protractor": "<from-root>",
|
||||
"selenium-webdriver": "<from-root>",
|
||||
"semver": "<from-root>",
|
||||
"shelljs": "<from-root>",
|
||||
"ts-node": "<from-root>",
|
||||
"tslib": "<from-root>",
|
||||
"typed-graphqlify": "<from-root>",
|
||||
|
|
|
@ -21,12 +21,10 @@ ts_library(
|
|||
"@npm//@types/inquirer",
|
||||
"@npm//@types/node",
|
||||
"@npm//@types/semver",
|
||||
"@npm//@types/shelljs",
|
||||
"@npm//@types/yargs",
|
||||
"@npm//chalk",
|
||||
"@npm//inquirer",
|
||||
"@npm//semver",
|
||||
"@npm//shelljs",
|
||||
"@npm//tslib",
|
||||
"@npm//typed-graphqlify",
|
||||
"@npm//yargs",
|
||||
|
|
|
@ -10,6 +10,7 @@ import {spawn as _spawn, SpawnOptions as _SpawnOptions, spawnSync as _spawnSync,
|
|||
import {debug, error} from './console';
|
||||
|
||||
|
||||
/** Interface describing the options for spawning a process synchronously. */
|
||||
export interface SpawnSyncOptions extends Omit<_SpawnSyncOptions, 'shell'|'stdio'> {
|
||||
/** Whether to prevent exit codes being treated as failures. */
|
||||
suppressErrorOnFailingExitCode?: boolean;
|
||||
|
@ -58,7 +59,7 @@ export function spawnInteractive(
|
|||
* output mode, stdout/stderr output is also printed to the console, or only on error.
|
||||
*
|
||||
* @returns a Promise resolving with captured stdout and stderr on success. The promise
|
||||
* rejects on command failure
|
||||
* rejects on command failure.
|
||||
*/
|
||||
export function spawn(
|
||||
command: string, args: string[], options: SpawnOptions = {}): Promise<SpawnResult> {
|
||||
|
@ -115,12 +116,12 @@ export function spawn(
|
|||
}
|
||||
|
||||
/**
|
||||
* Spawns a given command with the specified arguments inside a shell syncronously.
|
||||
* Spawns a given command with the specified arguments inside a shell synchronously.
|
||||
*
|
||||
* @returns The command's stdout and stderr.
|
||||
*/
|
||||
export function spawnSync(
|
||||
command: string, args: string[], options: SpawnOptions = {}): SpawnResult {
|
||||
command: string, args: string[], options: SpawnSyncOptions = {}): SpawnResult {
|
||||
const commandText = `${command} ${args.join(' ')}`;
|
||||
debug(`Executing command: ${commandText}`);
|
||||
|
||||
|
@ -137,9 +138,14 @@ export function spawnSync(
|
|||
throw new Error(stderr);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/** Convert the provided exitCode and signal to a single status code. */
|
||||
/**
|
||||
* Convert the provided exitCode and signal to a single status code.
|
||||
*
|
||||
* During `exit` node provides either a `code` or `signal`, one of which is guaranteed to be
|
||||
* non-null.
|
||||
*
|
||||
* For more details see: https://nodejs.org/api/child_process.html#child_process_event_exit
|
||||
*/
|
||||
function statusFromExitCodeAndSignal(exitCode: number|null, signal: NodeJS.Signals|null) {
|
||||
return exitCode !== null ? exitCode : signal !== null ? signal : -1;
|
||||
return exitCode ?? signal ?? -1;
|
||||
}
|
||||
|
|
|
@ -23,6 +23,10 @@ export class GitCommandError extends Error {
|
|||
// accidentally leak the Github token that might be used in a command,
|
||||
// we sanitize the command that will be part of the error message.
|
||||
super(`Command failed: git ${client.sanitizeConsoleOutput(args.join(' '))}`);
|
||||
|
||||
// Set the prototype explicitly because in ES5, the prototype is accidentally lost due to
|
||||
// a limitation in down-leveling.
|
||||
// https://github.com/Microsoft/TypeScript/wiki/FAQ#why-doesnt-extending-built-ins-like-error-array-and-map-work.
|
||||
Object.setPrototypeOf(this, GitCommandError.prototype);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,17 +0,0 @@
|
|||
/**
|
||||
* @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 {exec as _exec, ExecOptions, ShellString} from 'shelljs';
|
||||
|
||||
/**
|
||||
* Runs an given command as child process. By default, child process
|
||||
* output will not be printed.
|
||||
*/
|
||||
export function exec(cmd: string, opts?: Omit<ExecOptions, 'async'>): ShellString {
|
||||
return _exec(cmd, {silent: true, ...opts, async: false});
|
||||
}
|
Loading…
Reference in New Issue