diff --git a/.bazelrc b/.bazelrc index d34805e2baf..c4ad01facfa 100644 --- a/.bazelrc +++ b/.bazelrc @@ -61,6 +61,15 @@ build:aio_local_deps --workspace_status_command="yarn -s --cwd aio local-workspa build:snapshot-build --workspace_status_command="yarn -s ng-dev release build-env-stamp --mode=snapshot" build:snapshot-build --stamp +########################################################## +# AIO architect build configuration # +# See aio/angular.json for available configurations. # +# To build with a partiular configuration: # +# bazel build //aio:build --aio_build_config= # +# Default config is `stable``. # +########################################################## +build --flag_alias=aio_build_config=//aio:flag_aio_build_config + #################################### # AIO first party dep substitution # # Turn on with # diff --git a/aio/BUILD.bazel b/aio/BUILD.bazel index 771c96bf315..d67502afae7 100644 --- a/aio/BUILD.bazel +++ b/aio/BUILD.bazel @@ -3,7 +3,7 @@ load("@build_bazel_rules_nodejs//:index.bzl", "copy_to_bin", "npm_package_bin") load("//tools:defaults.bzl", "nodejs_binary") load("@aspect_bazel_lib//lib:copy_to_directory.bzl", "copy_to_directory") load(":local_packages_util.bzl", "link_local_packages", "substitute_local_package_deps") -load("@bazel_skylib//rules:common_settings.bzl", "bool_flag") +load("@bazel_skylib//rules:common_settings.bzl", "bool_flag", "string_flag") load("//aio/scripts:local_server_test.bzl", "local_server_test") load("@aio_npm//@angular/build-tooling/bazel/remote-execution:index.bzl", "ENABLE_NETWORK") load(":aio_targets.bzl", "aio_test") @@ -29,6 +29,46 @@ config_setting( }, ) +# Config setting controlling the AIO architect configuration to build with +string_flag( + name = "flag_aio_build_config", + build_setting_default = "stable", + values = [ + "stable", + "rc", + "next", + "archive", + ], +) + +config_setting( + name = "aio_build_config_stable", + flag_values = { + ":flag_aio_build_config": "stable", + }, +) + +config_setting( + name = "aio_build_config_rc", + flag_values = { + ":flag_aio_build_config": "rc", + }, +) + +config_setting( + name = "aio_build_config_next", + flag_values = { + ":flag_aio_build_config": "next", + }, +) + +config_setting( + name = "aio_build_config_archive", + flag_values = { + ":flag_aio_build_config": "archive", + }, +) + # Run dgeni generation npm_package_bin( name = "dgeni", @@ -186,8 +226,12 @@ copy_to_bin( architect( name = "build-app", - args = [ - "site:build:stable", + args = select({ + ":aio_build_config_stable": ["site:build:stable"], + ":aio_build_config_next": ["site:build:next"], + ":aio_build_config_rc": ["site:build:rc"], + ":aio_build_config_archive": ["site:build:archive"], + }) + [ "--output-path=build-app", ], chdir = "$(RULEDIR)", diff --git a/aio/package.json b/aio/package.json index 97ec9fc3141..bbba2949834 100644 --- a/aio/package.json +++ b/aio/package.json @@ -30,7 +30,7 @@ "example-list-overrides": "bazel run //aio/tools/examples:example-boilerplate list-overrides", "example-lint": "eslint content/examples", "example-playground": "node ./tools/examples/create-example-playground-wrapper.mjs", - "deploy-production": "bazel run //aio/scripts/deploy-to-firebase --config=release", + "deploy-production": "node ./scripts/deploy-to-firebase/index.mjs", "check-env": "yarn ~~check-env", "payload-size": "scripts/payload.sh", "predocs": "node scripts/contributors/validate-data && bazel build -- //aio:stackblitz //aio:example-zips", diff --git a/aio/scripts/deploy-to-firebase/BUILD.bazel b/aio/scripts/deploy-to-firebase/BUILD.bazel index e49cb572a5e..407d2972522 100644 --- a/aio/scripts/deploy-to-firebase/BUILD.bazel +++ b/aio/scripts/deploy-to-firebase/BUILD.bazel @@ -1,7 +1,5 @@ load("@aio_npm//@bazel/jasmine:index.bzl", "jasmine_node_test") -load("//tools:defaults.bzl", "nodejs_binary") load("@aio_npm//@angular/build-tooling/bazel/remote-execution:index.bzl", "ENABLE_NETWORK") -load("//:yarn.bzl", "YARN_LABEL") DEPLOY_TO_FIREBASE_SOURCES = glob( ["**/*.mjs"], @@ -12,18 +10,8 @@ DEPLOY_TO_FIREBASE_DEPS = [ "@aio_npm//shelljs", "//aio:build", "//:package.json", - YARN_LABEL, ] -nodejs_binary( - name = "deploy-to-firebase", - data = DEPLOY_TO_FIREBASE_SOURCES + DEPLOY_TO_FIREBASE_DEPS, - entry_point = "index.mjs", - env = { - "YARN_BIN": "$(rootpath %s)" % YARN_LABEL, - }, -) - jasmine_node_test( name = "test", srcs = glob(["**/*.spec.mjs"]), diff --git a/aio/scripts/deploy-to-firebase/index.mjs b/aio/scripts/deploy-to-firebase/index.mjs index c37a4ffb30a..05d791f5f4a 100644 --- a/aio/scripts/deploy-to-firebase/index.mjs +++ b/aio/scripts/deploy-to-firebase/index.mjs @@ -50,6 +50,7 @@ import path from 'path'; import sh from 'shelljs'; +import {fileURLToPath} from 'url'; import post from './post-deploy-actions.mjs'; import pre from './pre-deploy-actions.mjs'; import u from './utils.mjs'; @@ -58,9 +59,11 @@ sh.set('-e'); // Constants -const RUNFILES_ROOT = process.cwd(); -const DIRNAME = path.join(RUNFILES_ROOT, 'aio', 'scripts', 'deploy-to-firebase'); -const ROOT_PKG_PATH = path.join(RUNFILES_ROOT, 'package.json'); +const inBazelTest = !!process.env.TEST_SRCDIR; +const DIRNAME = !inBazelTest + ? u.getDirname(import.meta.url) + : path.join('.', 'aio', 'scripts', 'deploy-to-firebase'); +const ROOT_PKG_PATH = `${DIRNAME}/../../../package.json`; // Exports export { @@ -75,7 +78,9 @@ export { // references the full file path (including the file extension). // See https://stackoverflow.com/questions/45136831/node-js-require-main-module#answer-60309682 for // more details. -if (path.resolve(DIRNAME, 'index.mjs') === process.argv[1]) { +const isMain = inBazelTest || + (fileURLToPath(import.meta.url) === process.argv[1]); +if (isMain) { const isDryRun = process.argv[2] === '--dry-run'; const inputVars = computeInputVars(process.env); const deploymentsInfo = computeDeploymentsInfo(inputVars); diff --git a/aio/scripts/deploy-to-firebase/index.spec.mjs b/aio/scripts/deploy-to-firebase/index.spec.mjs index b8a5f945cdb..0c7b58751dc 100644 --- a/aio/scripts/deploy-to-firebase/index.spec.mjs +++ b/aio/scripts/deploy-to-firebase/index.spec.mjs @@ -585,7 +585,11 @@ describe('deploy-to-firebase:', () => { CI_BRANCH: '4.4.x', CI_STABLE_BRANCH: mostRecentMinorBranch, CI_COMMIT: latestCommits['4.4.x'], + // Pass along this Bazel test env var as it's used + // by the script to determine if it's in a test. + TEST_SRCDIR: process.env.TEST_SRCDIR, }; + const result = execSync(cmd, {encoding: 'utf8', env}).trim(); expect(result).toBe( 'Deployments (1): archive\n' + diff --git a/aio/scripts/deploy-to-firebase/pre-deploy-actions.mjs b/aio/scripts/deploy-to-firebase/pre-deploy-actions.mjs index b8486bd83a6..f6538ed1dd1 100644 --- a/aio/scripts/deploy-to-firebase/pre-deploy-actions.mjs +++ b/aio/scripts/deploy-to-firebase/pre-deploy-actions.mjs @@ -4,7 +4,7 @@ import u from './utils.mjs'; // Constants -const DIST_DIR = 'dist'; +const DIST_DIR = 'dist/bin/aio/build'; const FIREBASE_JSON_PATH = 'firebase.json'; const NGSW_JSON_PATH = `${DIST_DIR}/ngsw.json`; const NGSW_JSON_BAK_PATH = `${NGSW_JSON_PATH}.bak`; @@ -34,7 +34,7 @@ export default exp; // Helpers function build({deployedUrl, deployEnv}) { u.logSectionHeader('Build the AIO app.'); - u.yarn(`build --configuration=${deployEnv} --progress=false`); + u.yarn(`build --aio_build_config=${deployEnv}`); u.logSectionHeader('Add any mode-specific files into the AIO distribution.'); sh.cp('-rf', `src/extra-files/${deployEnv}/.`, DIST_DIR); diff --git a/aio/scripts/deploy-to-firebase/pre-deploy-actions.spec.mjs b/aio/scripts/deploy-to-firebase/pre-deploy-actions.spec.mjs index f83a93bae91..67540cfba0e 100644 --- a/aio/scripts/deploy-to-firebase/pre-deploy-actions.spec.mjs +++ b/aio/scripts/deploy-to-firebase/pre-deploy-actions.spec.mjs @@ -28,12 +28,12 @@ describe('deploy-to-firebase/pre-deploy-actions:', () => { it('should build the app for the appropriate mode', () => { pre.build({deployedUrl: 'http://example.com/foo/', deployEnv: 'bar'}); - expect(yarnSpy).toHaveBeenCalledWith('build --configuration=bar --progress=false'); + expect(yarnSpy).toHaveBeenCalledWith('build --aio_build_config=bar'); }); it('should add mode-specific files into the distribution', () => { pre.build({deployedUrl: 'http://example.com/foo/', deployEnv: 'bar'}); - expect(cpSpy).toHaveBeenCalledWith('-rf', 'src/extra-files/bar/.', 'dist'); + expect(cpSpy).toHaveBeenCalledWith('-rf', 'src/extra-files/bar/.', 'dist/bin/aio/build'); }); it('should update the opensearch descriptor', () => { @@ -56,8 +56,8 @@ describe('deploy-to-firebase/pre-deploy-actions:', () => { pre.build({deployedUrl: 'http://example.com/foo/', deployEnv: 'bar'}); expect(logs).toEqual([ - 'yarn build --configuration=bar --progress=false', - 'cp -rf src/extra-files/bar/. dist', + 'yarn build --aio_build_config=bar', + 'cp -rf src/extra-files/bar/. dist/bin/aio/build', 'yarn set-opensearch-url http://example.com/foo/', ]); }); @@ -81,7 +81,8 @@ describe('deploy-to-firebase/pre-deploy-actions:', () => { it('should disable the ServiceWorker by renaming the `ngsw.json` manifest', () => { pre.disableServiceWorker(); - expect(mvSpy).toHaveBeenCalledWith('dist/ngsw.json', 'dist/ngsw.json.bak'); + expect(mvSpy).toHaveBeenCalledWith('dist/bin/aio/build/ngsw.json', + 'dist/bin/aio/build/ngsw.json.bak'); }); }); @@ -148,7 +149,7 @@ describe('deploy-to-firebase/pre-deploy-actions:', () => { it('should undo `build()`', () => { pre.undo.build(); - expect(rmSpy).toHaveBeenCalledWith('-rf', 'dist'); + expect(rmSpy).toHaveBeenCalledWith('-rf', 'dist/bin/aio/build'); }); }); @@ -164,7 +165,8 @@ describe('deploy-to-firebase/pre-deploy-actions:', () => { it('should undo `disableServiceWorker()`', () => { pre.undo.disableServiceWorker(); - expect(mvSpy).toHaveBeenCalledWith('dist/ngsw.json.bak', 'dist/ngsw.json'); + expect(mvSpy).toHaveBeenCalledWith('dist/bin/aio/build/ngsw.json.bak', + 'dist/bin/aio/build/ngsw.json'); }); }); diff --git a/aio/scripts/deploy-to-firebase/utils.mjs b/aio/scripts/deploy-to-firebase/utils.mjs index fd592c1bfa7..8096cdbd482 100644 --- a/aio/scripts/deploy-to-firebase/utils.mjs +++ b/aio/scripts/deploy-to-firebase/utils.mjs @@ -105,5 +105,5 @@ function yarn(cmd) { // This is not strictly necessary, since CircleCI will mask secret environment variables in the // output (see https://circleci.com/docs/2.0/env-vars/#secrets-masking), but is an extra // precaution. - return sh.exec(`${process.env.YARN_BIN} --silent ${cmd}`, {cwd: 'aio'}); + return sh.exec(`yarn --silent ${cmd}`); } diff --git a/aio/scripts/deploy-to-firebase/utils.spec.mjs b/aio/scripts/deploy-to-firebase/utils.spec.mjs index 4c0bd6b2ff2..c9254cf1296 100644 --- a/aio/scripts/deploy-to-firebase/utils.spec.mjs +++ b/aio/scripts/deploy-to-firebase/utils.spec.mjs @@ -284,13 +284,6 @@ describe('deploy-to-firebase/utils:', () => { beforeEach(() => execSpy = spyOn(sh, 'exec')); - it('should execute the yarn binary in process.env.YARN_BIN', () => { - process.env.YARN_BIN = '/foo/yarn'; - u.yarn('foo --bar'); - const cmd = execSpy.calls.argsFor(0)[0]; - expect(cmd.startsWith('/foo/yarn')).toEqual(true); - }); - it('should execute yarn in silent mode', () => { u.yarn('foo --bar'); @@ -298,13 +291,6 @@ describe('deploy-to-firebase/utils:', () => { expect(cmd.endsWith('--silent foo --bar')).toEqual(true); }); - it('should cd into aio', () => { - u.yarn('foo --bar'); - - const options = execSpy.calls.argsFor(0)[1]; - expect(options.cwd).toEqual('aio'); - }); - it('should return the output from the command\'s execution', () => { execSpy.and.returnValue('command output\n'); expect(u.yarn('foo --bar')).toBe('command output\n');