Revert "refactor(dev-infra): remove usages and dependency on shelljs (#42394)" (#42829)

This reverts commit f0d857eff8.

PR Close #42829
This commit is contained in:
Andrew Kushnir
2021-07-12 15:24:54 -07:00
parent b33665ab2c
commit 3d668162d9
21 changed files with 228 additions and 208 deletions
@@ -10,8 +10,10 @@ 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 {mkdirSync} from 'fs';
import {mkdir} from 'shelljs';
export {verifyNoBrowserErrors} from './e2e_util';
@@ -61,9 +61,7 @@ function createBenchpressRunner(): Runner {
runId = process.env.GIT_SHA + ' ' + runId;
}
const resultsFolder = './dist/benchmark_results';
mkdirSync(resultsFolder, {
recursive: true,
});
mkdir('-p', resultsFolder);
const providers: StaticProvider[] = [
SeleniumWebDriverAdapter.PROTRACTOR_PROVIDERS,
{provide: Options.FORCE_GC, useValue: globalOptions.forceGc},
-3
View File
@@ -144,9 +144,6 @@ 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;
}
+2
View File
@@ -13,10 +13,12 @@ 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",
],
)
+2
View File
@@ -10,9 +10,11 @@ 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,8 +10,7 @@ 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|NodeJS.Signals, stdout: string, stderr: string) => boolean;
export type CallbackFunc = (file: string, code: number, stdout: string, stderr: string) => boolean;
// The actions a formatter can take.
export type FormatterAction = 'check'|'format';
+2 -2
View File
@@ -26,14 +26,14 @@ export class Buildifier extends Formatter {
check: {
commandFlags: `${BAZEL_WARNING_FLAG} --lint=warn --mode=check --format=json`,
callback:
(_: string, code: number|NodeJS.Signals, stdout: string) => {
(_: string, code: number, 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|NodeJS.Signals, _: string, stderr: string) => {
(file: string, code: number, _: string, stderr: string) => {
if (code !== 0) {
error(`Error running buildifier on: ${file}`);
error(stderr);
+2 -2
View File
@@ -26,14 +26,14 @@ export class ClangFormat extends Formatter {
check: {
commandFlags: `--Werror -n -style=file`,
callback:
(_: string, code: number|NodeJS.Signals) => {
(_: string, code: number) => {
return code !== 0;
},
},
format: {
commandFlags: `-i -style=file`,
callback:
(file: string, code: number|NodeJS.Signals, _: string, stderr: string) => {
(file: string, code: number, _: string, stderr: string) => {
if (code !== 0) {
error(`Error running clang-format on: ${file}`);
error(stderr);
+5 -6
View File
@@ -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,22 +27,21 @@ 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'] ?
spawnSync(this.binaryFilePath, ['--find-config-path', '.']).stdout.trim() :
'';
private configPath =
this.config['prettier'] ? exec(`${this.binaryFilePath} --find-config-path .`).trim() : '';
override actions = {
check: {
commandFlags: `--config ${this.configPath} --check`,
callback:
(_: string, code: number|NodeJS.Signals, stdout: string) => {
(_: string, code: number, stdout: string) => {
return code !== 0;
},
},
format: {
commandFlags: `--config ${this.configPath} --write`,
callback:
(file: string, code: number|NodeJS.Signals, _: string, stderr: string) => {
(file: string, code: number, _: string, stderr: string) => {
if (code !== 0) {
error(`Error running prettier on: ${file}`);
error(stderr);
+8 -6
View File
@@ -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,11 +86,12 @@ export function runFormatterInParallel(allFiles: string[], action: FormatterActi
// Get the file and formatter for the next command.
const {file, formatter} = nextCommand;
const [spawnCmd, ...spawnArgs] = [...formatter.commandFor(action).split(' '), file];
spawn(spawnCmd, spawnArgs, {suppressErrorOnFailingExitCode: true, mode: 'silent'})
.then(({stdout, stderr, status}: SpawnResult) => {
exec(
`${formatter.commandFor(action)} ${file}`,
{async: true, silent: true},
(code, stdout, stderr) => {
// Run the provided callback function.
const failed = formatter.callbackFor(action)(file, status, stdout, stderr);
const failed = formatter.callbackFor(action)(file, code, stdout, stderr);
if (failed) {
failures.push({filePath: file, message: stderr});
}
@@ -109,7 +110,8 @@ 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;
}
+5 -5
View File
@@ -7,13 +7,13 @@
*/
import {green} from 'chalk';
import {lstatSync} from 'fs';
import {resolve} from 'path';
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 {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) {
await spawn('yarn', ['link', '--cwd', outputPath]);
await spawn('yarn', ['link', '--cwd', projectRoot, name]);
exec(`yarn link --cwd ${outputPath}`);
exec(`yarn link --cwd ${projectRoot} ${name}`);
}
info(green(` ✓ Linked release packages in provided project.`));
+132 -140
View File
File diff suppressed because it is too large Load Diff
@@ -11,6 +11,7 @@ ts_library(
"//dev-infra/utils",
"@npm//@types/cli-progress",
"@npm//@types/node",
"@npm//@types/shelljs",
"@npm//@types/yargs",
"@npm//typed-graphqlify",
],
+15 -3
View File
@@ -13,6 +13,7 @@ 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. */
@@ -124,9 +125,8 @@ export async function discoverNewConflictsForPr(newPrNumber: number, updatedAfte
} catch (err) {
if (err instanceof GitCommandError) {
conflicts.push(pr);
} else {
throw err;
}
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:`);
git.checkout(previousBranchOrRevision, true);
cleanUpGitState(previousBranchOrRevision);
// If no conflicts are found, exit successfully.
if (conflicts.length === 0) {
@@ -154,3 +154,15 @@ 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}`);
}
+2
View File
@@ -17,9 +17,11 @@ 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",
],
+20 -18
View File
@@ -9,6 +9,8 @@
import {join} from 'path';
import {GitClient} from '../../utils/git/git-client';
import {exec as _exec} from '../../utils/shelljs';
export type EnvStampMode = 'snapshot'|'release';
/**
@@ -23,18 +25,22 @@ export type EnvStampMode = 'snapshot'|'release';
*/
export function buildEnvStamp(mode: EnvStampMode) {
console.info(`BUILD_SCM_BRANCH ${getCurrentBranch()}`);
console.info(`BUILD_SCM_COMMIT_SHA ${getCurrentBranchOrRevision()}`);
console.info(`BUILD_SCM_HASH ${getCurrentBranchOrRevision()}`);
console.info(`BUILD_SCM_COMMIT_SHA ${getCurrentSha()}`);
console.info(`BUILD_SCM_HASH ${getCurrentSha()}`);
console.info(`BUILD_SCM_LOCAL_CHANGES ${hasLocalChanges()}`);
console.info(`BUILD_SCM_USER ${getCurrentGitUser()}`);
console.info(`BUILD_SCM_VERSION ${getSCMVersion(mode)}`);
process.exit();
process.exit(0);
}
/** Run the exec command and return the stdout as a trimmed string. */
function exec(cmd: string) {
return _exec(cmd).trim();
}
/** Whether the repo has local changes. */
function hasLocalChanges() {
const git = GitClient.get();
return git.hasUncommittedChanges();
return !!exec(`git status --untracked-files=no --porcelain`);
}
/**
@@ -44,38 +50,34 @@ function hasLocalChanges() {
* In release mode, the version is based on the base package.json version.
*/
function getSCMVersion(mode: EnvStampMode) {
const git = GitClient.get();
if (mode === 'release') {
const git = GitClient.get();
const packageJsonPath = join(git.baseDir, 'package.json');
const {version} = require(packageJsonPath);
return version;
}
if (mode === 'snapshot') {
const version =
git.run(['describe', '--match', '[0-9]*.[0-9]*.[0-9]*', '--abbrev=7', '--tags', 'HEAD'])
.stdout.trim();
const version = exec(`git describe --match [0-9]*.[0-9]*.[0-9]* --abbrev=7 --tags HEAD`);
return `${version.replace(/-([0-9]+)-g/, '+$1.sha-')}${
(hasLocalChanges() ? '.with-local-changes' : '')}`;
}
return '0.0.0';
}
/** Get the current branch or revision of HEAD. */
function getCurrentBranchOrRevision() {
const git = GitClient.get();
return git.getCurrentBranchOrRevision();
/** Get the current SHA of HEAD. */
function getCurrentSha() {
return exec(`git rev-parse HEAD`);
}
/** Get the currently checked out branch. */
function getCurrentBranch() {
const git = GitClient.get();
return git.run(['symbolic-ref', '--short', 'HEAD']).stdout.trim();
return exec(`git symbolic-ref --short HEAD`);
}
/** Get the current git user based on the git config. */
function getCurrentGitUser() {
const git = GitClient.get();
const userName = git.run(['config', 'user.name']).stdout.trim();
const userEmail = git.run(['config', 'user.email']).stdout.trim();
const userName = exec(`git config user.name`);
const userEmail = exec(`git config user.email`);
return `${userName} <${userEmail}>`;
}
+1
View File
@@ -33,6 +33,7 @@
"protractor": "<from-root>",
"selenium-webdriver": "<from-root>",
"semver": "<from-root>",
"shelljs": "<from-root>",
"ts-node": "<from-root>",
"tslib": "<from-root>",
"typed-graphqlify": "<from-root>",
+2
View File
@@ -21,10 +21,12 @@ 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",
+7 -13
View File
@@ -10,7 +10,6 @@ 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;
@@ -59,7 +58,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> {
@@ -116,12 +115,12 @@ export function spawn(
}
/**
* Spawns a given command with the specified arguments inside a shell synchronously.
* Spawns a given command with the specified arguments inside a shell syncronously.
*
* @returns The command's stdout and stderr.
*/
export function spawnSync(
command: string, args: string[], options: SpawnSyncOptions = {}): SpawnResult {
command: string, args: string[], options: SpawnOptions = {}): SpawnResult {
const commandText = `${command} ${args.join(' ')}`;
debug(`Executing command: ${commandText}`);
@@ -138,14 +137,9 @@ export function spawnSync(
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
*/
/** Convert the provided exitCode and signal to a single status code. */
function statusFromExitCodeAndSignal(exitCode: number|null, signal: NodeJS.Signals|null) {
return exitCode ?? signal ?? -1;
return exitCode !== null ? exitCode : signal !== null ? signal : -1;
}
-4
View File
@@ -23,10 +23,6 @@ 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);
}
}
+17
View File
@@ -0,0 +1,17 @@
/**
* @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});
}