angular-docs-cn/scripts/build/package-builder.js
Paul Gschwendtner 7fb8527e1e refactor(dev-infra): remove invoke bazel clean command from release tool (#42101)
Currently the ng-dev release tool always run `bazel clean` before
calling the configured build release function. The clean is necessary
to ensure the release output is actually built; and not restored
from previous builds which could have different bazel workspace
status variables (which provide the NPM package version).

Instead of doing this as part of the release tool, the
actual script running to build the release output should
run the `bazel clean`. The release tool does not intend to
know about details on how the release output is built. This
is necessary because the build setup could vary between version
branches (especially for older ones; such as LTS version branches).

PR Close #42101
2021-05-14 21:06:09 +00:00

156 lines
6.0 KiB
JavaScript

/**
* @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
*/
'use strict';
// Build the dist/packages-dist directory in the same fashion as the legacy
// /build.sh script, by building the npm packages with Bazel and copying files.
// This is needed for scripts and tests which are not updated to the Bazel output
// layout (which always matches the input layout).
// Do not add new dependencies on this script, instead adapt scripts to use the
// new layout, and write new tests as Bazel targets.
//
// Ideally integration tests should run under bazel, and just consume the npm
// packages via `deps`. Until that works, we manually build the npm packages and then
// copy the results to the appropriate `dist` location.
// NOTE: this script may be run from any directory. The actions should be written to be independent
// of the current working directory. For example, use absolute paths wherever possible, and pass a
// working directory to tools like `yarn`.
const {execSync} = require('child_process');
const {resolve, relative} = require('path');
const {chmod, cp, mkdir, rm, set, test} = require('shelljs');
set('-e');
/** @type {string} The absolute path to the project root directory. */
const baseDir = resolve(`${__dirname}/../..`);
/** @type {string} The command to use for running bazel. */
const bazelCmd = `yarn --cwd "${baseDir}" --silent bazel`;
/** @type {string} The absolute path to the bazel-bin directory. */
const bazelBin = exec(`${bazelCmd} info bazel-bin`, true);
/**
* @type {string}
* The relative path to the entry script (i.e. the one loaded when the Node.js process launched).
* It is relative to `baseDir`.
*/
const scriptPath = relative(baseDir, require.main.filename);
module.exports = {
baseDir,
bazelBin,
bazelCmd,
buildTargetPackages,
exec,
scriptPath,
};
/**
* Build the Angular packages.
*
* @param {string} destDir Path to the output directory into which we copy the npm packages.
* This path should either be absolute or relative to the project root.
* @param {boolean} enableIvy True, if Ivy should be used.
* @param {string} description Human-readable description of the build.
* @param {boolean?} isRelease True, if the build should be stamped for a release.
* @returns {Array<{name: string, outputPath: string}} A list of packages built.
*/
function buildTargetPackages(destDir, enableIvy, description, isRelease = false) {
console.info('##################################');
console.info(`${scriptPath}:`);
console.info(' Building @angular/* npm packages');
console.info(` Mode: ${description}`);
console.info('##################################');
/** The list of packages which were built. */
const builtPackages = [];
// List of targets to build, e.g. core, common, compiler, etc. Note that we want to also remove
// all carriage return (`\r`) characters form the query output, because otherwise the carriage
// return is part of the bazel target name and bazel will complain.
const getTargetsCmd = `${
bazelCmd} query --output=label "attr('tags', '\\[.*release-with-framework.*\\]', //packages/...) intersect kind('ng_package|pkg_npm', //packages/...)"`;
const targets = exec(getTargetsCmd, true).split(/\r?\n/);
// If we are in release mode, run `bazel clean` to ensure the execroot and action cache
// are not populated. This is necessary because targets using `npm_package` rely on
// workspace status variables for the package version. Such NPM package targets are not
// rebuilt if only the workspace status variables change. This could result in accidental
// re-use of previously built package output with a different `version` in the `package.json`.
if (isRelease) {
console.info('Building in release mode. Resetting the Bazel execroot and action cache..');
exec(`${bazelCmd} clean`);
}
// Use either `--config=snapshot` or `--config=release` so that builds are created with the
// correct embedded version info.
exec(`${bazelCmd} build --config=${isRelease ? 'release' : 'snapshot'} --config=${
enableIvy ? 'ivy' : 'view-engine'} ${targets.join(' ')}`);
// Create the output directory.
const absDestDir = resolve(baseDir, destDir);
if (!test('-d', absDestDir)) {
mkdir('-p', absDestDir);
}
targets.forEach(target => {
const pkg = target.replace(/\/\/packages\/(.*):npm_package/, '$1');
// Skip any that don't have an "npm_package" target.
const srcDir = `${bazelBin}/packages/${pkg}/npm_package`;
const destDir = `${absDestDir}/${pkg}`;
if (test('-d', srcDir)) {
console.info(`# Copy artifacts to ${destDir}`);
rm('-rf', destDir);
cp('-R', srcDir, destDir);
chmod('-R', 'u+w', destDir);
builtPackages.push({name: `@angular/${pkg}`, outputPath: destDir});
}
});
console.info('');
return builtPackages;
}
/**
* Execute a command synchronously.
*
* By default, the current process' stdout is used (and thus the output is not captured and returned
* to the caller). This is necessary for showing colors and modifying already printed output, for
* example to show progress.
*
* If the caller requests the output (via `captureStdout: true`), the command is run without
* printing anything to stdout and then (once the command has completed) the whole output is printed
* to stdout and returned to the caller.
*
* @param {string} cmd The command to run.
* @param {boolean} [captureStdout=false] Whether to return the output of the command.
* @param {import('child_process').ExecSyncOptions} [options] The options to pass to `execSync()`.
* @return {string | undefined} The captured stdout output if `captureStdout: true` or `undefined`.
*/
function exec(cmd, captureStdout, options) {
const output = execSync(cmd, {
stdio: [
/* stdin */ 'inherit',
/* stdout */ captureStdout ? 'pipe' : 'inherit',
/* stderr */ 'inherit',
],
...options,
});
if (captureStdout) {
process.stdout.write(output);
return output.toString().trim();
}
}