From d248d83c17150d045d10aca424d711ba032d6319 Mon Sep 17 00:00:00 2001 From: Paul Gschwendtner Date: Wed, 22 Jun 2022 16:13:15 +0000 Subject: [PATCH] build: convert release package build scripts to typescript (#46456) Follow-up to: cce395a928bdcd85fe1b24c5887c2ca587b659a2. PR Close #46456 --- .bazelrc | 4 +- .circleci/config.yml | 2 +- .ng-dev/release.mts | 11 +- aio/tools/ng-packages-installer/index.js | 9 +- aio/tools/ng-packages-installer/index.spec.js | 13 +- devtools/src/BUILD.bazel | 2 +- docs/BAZEL.md | 2 +- docs/DEBUG_COMPONENTS_REPO_IVY.md | 3 +- docs/DEVELOPER.md | 4 +- integration/README.md | 2 +- .../cli-hello-world-ivy-compat/debug-test.sh | 3 +- .../cli-hello-world-ivy-minimal/debug-test.sh | 3 +- integration/ivy-i18n/debug-test.sh | 3 +- integration/ngcc/debug-test.sh | 3 +- integration/run_tests.sh | 2 +- package.json | 9 +- scripts/build-package-dist.js | 27 ---- scripts/build/angular-in-memory-web-api.js | 54 ------- scripts/build/angular-in-memory-web-api.mts | 50 ++++++ ...ckages-dist.js => build-packages-dist.mts} | 11 +- scripts/build/package-builder.d.ts | 18 --- scripts/build/package-builder.js | 153 ------------------ scripts/build/package-builder.mts | 135 ++++++++++++++++ ...zone-js-builder.js => zone-js-builder.mts} | 45 +++--- scripts/tsconfig.json | 14 ++ 25 files changed, 258 insertions(+), 324 deletions(-) delete mode 100755 scripts/build-package-dist.js delete mode 100644 scripts/build/angular-in-memory-web-api.js create mode 100644 scripts/build/angular-in-memory-web-api.mts rename scripts/build/{build-packages-dist.js => build-packages-dist.mts} (71%) delete mode 100644 scripts/build/package-builder.d.ts delete mode 100644 scripts/build/package-builder.js create mode 100644 scripts/build/package-builder.mts rename scripts/build/{zone-js-builder.js => zone-js-builder.mts} (61%) create mode 100644 scripts/tsconfig.json diff --git a/.bazelrc b/.bazelrc index 2113c04e8ec8b..8cb316f8d731f 100644 --- a/.bazelrc +++ b/.bazelrc @@ -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 # diff --git a/.circleci/config.yml b/.circleci/config.yml index acdd0ca634a67..88d500c914e07 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -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: diff --git a/.ng-dev/release.mts b/.ng-dev/release.mts index 788427e481704..e68afaeaa3586 100644 --- a/.ng-dev/release.mts +++ b/.ng-dev/release.mts @@ -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'], diff --git a/aio/tools/ng-packages-installer/index.js b/aio/tools/ng-packages-installer/index.js index 2e021a2e41e93..fe76161b69222 100644 --- a/aio/tools/ng-packages-installer/index.js +++ b/aio/tools/ng-packages-installer/index.js @@ -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...', diff --git a/aio/tools/ng-packages-installer/index.spec.js b/aio/tools/ng-packages-installer/index.spec.js index 77ff633c1718f..d9d5981362249 100644 --- a/aio/tools/ng-packages-installer/index.spec.js +++ b/aio/tools/ng-packages-installer/index.spec.js @@ -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', () => { diff --git a/devtools/src/BUILD.bazel b/devtools/src/BUILD.bazel index 97dc72f20b296..ba0a274b8772f 100644 --- a/devtools/src/BUILD.bazel +++ b/devtools/src/BUILD.bazel @@ -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. diff --git a/docs/BAZEL.md b/docs/BAZEL.md index d8be78c87e4ad..0461d5833a6e4 100644 --- a/docs/BAZEL.md +++ b/docs/BAZEL.md @@ -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 diff --git a/docs/DEBUG_COMPONENTS_REPO_IVY.md b/docs/DEBUG_COMPONENTS_REPO_IVY.md index 079b7a9c5722b..bd1d6e3781cbd 100644 --- a/docs/DEBUG_COMPONENTS_REPO_IVY.md +++ b/docs/DEBUG_COMPONENTS_REPO_IVY.md @@ -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)). diff --git a/docs/DEVELOPER.md b/docs/DEVELOPER.md index 985fd49c1a0e1..bb526648eb4db 100644 --- a/docs/DEVELOPER.md +++ b/docs/DEVELOPER.md @@ -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: diff --git a/integration/README.md b/integration/README.md index f0066da7393d4..884f9ac10396d 100644 --- a/integration/README.md +++ b/integration/README.md @@ -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. diff --git a/integration/cli-hello-world-ivy-compat/debug-test.sh b/integration/cli-hello-world-ivy-compat/debug-test.sh index 38013c4ffc743..c24a10d5b34ee 100755 --- a/integration/cli-hello-world-ivy-compat/debug-test.sh +++ b/integration/cli-hello-world-ivy-compat/debug-test.sh @@ -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 diff --git a/integration/cli-hello-world-ivy-minimal/debug-test.sh b/integration/cli-hello-world-ivy-minimal/debug-test.sh index 38013c4ffc743..c24a10d5b34ee 100755 --- a/integration/cli-hello-world-ivy-minimal/debug-test.sh +++ b/integration/cli-hello-world-ivy-minimal/debug-test.sh @@ -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 diff --git a/integration/ivy-i18n/debug-test.sh b/integration/ivy-i18n/debug-test.sh index 38013c4ffc743..c24a10d5b34ee 100755 --- a/integration/ivy-i18n/debug-test.sh +++ b/integration/ivy-i18n/debug-test.sh @@ -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 diff --git a/integration/ngcc/debug-test.sh b/integration/ngcc/debug-test.sh index 83d3ed6894049..88cf0cffabd85 100755 --- a/integration/ngcc/debug-test.sh +++ b/integration/ngcc/debug-test.sh @@ -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 diff --git a/integration/run_tests.sh b/integration/run_tests.sh index 76d36faffab52..3fd4d990f07e5 100755 --- a/integration/run_tests.sh +++ b/integration/run_tests.sh @@ -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 diff --git a/package.json b/package.json index 430bd340925b2..a1315f3d37bd3 100644 --- a/package.json +++ b/package.json @@ -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": { diff --git a/scripts/build-package-dist.js b/scripts/build-package-dist.js deleted file mode 100755 index 37a07407ffb44..0000000000000 --- a/scripts/build-package-dist.js +++ /dev/null @@ -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); diff --git a/scripts/build/angular-in-memory-web-api.js b/scripts/build/angular-in-memory-web-api.js deleted file mode 100644 index 0e8ac2ddb4a5a..0000000000000 --- a/scripts/build/angular-in-memory-web-api.js +++ /dev/null @@ -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(''); -} diff --git a/scripts/build/angular-in-memory-web-api.mts b/scripts/build/angular-in-memory-web-api.mts new file mode 100644 index 0000000000000..3279a6216f9d8 --- /dev/null +++ b/scripts/build/angular-in-memory-web-api.mts @@ -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); +} diff --git a/scripts/build/build-packages-dist.js b/scripts/build/build-packages-dist.mts similarity index 71% rename from scripts/build/build-packages-dist.js rename to scripts/build/build-packages-dist.mts index 86575d509bb17..a39f74d7c81a6 100755 --- a/scripts/build/build-packages-dist.js +++ b/scripts/build/build-packages-dist.mts @@ -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. diff --git a/scripts/build/package-builder.d.ts b/scripts/build/package-builder.d.ts deleted file mode 100644 index a84dd147b6361..0000000000000 --- a/scripts/build/package-builder.d.ts +++ /dev/null @@ -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}[]; diff --git a/scripts/build/package-builder.js b/scripts/build/package-builder.js deleted file mode 100644 index a9288f6a1fdb2..0000000000000 --- a/scripts/build/package-builder.js +++ /dev/null @@ -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(); - } -} diff --git a/scripts/build/package-builder.mts b/scripts/build/package-builder.mts new file mode 100644 index 0000000000000..6b4ac808cac03 --- /dev/null +++ b/scripts/build/package-builder.mts @@ -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(); + } +} diff --git a/scripts/build/zone-js-builder.js b/scripts/build/zone-js-builder.mts similarity index 61% rename from scripts/build/zone-js-builder.js rename to scripts/build/zone-js-builder.mts index 604b2eb7b0d11..9037919e39e24 100644 --- a/scripts/build/zone-js-builder.js +++ b/scripts/build/zone-js-builder.mts @@ -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`); } diff --git a/scripts/tsconfig.json b/scripts/tsconfig.json new file mode 100644 index 0000000000000..64d59de9c3ed9 --- /dev/null +++ b/scripts/tsconfig.json @@ -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 + } +}