fix(dev-infra): allow build-worker to be used in forked process (#40012)
Generates a local copy of the build-worker file to allow it to be loaded at runtime in a forked process. PR Close #40012
This commit is contained in:
parent
74e42cf7d5
commit
c043ecf317
|
@ -1,6 +1,6 @@
|
|||
load("@build_bazel_rules_nodejs//:index.bzl", "generated_file_test", "pkg_npm")
|
||||
load("@build_bazel_rules_nodejs//:index.bzl", "pkg_npm")
|
||||
load("@npm//@bazel/typescript:index.bzl", "ts_library")
|
||||
load("@npm//@bazel/rollup:index.bzl", "rollup_bundle")
|
||||
load("//dev-infra:index.bzl", "ng_dev_rolled_up_generated_file")
|
||||
|
||||
ts_library(
|
||||
name = "cli",
|
||||
|
@ -24,30 +24,6 @@ ts_library(
|
|||
],
|
||||
)
|
||||
|
||||
rollup_bundle(
|
||||
name = "cli_rollup",
|
||||
args = [
|
||||
"--plugin",
|
||||
"rollup-plugin-hashbang",
|
||||
],
|
||||
entry_point = ":cli.ts",
|
||||
format = "cjs",
|
||||
silent = True,
|
||||
sourcemap = "false",
|
||||
deps = [
|
||||
":cli",
|
||||
# TODO(josephperrott): Determine if this plugin is the best method for ensuring the hashbang
|
||||
# in both local and published use case.
|
||||
"@npm//rollup-plugin-hashbang",
|
||||
],
|
||||
)
|
||||
|
||||
generated_file_test(
|
||||
name = "local_ng_dev",
|
||||
src = "ng-dev.js",
|
||||
generated = "cli_rollup",
|
||||
)
|
||||
|
||||
genrule(
|
||||
name = "package-json",
|
||||
srcs = [
|
||||
|
@ -93,3 +69,34 @@ pkg_npm(
|
|||
"//dev-infra/ts-circular-dependencies",
|
||||
],
|
||||
)
|
||||
|
||||
# Because the angular/angular repository relies on the local repository for running ng-dev commands,
|
||||
# the rollup generated javascript files are committed into the repository to be used as node
|
||||
# scripts. To ensure they stay up to date, they are created using a generated file test.
|
||||
#
|
||||
# Currently there are two generated files which are needed
|
||||
# ng-dev.js - The main script representing ng-dev
|
||||
# build-worker.js - The worker script for the `ng-dev release build` command, allowing it to run
|
||||
# in a forked process.
|
||||
ng_dev_rolled_up_generated_file(
|
||||
name = "ng-dev",
|
||||
entry_point = ":cli.ts",
|
||||
rollup_args = [
|
||||
"--plugin",
|
||||
"rollup-plugin-hashbang",
|
||||
],
|
||||
deps = [
|
||||
":cli",
|
||||
# TODO(josephperrott): Determine if this plugin is the best method for ensuring the hashbang
|
||||
# in both local and published use case.
|
||||
"@npm//rollup-plugin-hashbang",
|
||||
],
|
||||
)
|
||||
|
||||
ng_dev_rolled_up_generated_file(
|
||||
name = "build-worker",
|
||||
entry_point = "//dev-infra/release/build:build-worker.ts",
|
||||
deps = [
|
||||
"//dev-infra/release/build",
|
||||
],
|
||||
)
|
||||
|
|
|
@ -0,0 +1,316 @@
|
|||
'use strict';
|
||||
|
||||
function _interopDefault (ex) { return (ex && (typeof ex === 'object') && 'default' in ex) ? ex['default'] : ex; }
|
||||
|
||||
var tslib = require('tslib');
|
||||
var fs = require('fs');
|
||||
var path = require('path');
|
||||
var chalk = _interopDefault(require('chalk'));
|
||||
require('inquirer');
|
||||
require('inquirer-autocomplete-prompt');
|
||||
var shelljs = require('shelljs');
|
||||
|
||||
/**
|
||||
* @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
|
||||
*/
|
||||
/** Reexport of chalk colors for convenient access. */
|
||||
var red = chalk.red;
|
||||
var green = chalk.green;
|
||||
var yellow = chalk.yellow;
|
||||
var bold = chalk.bold;
|
||||
var blue = chalk.blue;
|
||||
/**
|
||||
* Supported levels for logging functions.
|
||||
*
|
||||
* Levels are mapped to numbers to represent a hierarchy of logging levels.
|
||||
*/
|
||||
var LOG_LEVELS;
|
||||
(function (LOG_LEVELS) {
|
||||
LOG_LEVELS[LOG_LEVELS["SILENT"] = 0] = "SILENT";
|
||||
LOG_LEVELS[LOG_LEVELS["ERROR"] = 1] = "ERROR";
|
||||
LOG_LEVELS[LOG_LEVELS["WARN"] = 2] = "WARN";
|
||||
LOG_LEVELS[LOG_LEVELS["LOG"] = 3] = "LOG";
|
||||
LOG_LEVELS[LOG_LEVELS["INFO"] = 4] = "INFO";
|
||||
LOG_LEVELS[LOG_LEVELS["DEBUG"] = 5] = "DEBUG";
|
||||
})(LOG_LEVELS || (LOG_LEVELS = {}));
|
||||
/** Default log level for the tool. */
|
||||
var DEFAULT_LOG_LEVEL = LOG_LEVELS.INFO;
|
||||
/** Write to the console for at INFO logging level */
|
||||
var info = buildLogLevelFunction(function () { return console.info; }, LOG_LEVELS.INFO);
|
||||
/** Write to the console for at ERROR logging level */
|
||||
var error = buildLogLevelFunction(function () { return console.error; }, LOG_LEVELS.ERROR);
|
||||
/** Write to the console for at DEBUG logging level */
|
||||
var debug = buildLogLevelFunction(function () { return console.debug; }, LOG_LEVELS.DEBUG);
|
||||
/** Write to the console for at LOG logging level */
|
||||
// tslint:disable-next-line: no-console
|
||||
var log = buildLogLevelFunction(function () { return console.log; }, LOG_LEVELS.LOG);
|
||||
/** Write to the console for at WARN logging level */
|
||||
var warn = buildLogLevelFunction(function () { return console.warn; }, LOG_LEVELS.WARN);
|
||||
/** Build an instance of a logging function for the provided level. */
|
||||
function buildLogLevelFunction(loadCommand, level) {
|
||||
/** Write to stdout for the LOG_LEVEL. */
|
||||
var loggingFunction = function () {
|
||||
var text = [];
|
||||
for (var _i = 0; _i < arguments.length; _i++) {
|
||||
text[_i] = arguments[_i];
|
||||
}
|
||||
runConsoleCommand.apply(void 0, tslib.__spread([loadCommand, level], text));
|
||||
};
|
||||
/** Start a group at the LOG_LEVEL, optionally starting it as collapsed. */
|
||||
loggingFunction.group = function (text, collapsed) {
|
||||
if (collapsed === void 0) { collapsed = false; }
|
||||
var command = collapsed ? console.groupCollapsed : console.group;
|
||||
runConsoleCommand(function () { return command; }, level, text);
|
||||
};
|
||||
/** End the group at the LOG_LEVEL. */
|
||||
loggingFunction.groupEnd = function () {
|
||||
runConsoleCommand(function () { return console.groupEnd; }, level);
|
||||
};
|
||||
return loggingFunction;
|
||||
}
|
||||
/**
|
||||
* Run the console command provided, if the environments logging level greater than the
|
||||
* provided logging level.
|
||||
*
|
||||
* The loadCommand takes in a function which is called to retrieve the console.* function
|
||||
* to allow for jasmine spies to still work in testing. Without this method of retrieval
|
||||
* the console.* function, the function is saved into the closure of the created logging
|
||||
* function before jasmine can spy.
|
||||
*/
|
||||
function runConsoleCommand(loadCommand, logLevel) {
|
||||
var text = [];
|
||||
for (var _i = 2; _i < arguments.length; _i++) {
|
||||
text[_i - 2] = arguments[_i];
|
||||
}
|
||||
if (getLogLevel() >= logLevel) {
|
||||
loadCommand().apply(void 0, tslib.__spread(text));
|
||||
}
|
||||
printToLogFile.apply(void 0, tslib.__spread([logLevel], text));
|
||||
}
|
||||
/**
|
||||
* Retrieve the log level from environment variables, if the value found
|
||||
* based on the LOG_LEVEL environment variable is undefined, return the default
|
||||
* logging level.
|
||||
*/
|
||||
function getLogLevel() {
|
||||
var logLevelEnvValue = (process.env["LOG_LEVEL"] || '').toUpperCase();
|
||||
var logLevel = LOG_LEVELS[logLevelEnvValue];
|
||||
if (logLevel === undefined) {
|
||||
return DEFAULT_LOG_LEVEL;
|
||||
}
|
||||
return logLevel;
|
||||
}
|
||||
/**
|
||||
* The number of columns used in the prepended log level information on each line of the logging
|
||||
* output file.
|
||||
*/
|
||||
var LOG_LEVEL_COLUMNS = 7;
|
||||
/** Write the provided text to the log file, prepending each line with the log level. */
|
||||
function printToLogFile(logLevel) {
|
||||
var text = [];
|
||||
for (var _i = 1; _i < arguments.length; _i++) {
|
||||
text[_i - 1] = arguments[_i];
|
||||
}
|
||||
var logLevelText = (LOG_LEVELS[logLevel] + ":").padEnd(LOG_LEVEL_COLUMNS);
|
||||
}
|
||||
|
||||
/**
|
||||
* @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.
|
||||
*
|
||||
* 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
|
||||
*/
|
||||
/** Whether ts-node has been installed and is available to ng-dev. */
|
||||
function isTsNodeAvailable() {
|
||||
try {
|
||||
require.resolve('ts-node');
|
||||
return true;
|
||||
}
|
||||
catch (_a) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @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
|
||||
*/
|
||||
/**
|
||||
* The filename expected for creating the ng-dev config, without the file
|
||||
* extension to allow either a typescript or javascript file to be used.
|
||||
*/
|
||||
var CONFIG_FILE_PATH = '.ng-dev/config';
|
||||
/** The configuration for ng-dev. */
|
||||
var cachedConfig = null;
|
||||
/**
|
||||
* Get the configuration from the file system, returning the already loaded
|
||||
* copy if it is defined.
|
||||
*/
|
||||
function getConfig() {
|
||||
// If the global config is not defined, load it from the file system.
|
||||
if (cachedConfig === null) {
|
||||
// The full path to the configuration file.
|
||||
var configPath = path.join(getRepoBaseDir(), CONFIG_FILE_PATH);
|
||||
// Read the configuration and validate it before caching it for the future.
|
||||
cachedConfig = validateCommonConfig(readConfigFile(configPath));
|
||||
}
|
||||
// Return a clone of the cached global config to ensure that a new instance of the config
|
||||
// is returned each time, preventing unexpected effects of modifications to the config object.
|
||||
return tslib.__assign({}, cachedConfig);
|
||||
}
|
||||
/** Validate the common configuration has been met for the ng-dev command. */
|
||||
function validateCommonConfig(config) {
|
||||
var errors = [];
|
||||
// Validate the github configuration.
|
||||
if (config.github === undefined) {
|
||||
errors.push("Github repository not configured. Set the \"github\" option.");
|
||||
}
|
||||
else {
|
||||
if (config.github.name === undefined) {
|
||||
errors.push("\"github.name\" is not defined");
|
||||
}
|
||||
if (config.github.owner === undefined) {
|
||||
errors.push("\"github.owner\" is not defined");
|
||||
}
|
||||
}
|
||||
assertNoErrors(errors);
|
||||
return config;
|
||||
}
|
||||
/**
|
||||
* Resolves and reads the specified configuration file, optionally returning an empty object if the
|
||||
* configuration file cannot be read.
|
||||
*/
|
||||
function readConfigFile(configPath, returnEmptyObjectOnError) {
|
||||
if (returnEmptyObjectOnError === void 0) { returnEmptyObjectOnError = false; }
|
||||
// If the the `.ts` extension has not been set up already, and a TypeScript based
|
||||
// version of the given configuration seems to exist, set up `ts-node` if available.
|
||||
if (require.extensions['.ts'] === undefined && fs.existsSync(configPath + ".ts") &&
|
||||
isTsNodeAvailable()) {
|
||||
// Ensure the module target is set to `commonjs`. This is necessary because the
|
||||
// dev-infra tool runs in NodeJS which does not support ES modules by default.
|
||||
// Additionally, set the `dir` option to the directory that contains the configuration
|
||||
// file. This allows for custom compiler options (such as `--strict`).
|
||||
require('ts-node').register({ dir: path.dirname(configPath), transpileOnly: true, compilerOptions: { module: 'commonjs' } });
|
||||
}
|
||||
try {
|
||||
return require(configPath);
|
||||
}
|
||||
catch (e) {
|
||||
if (returnEmptyObjectOnError) {
|
||||
debug("Could not read configuration file at " + configPath + ", returning empty object instead.");
|
||||
debug(e);
|
||||
return {};
|
||||
}
|
||||
error("Could not read configuration file at " + configPath + ".");
|
||||
error(e);
|
||||
process.exit(1);
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Asserts the provided array of error messages is empty. If any errors are in the array,
|
||||
* logs the errors and exit the process as a failure.
|
||||
*/
|
||||
function assertNoErrors(errors) {
|
||||
var e_1, _a;
|
||||
if (errors.length == 0) {
|
||||
return;
|
||||
}
|
||||
error("Errors discovered while loading configuration file:");
|
||||
try {
|
||||
for (var errors_1 = tslib.__values(errors), errors_1_1 = errors_1.next(); !errors_1_1.done; errors_1_1 = errors_1.next()) {
|
||||
var err = errors_1_1.value;
|
||||
error(" - " + err);
|
||||
}
|
||||
}
|
||||
catch (e_1_1) { e_1 = { error: e_1_1 }; }
|
||||
finally {
|
||||
try {
|
||||
if (errors_1_1 && !errors_1_1.done && (_a = errors_1.return)) _a.call(errors_1);
|
||||
}
|
||||
finally { if (e_1) throw e_1.error; }
|
||||
}
|
||||
process.exit(1);
|
||||
}
|
||||
/** Gets the path of the directory for the repository base. */
|
||||
function getRepoBaseDir() {
|
||||
var baseRepoDir = exec("git rev-parse --show-toplevel");
|
||||
if (baseRepoDir.code) {
|
||||
throw Error("Unable to find the path to the base directory of the repository.\n" +
|
||||
"Was the command run from inside of the repo?\n\n" +
|
||||
("ERROR:\n " + baseRepoDir.stderr));
|
||||
}
|
||||
return baseRepoDir.trim();
|
||||
}
|
||||
|
||||
/**
|
||||
* @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
|
||||
*/
|
||||
/** Retrieve and validate the config as `ReleaseConfig`. */
|
||||
function getReleaseConfig(config = getConfig()) {
|
||||
var _a, _b, _c;
|
||||
// List of errors encountered validating the config.
|
||||
const errors = [];
|
||||
if (config.release === undefined) {
|
||||
errors.push(`No configuration defined for "release"`);
|
||||
}
|
||||
if (((_a = config.release) === null || _a === void 0 ? void 0 : _a.npmPackages) === undefined) {
|
||||
errors.push(`No "npmPackages" configured for releasing.`);
|
||||
}
|
||||
if (((_b = config.release) === null || _b === void 0 ? void 0 : _b.buildPackages) === undefined) {
|
||||
errors.push(`No "buildPackages" function configured for releasing.`);
|
||||
}
|
||||
if (((_c = config.release) === null || _c === void 0 ? void 0 : _c.generateReleaseNotesForHead) === undefined) {
|
||||
errors.push(`No "generateReleaseNotesForHead" function configured for releasing.`);
|
||||
}
|
||||
assertNoErrors(errors);
|
||||
return config.release;
|
||||
}
|
||||
|
||||
/**
|
||||
* @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
|
||||
*/
|
||||
// Start the release package building.
|
||||
main();
|
||||
/** Main function for building the release packages. */
|
||||
function main() {
|
||||
return tslib.__awaiter(this, void 0, void 0, function* () {
|
||||
if (process.send === undefined) {
|
||||
throw Error('This script needs to be invoked as a NodeJS worker.');
|
||||
}
|
||||
const config = getReleaseConfig();
|
||||
const builtPackages = yield config.buildPackages();
|
||||
// Transfer the built packages back to the parent process.
|
||||
process.send(builtPackages);
|
||||
});
|
||||
}
|
|
@ -3,7 +3,32 @@
|
|||
# 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
|
||||
|
||||
# File is currently empty but serves as indicator for `rules_nodejs` and instructs it to
|
||||
# preserve the content output in the NPM install workspace. This allows consumers to use
|
||||
# rules and targets from within Bazel. e.g. by using `@npm//@angular/dev-infra-private/<..>`.
|
||||
load("@build_bazel_rules_nodejs//:index.bzl", "generated_file_test")
|
||||
load("@npm//@bazel/rollup:index.bzl", "rollup_bundle")
|
||||
|
||||
# This file continues to serve as indicator for `rules_nodejs` and instructs it preserve the
|
||||
# content output in the NPM install workspace. This allows consumers to use rules and targets from
|
||||
# within Bazel. e.g. by using `@npm//@angular/dev-infra-private/<..>`.
|
||||
# See: https://github.com/bazelbuild/rules_nodejs/commit/4f508b1a0be1f5444e9c13b0439e649449792fef.
|
||||
|
||||
def ng_dev_rolled_up_generated_file(name, entry_point, deps = [], rollup_args = []):
|
||||
"""Rollup and generated file test macro.
|
||||
|
||||
This provides a single macro to create a rollup bundled script and a generated file test for the
|
||||
created script to ensure it stays up to date in the repository.
|
||||
"""
|
||||
rollup_bundle(
|
||||
name = "%s_bundle" % name,
|
||||
args = rollup_args,
|
||||
entry_point = entry_point,
|
||||
format = "cjs",
|
||||
silent = True,
|
||||
sourcemap = "false",
|
||||
deps = deps,
|
||||
)
|
||||
|
||||
generated_file_test(
|
||||
name = name,
|
||||
src = "%s.js" % name,
|
||||
generated = "%s_bundle" % name,
|
||||
)
|
||||
|
|
|
@ -1,6 +1,10 @@
|
|||
load("@npm//@bazel/typescript:index.bzl", "ts_library")
|
||||
load("//tools:defaults.bzl", "jasmine_node_test")
|
||||
|
||||
exports_files([
|
||||
"build-worker.ts",
|
||||
])
|
||||
|
||||
ts_library(
|
||||
name = "build",
|
||||
srcs = glob(
|
||||
|
|
Loading…
Reference in New Issue