build: convert release package build scripts to typescript (#46456)

Follow-up to: cce395a928.

PR Close #46456
This commit is contained in:
Paul Gschwendtner
2022-06-22 16:13:15 +00:00
committed by Andrew Kushnir
parent 2d713f5847
commit d248d83c17
25 changed files with 258 additions and 324 deletions
+2 -2
View File
@@ -53,8 +53,8 @@ build:release --workspace_status_command="yarn -s ng-dev release build-env-stamp
build:release --stamp
# Snapshots should also be stamped with version control information.
build:snapshot --workspace_status_command="yarn -s ng-dev release build-env-stamp --mode=snapshot"
build:snapshot --stamp
build:snapshot-build --workspace_status_command="yarn -s ng-dev release build-env-stamp --mode=snapshot"
build:snapshot-build --stamp
###############################
# Output #
+1 -1
View File
@@ -442,7 +442,7 @@ jobs:
steps:
- custom_attach_workspace
- init_environment
- run: node scripts/build/build-packages-dist.js
- run: yarn build
# Save the npm packages from //packages/... for other workflow jobs to read
- persist_to_workspace:
+4 -7
View File
@@ -1,5 +1,4 @@
import {ReleaseConfig} from '@angular/dev-infra-private/ng-dev';
import {join} from 'path';
/** Configuration for the `ng-dev release` command. */
export const release: ReleaseConfig = {
@@ -24,12 +23,10 @@ export const release: ReleaseConfig = {
{name: '@angular/upgrade'},
],
buildPackages: async () => {
// The buildTargetPackages function is loaded at runtime as the loading the script causes an
// invocation of bazel.
const packageBuilder = await import('../scripts/build/package-builder.js');
return packageBuilder.default.buildTargetPackages(
'dist/release-output', 'Release', /* isRelease */ true);
// The buildTargetPackages function is loaded at runtime as the loading the script
// causes an invocation of Bazel.
const {performNpmReleaseBuild} = await import('../scripts/build/package-builder.mjs');
return performNpmReleaseBuild();
},
releaseNotes: {
hiddenScopes: ['aio', 'bazel', 'dev-infra', 'docs-infra', 'zone.js', 'devtools'],
+4 -5
View File
@@ -16,8 +16,7 @@ const ANGULAR_ROOT_DIR = path.resolve(__dirname, '../../..');
const ANGULAR_DIST_PACKAGES_DIR = path.join(ANGULAR_ROOT_DIR, 'dist/packages-dist');
const AIMWA_DIST_PACKAGES_DIR = path.join(ANGULAR_ROOT_DIR, 'dist/angular-in-memory-web-api-dist');
const ZONEJS_DIST_PACKAGES_DIR = path.join(ANGULAR_ROOT_DIR, 'dist/zone.js-dist');
const DIST_PACKAGES_BUILD_SCRIPT = path.join(ANGULAR_ROOT_DIR, 'scripts/build/build-packages-dist.js');
const DIST_PACKAGES_BUILD_CMD = `"${process.execPath}" "${DIST_PACKAGES_BUILD_SCRIPT}"`;
const DIST_PACKAGES_BUILD_CMD = 'yarn -s build';
/**
* A tool that can install Angular/Zone.js dependencies for a project from NPM or from the
@@ -181,14 +180,14 @@ class NgPackagesInstaller {
const canBuild = process.platform !== 'win32';
if (canBuild) {
this._log(`Building the local packages with: ${DIST_PACKAGES_BUILD_SCRIPT}`);
shelljs.exec(DIST_PACKAGES_BUILD_CMD);
this._log(`Building the local packages with: ${DIST_PACKAGES_BUILD_CMD} in ${ANGULAR_ROOT_DIR}`);
shelljs.exec(DIST_PACKAGES_BUILD_CMD, {cwd: ANGULAR_ROOT_DIR});
} else {
this._warn([
'Automatically building the local Angular/angular-in-memory-web-api/zone.js packages is currently not ' +
'supported on Windows.',
`Please, ensure '${ANGULAR_DIST_PACKAGES_DIR}', '${AIMWA_DIST_PACKAGES_DIR}' and ` +
`'${ZONEJS_DIST_PACKAGES_DIR}' exist and are up-to-date (e.g. by running '${DIST_PACKAGES_BUILD_SCRIPT}' ` +
`'${ZONEJS_DIST_PACKAGES_DIR}' exist and are up-to-date (e.g. by running "${DIST_PACKAGES_BUILD_CMD}" ` +
'in Git Bash for Windows, Windows Subsystem for Linux or a Linux docker container or VM).',
'',
'Proceeding anyway...',
@@ -305,25 +305,20 @@ describe('NgPackagesInstaller', () => {
};
it('should build the local packages, when not on Windows', () => {
const buildScript = path.join(ngRootDir, 'scripts/build/build-packages-dist.js');
const buildCmd = `"${process.execPath}" "${buildScript}"`;
const buildCmd = 'yarn -s build';
buildDistPackagesOnPlatform('linux');
expect(shelljs.exec).toHaveBeenCalledWith(buildCmd);
expect(shelljs.exec).toHaveBeenCalledWith(buildCmd, {cwd: ngRootDir});
shelljs.exec.calls.reset();
buildDistPackagesOnPlatform('darwin');
expect(shelljs.exec).toHaveBeenCalledWith(buildCmd);
expect(shelljs.exec).toHaveBeenCalledWith(buildCmd, {cwd: ngRootDir});
shelljs.exec.calls.reset();
buildDistPackagesOnPlatform('anythingButWindows :(');
expect(shelljs.exec).toHaveBeenCalledWith(buildCmd);
// Ensure that the script does actually exist (e.g. it was not renamed/moved).
fs.existsSync.and.callThrough();
expect(fs.existsSync(buildScript)).toBe(true);
expect(shelljs.exec).toHaveBeenCalledWith(buildCmd, {cwd: ngRootDir});
});
it('should print a warning, when on Windows', () => {
+1 -1
View File
@@ -283,7 +283,7 @@ pkg_web(
"@npm//:node_modules/tslib/tslib.js",
],
# Currently, ibazel doesn't allow passing in flags to bazel run.
# This means we are not able to use --config snapshot
# This means we are not able to use --config snapshot-build
# to access the current commit SHA.
# Since we still want to be able to use ibazel to speed up
# local development, we supply an empty string for the SHA substitution.
+1 -1
View File
@@ -297,7 +297,7 @@ The `msys64` library and associated tools (like `mkdir`) are required to build A
Make sure you have `C:\msys64\usr\bin` in the "system" `PATH` rather than the "user" `PATH`.
After that, a `git clean -xfd`, `yarn`, and `node scripts\build\build-packages-dist.js` should resolve this issue.
After that, a `git clean -xfd`, `yarn`, and `yarn build` should resolve this issue.
### Xcode
+1 -2
View File
@@ -4,8 +4,7 @@ Currently all changes to Ivy are validated against the test suite of the
`angular/components` repository. In order to debug the `components-repo-unit-tests` CI
job, the following steps can be used:
1\) Build the Ivy package output by running `node ./scripts/build/build-packages-dist.js` in
the `angular/angular` repo.
1\) Build the Ivy package output by running `yarn build` in the `angular/angular` repo.
2\) Clone the `angular/components` repository if not done yet ([quick link to repo](https://github.com/angular/components)).
+2 -2
View File
@@ -67,7 +67,7 @@ yarn install
To build Angular run:
```shell
node ./scripts/build/build-packages-dist.js
yarn build
```
* Results are put in the `dist/packages-dist` folder.
@@ -197,7 +197,7 @@ c. Some package managers (such as `pnpm` or `yarn pnp`) might not work correctly
### Publishing to GitHub Repos
You can also manually publish `*-builds` snapshots just like our CircleCI build does for upstream
builds. Before being able to publish the packages, you need to build them locally by running the
`./scripts/build/build-packages-dist.js` script.
`yarn build` command.
First time, you need to create the GitHub repositories:
+1 -1
View File
@@ -4,7 +4,7 @@ This directory contains end-to-end tests for Angular. Each directory is a self-c
that exactly mimics how a user might expect Angular to work, so they allow high-fidelity
reproductions of real-world issues.
For this to work, we first build the Angular distribution via `./scripts/build/build-packages-dist.js`, then
For this to work, we first build the Angular distribution via `yarn build`, then
install the distribution into each app.
To test Angular CLI applications, we use the `cli-hello-world-*` integration tests.
@@ -11,7 +11,8 @@ set -u -e -o pipefail
cd "$(dirname "$0")"
node $(pwd)/../../scripts/build/build-packages-dist.js
# Go to the project directory and build the release packages.
(cd $(pwd)/../../ && yarn build)
# Workaround https://github.com/yarnpkg/yarn/issues/2165
# Yarn will cache file://dist URIs and not update Angular code
@@ -11,7 +11,8 @@ set -u -e -o pipefail
cd "$(dirname "$0")"
node $(pwd)/../../scripts/build/build-packages-dist.js
# Go to the project directory and build the release packages.
(cd $(pwd)/../../ && yarn build)
# Workaround https://github.com/yarnpkg/yarn/issues/2165
# Yarn will cache file://dist URIs and not update Angular code
+2 -1
View File
@@ -11,7 +11,8 @@ set -u -e -o pipefail
cd "$(dirname "$0")"
node $(pwd)/../../scripts/build/build-packages-dist.js
# Go to the project directory and build the release packages.
(cd $(pwd)/../../ && yarn build)
# Workaround https://github.com/yarnpkg/yarn/issues/2165
# Yarn will cache file://dist URIs and not update Angular code
+2 -1
View File
@@ -11,7 +11,8 @@ set -u -e -o pipefail
cd "$(dirname "$0")"
node $(pwd)/../../scripts/build/build-packages-dist.js
# Go to the project directory and build the release packages.
(cd $(pwd)/../../ && yarn build)
# Workaround https://github.com/yarnpkg/yarn/issues/2165
# Yarn will cache file://dist URIs and not update Angular code
+1 -1
View File
@@ -20,7 +20,7 @@ echo ${RUN_TESTS}
# Build the packages-dist directory.
# This should be fast on incremental re-build.
node ../scripts/build/build-packages-dist.js
yarn build
# Workaround https://github.com/yarnpkg/yarn/issues/2165
# Yarn will cache file://dist URIs and not update Angular code
+5 -4
View File
@@ -25,6 +25,7 @@
"postinstall": "node scripts/webdriver-manager-update.js && node --preserve-symlinks --preserve-symlinks-main ./tools/postinstall-patches.js",
"prepare": "husky install",
"ng-dev": "ts-node --esm --project .ng-dev/tsconfig.json node_modules/@angular/dev-infra-private/ng-dev/bundles/cli.mjs",
"build": "ts-node --esm --project scripts/tsconfig.json scripts/build/build-packages-dist.mts",
"test": "bazelisk test",
"test:ci": "bazelisk test -- //... -//devtools/... -//aio/...",
"test-tsec": "bazelisk test //... --build_tag_filters=tsec --test_tag_filters=tsec",
@@ -36,11 +37,11 @@
"symbol-extractor:update": "node tools/symbol-extractor/run_all_symbols_extractor_tests.js accept",
"ts-circular-deps:check": "yarn -s ng-dev ts-circular-deps check --config ./packages/circular-deps-test.conf.js",
"ts-circular-deps:approve": "yarn -s ng-dev ts-circular-deps approve --config ./packages/circular-deps-test.conf.js",
"check-tooling-setup": "yarn tsc --project .ng-dev/tsconfig.json",
"check-tooling-setup": "yarn tsc --project .ng-dev/tsconfig.json && yarn tsc --project scripts/tsconfig.json",
"devtools:devserver": "ibazel run //devtools/src:devserver",
"devtools:build:chrome": "bazelisk build --config snapshot --//devtools/projects/shell-browser/src:flag_browser=chrome -- devtools/projects/shell-browser/src:prodapp",
"devtools:build:firefox": "bazelisk build --config snapshot --//devtools/projects/shell-browser/src:flag_browser=firefox -- devtools/projects/shell-browser/src:prodapp",
"devtools:test": "bazelisk test --config snapshot --//devtools/projects/shell-browser/src:flag_browser=chrome -- //devtools/..."
"devtools:build:chrome": "bazelisk build --config snapshot-build --//devtools/projects/shell-browser/src:flag_browser=chrome -- devtools/projects/shell-browser/src:prodapp",
"devtools:build:firefox": "bazelisk build --config snapshot-build --//devtools/projects/shell-browser/src:flag_browser=firefox -- devtools/projects/shell-browser/src:prodapp",
"devtools:test": "bazelisk test --config snapshot-build --//devtools/projects/shell-browser/src:flag_browser=chrome -- //devtools/..."
},
"// 1": "dependencies are used locally and by bazel",
"dependencies": {
-27
View File
@@ -1,27 +0,0 @@
#!/usr/bin/env node
/**
* @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 build script used to be here but has been moved to `scripts/build/` in PR
// https://github.com/angular/angular/pull/35780. This is a temporary placeholder script for people
// that are not aware of the change and expect to find the script here.
//
// TODO: This script can be removed early May 2020.
'use strict';
const {red} = require('chalk');
const {relative, resolve} = require('path');
const absoluteScriptPath = resolve(`${__dirname}/build/build-packages-dist.js`);
const relativeScriptPath = relative(process.cwd(), absoluteScriptPath);
console.error(red('ERROR: The build script has been moved to \'scripts/build/\'.'));
console.error(red(` Run: node ${relativeScriptPath}`));
process.exit(1);
-54
View File
@@ -1,54 +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
*/
'use strict';
const {resolve} = require('path');
const {chmod, cp, mkdir, rm, test} = require('shelljs');
const {baseDir, bazelBin, bazelCmd, exec, scriptPath} = require('./package-builder');
module.exports = {
buildAngularInMemoryWebApiPackage,
};
/**
* Build the `angular-in-memory-web-api` npm package and copy it to `destDir` for other
* scripts/tests to use.
*
* NOTE: The `angular-in-memory-web-api` package is not built as part of `package-builder`'s
* `buildTargetPackages()` nor is it copied into the same directory as the Angular packages
* (e.g. `dist/packages-dist/`) despite its source's being inside `packages/`, because it is
* not published to npm under the `@angular` scope (as happens for the rest of the packages).
*
* @param {string} destDir Path to the output directory into which we copy the npm package.
* This path should either be absolute or relative to the project root.
*/
function buildAngularInMemoryWebApiPackage(destDir) {
console.info('##############################');
console.info(`${scriptPath}:`);
console.info(' Building angular-in-memory-web-api npm package');
console.info('##############################');
exec(`${bazelCmd} build //packages/misc/angular-in-memory-web-api:npm_package`);
// Create the output directory.
const absDestDir = resolve(baseDir, destDir);
if (!test('-d', absDestDir)) {
mkdir('-p', absDestDir);
}
const buildOutputDir = `${bazelBin}/packages/misc/angular-in-memory-web-api/npm_package`;
const distTargetDir = `${absDestDir}/angular-in-memory-web-api`;
console.info(`# Copy artifacts to ${distTargetDir}`);
rm('-rf', distTargetDir);
cp('-R', buildOutputDir, distTargetDir);
chmod('-R', 'u+w', distTargetDir);
console.info('');
}
@@ -0,0 +1,50 @@
/**
* @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 {join} from 'path';
import sh from 'shelljs';
import {projectDir, bazelCmd, exec} from './package-builder.mjs';
/**
* Build the `angular-in-memory-web-api` npm package and copies it into the release
* distribution directory.
*
* NOTE: The `angular-in-memory-web-api` package is not built as part of `package-builder`'s
* `buildTargetPackages()` nor is it copied into the same directory as the Angular packages (e.g.
* `dist/packages-dist/`) despite its source's being inside `packages/`, because it is not
* published to npm under the `@angular` scope (as happens for the rest of the packages).
*
* @param {string} destDir Path to the output directory into which we copy the npm package.
* This path should either be absolute or relative to the project root.
*/
export function buildAngularInMemoryWebApiPackage(destDir: string): void {
console.info('##############################');
console.info(' Building angular-in-memory-web-api npm package');
console.info('##############################');
exec(`${bazelCmd} build //packages/misc/angular-in-memory-web-api:npm_package`);
// Create the output directory.
if (!sh.test('-d', destDir)) {
sh.mkdir('-p', destDir);
}
const bazelBinPath = exec(`${bazelCmd} info bazel-bin`, true);
// Copy artifacts to `destDir`, so they can be easier persisted on CI and used by non-bazel
// scripts/tests.
const buildOutputDir = join(bazelBinPath, 'packages/misc/angular-in-memory-web-api/npm_package');
const distTargetDir = join(destDir, 'angular-in-memory-web-api');
console.info(`# Copy npm_package artifacts to ${distTargetDir}`);
sh.rm('-rf', distTargetDir);
sh.cp('-R', buildOutputDir, distTargetDir);
sh.chmod('-R', 'u+w', distTargetDir);
}
@@ -1,4 +1,5 @@
#!/usr/bin/env node
/**
* @license
* Copyright Google LLC All Rights Reserved.
@@ -7,15 +8,13 @@
* found in the LICENSE file at https://angular.io/license
*/
'use strict';
const {buildAngularInMemoryWebApiPackage} = require('./angular-in-memory-web-api');
const {buildTargetPackages} = require('./package-builder');
const {buildZoneJsPackage} = require('./zone-js-builder');
import {buildAngularInMemoryWebApiPackage} from './angular-in-memory-web-api.mjs';
import {performDefaultSnapshotBuild} from './package-builder.mjs';
import {buildZoneJsPackage} from './zone-js-builder.mjs';
// Build the legacy (view engine) npm packages into `dist/packages-dist/`.
buildTargetPackages('dist/packages-dist', 'Production');
performDefaultSnapshotBuild();
// Build the `angular-in-memory-web-api` npm package into `dist/angular-in-memory-web-api-dist/`,
// because it might be needed by other scripts/targets.
-18
View File
@@ -1,18 +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
*/
/**
* 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 {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.
*/
export declare function buildTargetPackages(destDir, description, isRelease: boolean): {name: string, outputPath: string}[];
-153
View File
@@ -1,153 +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
*/
'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 = process.env.BAZEL ?? `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 {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, 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'} ${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();
}
}
+135
View File
@@ -0,0 +1,135 @@
/**
* @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 {execSync} from 'child_process';
import {join, dirname} from 'path';
import {BuiltPackage} from '@angular/dev-infra-private/ng-dev';
import {fileURLToPath} from 'url';
import sh from 'shelljs';
// ShellJS should exit if a command fails.
sh.set('-e');
/** Path to the project directory. */
export const projectDir = join(dirname(fileURLToPath(import.meta.url)), '../..');
/** Command that runs Bazel. */
export const bazelCmd = process.env.BAZEL || `yarn -s bazel`;
/** Name of the Bazel tag that will be used to find release package targets. */
const releaseTargetTag = 'release-with-framework';
/** Command that queries Bazel for all release package targets. */
const queryPackagesCmd =
`${bazelCmd} query --output=label "attr('tags', '\\[.*${releaseTargetTag}.*\\]', //packages/...) ` +
`intersect kind('ng_package|pkg_npm', //packages/...)"`;
/** Path for the default distribution output directory. */
const defaultDistPath = join(projectDir, 'dist/packages-dist');
/** Builds the release packages for NPM. */
export function performNpmReleaseBuild(): BuiltPackage[] {
return buildReleasePackages(defaultDistPath, /* isSnapshotBuild */ false);
}
/**
* Builds the release packages as snapshot build. This means that the current
* Git HEAD SHA is included in the version (for easier debugging and back tracing).
*/
export function performDefaultSnapshotBuild(): BuiltPackage[] {
return buildReleasePackages(defaultDistPath, /* isSnapshotBuild */ true);
}
/**
* Builds the release packages with the given compile mode and copies
* the package output into the given directory.
*/
function buildReleasePackages(distPath: string, isSnapshotBuild: boolean): BuiltPackage[] {
console.info('######################################');
console.info(' Building release packages...');
console.info('######################################');
// List of targets to build. e.g. "packages/core:npm_package", or "packages/forms:npm_package".
const targets = exec(queryPackagesCmd, true).split(/\r?\n/);
const packageNames = getPackageNamesOfTargets(targets);
const bazelBinPath = exec(`${bazelCmd} info bazel-bin`, true);
const getBazelOutputPath = (pkgName: string) => join(bazelBinPath, 'packages', pkgName, 'npm_package');
const getDistPath = (pkgName: string) => join(distPath, pkgName);
// Build with "--config=release" or `--config=snapshot-build` so that Bazel
// runs the workspace stamping script. The stamping script ensures that the
// version placeholder is populated in the release output.
const stampConfigArg = `--config=${isSnapshotBuild ? 'snapshot-build' : 'release'}`;
// Walk through each release package and clear previous "npm_package" outputs. This is
// a workaround for: https://github.com/bazelbuild/rules_nodejs/issues/1219. We need to
// do this to ensure that the version placeholders are properly populated.
packageNames.forEach((pkgName) => {
const outputPath = getBazelOutputPath(pkgName);
if (sh.test('-d', outputPath)) {
sh.chmod('-R', 'u+w', outputPath);
sh.rm('-rf', outputPath);
}
});
exec(`${bazelCmd} build ${stampConfigArg} ${targets.join(' ')}`);
// Delete the distribution directory so that the output is guaranteed to be clean. Re-create
// the empty directory so that we can copy the release packages into it later.
sh.rm('-rf', distPath);
sh.mkdir('-p', distPath);
// Copy the package output into the specified distribution folder.
packageNames.forEach((pkgName) => {
const outputPath = getBazelOutputPath(pkgName);
const targetFolder = getDistPath(pkgName);
console.info(`> Copying package output to "${targetFolder}"`);
sh.cp('-R', outputPath, targetFolder);
sh.chmod('-R', 'u+w', targetFolder);
});
return packageNames.map((pkg) => {
return {
name: `@angular/${pkg}`,
outputPath: getDistPath(pkg),
};
});
}
/**
* Gets the package names of the specified Bazel targets.
* e.g. //packages/core:npm_package => core
*/
function getPackageNamesOfTargets(targets: string[]): string[] {
return targets.map((targetName) => {
const matches = targetName.match(/\/\/packages\/(.*):npm_package/);
if (matches === null) {
throw Error(
`Found Bazel target with "${releaseTargetTag}" tag, but could not ` +
`determine release output name: ${targetName}`
);
}
return matches[1];
});
}
/** Executes the given command in the project directory. */
export function exec(command: string): void;
/** Executes the given command in the project directory and returns its stdout. */
export function exec(command: string, captureStdout: true): string;
export function exec(command: string, captureStdout?: true) {
const stdout = execSync(command, {
cwd: projectDir,
stdio: ['inherit', captureStdout ? 'pipe' : 'inherit', 'inherit'],
});
if (captureStdout) {
process.stdout.write(stdout);
return stdout.toString().trim();
}
}
@@ -6,17 +6,10 @@
* found in the LICENSE file at https://angular.io/license
*/
'use strict';
import {join} from 'path';
import sh from 'shelljs';
const {resolve} = require('path');
const {chmod, cp, mkdir, mv, rm, test} = require('shelljs');
const zonePackageJson = require('../../packages/zone.js/package.json');
const {baseDir, bazelBin, bazelCmd, exec, scriptPath} = require('./package-builder');
module.exports = {
buildZoneJsPackage,
};
import {projectDir, bazelCmd, exec} from './package-builder.mjs';
/**
* Build the `zone.js` npm package into `dist/bin/packages/zone.js/npm_package/` and copy it to
@@ -30,36 +23,36 @@ module.exports = {
* @param {string} destDir Path to the output directory into which we copy the npm package.
* This path should either be absolute or relative to the project root.
*/
function buildZoneJsPackage(destDir) {
export function buildZoneJsPackage(destDir: string): void {
console.info('##############################');
console.info(`${scriptPath}:`);
console.info(' Building zone.js npm package');
console.info('##############################');
exec(`${bazelCmd} run //packages/zone.js:npm_package.pack`);
// Create the output directory.
const absDestDir = resolve(baseDir, destDir);
if (!test('-d', absDestDir)) {
mkdir('-p', absDestDir);
if (!sh.test('-d', destDir)) {
sh.mkdir('-p', destDir);
}
const bazelBinPath = exec(`${bazelCmd} info bazel-bin`, true);
// Copy artifacts to `destDir`, so they can be easier persisted on CI and used by non-bazel
// scripts/tests.
const buildOutputDir = `${bazelBin}/packages/zone.js/npm_package`;
const distTargetDir = `${absDestDir}/zone.js`;
const buildOutputDir = join(bazelBinPath, 'packages/zone.js/npm_package');
const distTargetDir = join(destDir, 'zone.js');
console.info(`# Copy npm_package artifacts to ${distTargetDir}`);
rm('-rf', distTargetDir);
cp('-R', buildOutputDir, distTargetDir);
chmod('-R', 'u+w', distTargetDir);
sh.rm('-rf', distTargetDir);
sh.cp('-R', buildOutputDir, distTargetDir);
sh.chmod('-R', 'u+w', distTargetDir);
// Copy `zone.js.tgz` to `destDir`, so we can test
// the archive generated by the `npm_package.pack` rule.
const distArchiveTargetDir = `${absDestDir}/archive`;
const distArchiveTargetDir = `${destDir}/archive`;
console.info(`# Copy npm_package archive file to ${distArchiveTargetDir}`);
rm('-rf', distArchiveTargetDir);
mkdir('-p', distArchiveTargetDir);
mv(`${baseDir}/zone.js-${zonePackageJson.version}.tgz`, `${distArchiveTargetDir}/zone.js.tgz`);
console.info('');
sh.rm('-rf', distArchiveTargetDir);
sh.mkdir('-p', distArchiveTargetDir);
sh.mv(`${projectDir}/zone.js-*.tgz`, `${distArchiveTargetDir}/zone.js.tgz`);
}
+14
View File
@@ -0,0 +1,14 @@
{
"compilerOptions": {
"outDir": "../dist/dev-infra-scripts",
"target": "es2020",
"lib": ["es2020"],
"module": "Node16",
"types": ["node"],
"strict": true,
"noEmit": true,
"skipLibCheck": true,
"downlevelIteration": true,
"esModuleInterop": true
}
}