Skip to content

Commit ca1398e

Browse files
devversionandrewseguin
authored andcommitted
build: use bazel from node modules (#16361)
The goal of 2ce5ffd was to avoid the use of Bazel through the `node_modules` because it adds unnecessary code overhead, slows down CI and means that some tools need to be installed multiple times (such as `yarn`). Unfortunately when building a release with Bazel right now, the bazel workspace status script depends on the global `node` binary. This means that we need to bring in Node when running with the `--config=release` flag.. Since that causes inconsistent behavior and just complicates the setup, we are using Bazel through Yarn for now. Similar to how we did it for `angular/angular` with angular/angular@8fc4ae5.
1 parent 3ec6408 commit ca1398e

File tree

5 files changed

+113
-121
lines changed

5 files changed

+113
-121
lines changed

.circleci/config.yml

Lines changed: 49 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -8,89 +8,88 @@
88
# http://yaml-online-parser.appspot.com/
99

1010
var_1: &docker_image circleci/node:10.16
11-
var_2: &docker_bazel_image l.gcr.io/google/bazel:0.26.1
1211

1312
# **Note**: When updating the beginning of the cache key, also update the cache key to match
1413
# the new cache key prefix. This allows us to take advantage of CircleCI's fallback caching.
1514
# Read more here: https://circleci.com/docs/2.0/caching/#restoring-cache.
16-
var_3: &cache_key v3-ng-mat-{{ checksum "WORKSPACE" }}-{{ checksum "yarn.lock" }}
17-
var_4: &cache_fallback_key v3-ng-mat-
15+
var_2: &cache_key v4-ng-mat-{{ checksum "WORKSPACE" }}-{{ checksum "yarn.lock" }}
16+
var_3: &cache_fallback_key v4-ng-mat-
1817

1918
# Settings common to each job
20-
var_5: &job_defaults
19+
var_4: &job_defaults
2120
working_directory: ~/ng
2221
docker:
2322
- image: *docker_image
2423

2524
# Job step for checking out the source code from GitHub. This also ensures that the source code
2625
# is rebased on top of master.
27-
var_6: &checkout_code
26+
var_5: &checkout_code
2827
checkout:
2928
# After checkout, rebase on top of master. By default, PRs are not rebased on top of master,
3029
# which we want. See https://discuss.circleci.com/t/1662
3130
post: git pull --ff-only origin "refs/pull/${CI_PULL_REQUEST//*pull\//}/merge"
3231

3332
# Restores the cache that could be available for the current Yarn lock file. The cache usually
3433
# includes the node modules and the Bazel repository cache.
35-
var_7: &restore_cache
34+
var_6: &restore_cache
3635
restore_cache:
3736
keys:
3837
- *cache_key
3938
- *cache_fallback_key
4039

4140
# Saves the cache for the current Yarn lock file. We store the node modules and the Bazel
4241
# repository cache in order to make subsequent builds faster.
43-
var_8: &save_cache
42+
var_7: &save_cache
4443
save_cache:
4544
key: *cache_key
4645
paths:
4746
- "node_modules"
4847
- "~/bazel_repository_cache"
4948

5049
# Decryption token that is used to decode the GCP credentials file in ".circleci/gcp_token".
51-
var_9: &gcp_decrypt_token "angular"
50+
var_8: &gcp_decrypt_token "angular"
5251

5352
# Job step that ensures that the node module dependencies are installed and up-to-date. We use
5453
# Yarn with the frozen lockfile option in order to make sure that lock file and package.json are
5554
# in sync. Unlike in Travis, we don't need to manually purge the node modules if stale because
5655
# CircleCI automatically discards the cache if the checksum of the lock file has changed.
57-
var_10: &yarn_install
56+
var_9: &yarn_install
5857
run:
5958
name: "Installing project dependencies"
6059
command: yarn install --frozen-lockfile --non-interactive
6160

6261
# Anchor that can be used to download and install Yarn globally in the bash environment.
63-
var_11: &yarn_download
62+
var_10: &yarn_download
6463
run:
6564
name: "Downloading and installing Yarn"
6665
command: |
6766
touch $BASH_ENV
6867
curl -o- -L https://yarnpkg.com/install.sh | PROFILE=$BASH_ENV bash -s -- --version "1.16.0"
6968
7069
# Sets up the Bazel config which is specific for CircleCI builds.
71-
var_12: &setup_bazel_ci_config
70+
var_11: &setup_bazel_ci_config
7271
run:
7372
name: "Setting up Bazel configuration for CI"
7473
command: |
7574
echo "import %workspace%/.circleci/bazel.rc" >> ./.bazelrc
7675
7776
# Sets up a different Docker image that includes a moe recent Firefox version which
7877
# is needed for headless testing.
79-
var_13: &docker-firefox-image
78+
var_12: &docker-firefox-image
8079
# TODO(devversion): Temporarily use a image that includes Firefox 62 because the
8180
# ngcontainer image does include an old Firefox version that does not support headless.
8281
- image: circleci/node:11.4.0-browsers
8382

8483
# Attaches the release output which has been stored in the workspace to the current job.
8584
# https://circleci.com/docs/2.0/workflows/#using-workspaces-to-share-data-among-jobs
86-
var_14: &attach_release_output
85+
var_13: &attach_release_output
8786
attach_workspace:
8887
at: dist/
8988

9089
# Branch filter that we can specify for jobs that should only run on publish branches. This filter
9190
# is used to ensure that not all upstream branches will be published as Github builds
9291
# (e.g. revert branches, feature branches)
93-
var_15: &publish_branches_filter
92+
var_14: &publish_branches_filter
9493
branches:
9594
only:
9695
- master
@@ -104,15 +103,15 @@ var_15: &publish_branches_filter
104103
# In order to reduce duplication we use a YAML anchor that just always excludes the "_presubmit"
105104
# branch. We don't want to run Circle for the temporary "_presubmit" branch which is reserved
106105
# for the caretaker.
107-
var_16: &ignore_presubmit_branch_filter
106+
var_15: &ignore_presubmit_branch_filter
108107
branches:
109108
ignore:
110109
- "_presubmit"
111110
- "ivy-2019"
112111

113112
# Runs a script that sets up the Bazel remote execution. This will be used by jobs that run
114113
# Bazel primarily and should benefit from remote caching and execution.
115-
var_17: &setup_bazel_remote_execution
114+
var_16: &setup_bazel_remote_execution
116115
run:
117116
name: "Setup bazel RBE remote execution"
118117
command: ./scripts/circleci/bazel/setup-remote-execution.sh
@@ -132,8 +131,7 @@ jobs:
132131
# Build and test job that uses Bazel.
133132
# -----------------------------------
134133
bazel_build_test:
135-
docker:
136-
- image: *docker_bazel_image
134+
<<: *job_defaults
137135
resource_class: xlarge
138136
environment:
139137
GCP_DECRYPT_TOKEN: *gcp_decrypt_token
@@ -142,17 +140,18 @@ jobs:
142140
- *restore_cache
143141
- *setup_bazel_ci_config
144142
- *setup_bazel_remote_execution
143+
- *yarn_download
144+
- *yarn_install
145145

146-
- run: bazel build src/... --build_tag_filters=-docs-package
147-
- run: bazel test src/... --build_tag_filters=-docs-package --test_tag_filters=-e2e
146+
- run: yarn bazel build src/... --build_tag_filters=-docs-package
147+
- run: yarn bazel test src/... --build_tag_filters=-docs-package --test_tag_filters=-e2e
148148

149149
# --------------------------------------------------------------------------------------------
150150
# Job that runs ts-api-guardian against our API goldens in "tools/public_api_guard".
151151
# This job fails whenever an API has been updated but not explicitly approved through goldens.
152152
# --------------------------------------------------------------------------------------------
153153
api_golden_checks:
154-
docker:
155-
- image: *docker_bazel_image
154+
<<: *job_defaults
156155
resource_class: xlarge
157156
environment:
158157
GCP_DECRYPT_TOKEN: *gcp_decrypt_token
@@ -161,15 +160,16 @@ jobs:
161160
- *restore_cache
162161
- *setup_bazel_ci_config
163162
- *setup_bazel_remote_execution
163+
- *yarn_download
164+
- *yarn_install
164165

165-
- run: bazel test tools/public_api_guard/...
166+
- run: yarn bazel test tools/public_api_guard/...
166167

167168
# -----------------------------------------------------------------
168169
# Job that runs the e2e tests with Protractor and Chromium headless
169170
# -----------------------------------------------------------------
170171
e2e_tests:
171-
docker:
172-
- image: *docker_bazel_image
172+
<<: *job_defaults
173173
resource_class: xlarge
174174
environment:
175175
GCP_DECRYPT_TOKEN: *gcp_decrypt_token
@@ -178,8 +178,10 @@ jobs:
178178
- *restore_cache
179179
- *setup_bazel_ci_config
180180
- *setup_bazel_remote_execution
181+
- *yarn_download
182+
- *yarn_install
181183

182-
- run: bazel test src/... --test_tag_filters=e2e
184+
- run: yarn bazel test src/... --test_tag_filters=e2e
183185

184186
# ------------------------------------------------------------------------------------------
185187
# Job that runs the unit tests on locally installed browsers (Chrome and Firefox headless).
@@ -330,8 +332,7 @@ jobs:
330332
# Job that publishes the build snapshots
331333
# ----------------------------------------
332334
publish_snapshots:
333-
docker:
334-
- image: *docker_bazel_image
335+
<<: *job_defaults
335336
resource_class: xlarge
336337
environment:
337338
GCP_DECRYPT_TOKEN: *gcp_decrypt_token
@@ -341,6 +342,8 @@ jobs:
341342
- *attach_release_output
342343
- *setup_bazel_ci_config
343344
- *setup_bazel_remote_execution
345+
- *yarn_download
346+
- *yarn_install
344347

345348
# CircleCI has a config setting to enforce SSH for all github connections.
346349
# This is not compatible with our mechanism of using a Personal Access Token
@@ -349,7 +352,7 @@ jobs:
349352

350353
# TODO(devversion): Ideally the "build_release_packages" job should build all packages with
351354
# Bazel, but for now we mix up the Gulp and bazel setup, so we need to build the package here.
352-
- run: bazel build src/material-examples:npm_package --config=release
355+
- run: yarn bazel build src/material-examples:npm_package --config=release
353356

354357
- run: ./scripts/circleci/publish-snapshots.sh
355358

@@ -365,8 +368,11 @@ jobs:
365368
- *restore_cache
366369
- *yarn_download
367370

368-
- run: python ./scripts/circleci/setup-angular-snapshots.py --tag master
369-
- *yarn_install
371+
- run: node ./scripts/circleci/setup-angular-snapshots.js --tag master
372+
# Install yarn dependencies after the package.json has been updated. Note that
373+
# we can't use frozen-lockfile since the setup snapshots script does not update
374+
# the lock file.
375+
- run: yarn install --non-interactive
370376
- run: ./scripts/circleci/run-local-browser-tests.sh
371377

372378

@@ -375,8 +381,7 @@ jobs:
375381
# specified in the project dev dependencies.
376382
# ----------------------------------------------------------------------------
377383
ivy_test:
378-
docker:
379-
- image: *docker_bazel_image
384+
<<: *job_defaults
380385
resource_class: xlarge
381386
environment:
382387
GCP_DECRYPT_TOKEN: *gcp_decrypt_token
@@ -385,28 +390,29 @@ jobs:
385390
- *restore_cache
386391
- *setup_bazel_ci_config
387392
- *setup_bazel_remote_execution
393+
- *yarn_download
394+
- *yarn_install
388395

389396
# Setup Angular ivy snapshots built with ngtsc but locked to a specific tag. We
390397
# cannot determine the tag automatically based on the Angular version specified in
391398
# the "package.json" because the SHA is not known for the given release. Nor can
392399
# we use ngcc to apply the ivy switches because ngcc currently does not handle the
393400
# UMD format which is used by Bazel when running tests. UMD processing is in
394401
# progress and tracked with FW-85.
395-
- run: python ./scripts/circleci/setup-angular-snapshots.py --tag 8.1.0-next.1-ivy-aot+82e0b4a
402+
- run: node ./scripts/circleci/setup-angular-snapshots.js --tag 8.1.0-next.1-ivy-aot+82e0b4a
396403
# Disable type checking when building with Ivy. This is necessary because
397404
# type checking is not complete yet and can incorrectly break compilation.
398405
# Issue is tracked with FW-1004.
399406
- run: sed -i "s/\(_ENABLE_NG_TYPE_CHECKING = \)True/\1False/g" tools/defaults.bzl
400407
# Run project tests with ngtsc and the Ivy Angular packages.
401-
- run: bazel build src/... --build_tag_filters=-docs-package --define=compile=aot
402-
- run: bazel test src/... --build_tag_filters=-docs-package --define=compile=aot --test_tag_filters=-e2e
408+
- run: yarn bazel build src/... --build_tag_filters=-docs-package --define=compile=aot
409+
- run: yarn bazel test src/... --build_tag_filters=-docs-package --define=compile=aot --test_tag_filters=-e2e
403410

404411
# ----------------------------------------------------------------------------
405412
# Job that runs all Bazel tests against Ivy from angular/angular#master.
406413
# ----------------------------------------------------------------------------
407414
ivy_snapshot_test_cronjob:
408-
docker:
409-
- image: *docker_bazel_image
415+
<<: *job_defaults
410416
resource_class: xlarge
411417
environment:
412418
GCP_DECRYPT_TOKEN: *gcp_decrypt_token
@@ -415,16 +421,18 @@ jobs:
415421
- *restore_cache
416422
- *setup_bazel_ci_config
417423
- *setup_bazel_remote_execution
424+
- *yarn_download
425+
- *yarn_install
418426

419427
# Setup Angular ivy snapshots built with ngtsc.
420-
- run: python ./scripts/circleci/setup-angular-snapshots.py --tag master-ivy-aot
428+
- run: node ./scripts/circleci/setup-angular-snapshots.js --tag master-ivy-aot
421429
# Disable type checking when building with Ivy. This is necessary because
422430
# type checking is not complete yet and can incorrectly break compilation.
423431
# Issue is tracked with FW-1004.
424432
- run: sed -i "s/\(_ENABLE_NG_TYPE_CHECKING = \)True/\1False/g" tools/defaults.bzl
425433
# Run project tests with ngtsc and the Ivy Angular packages.
426-
- run: bazel build src/... --build_tag_filters=-docs-package --define=compile=aot
427-
- run: bazel test src/... --build_tag_filters=-docs-package --define=compile=aot --test_tag_filters=-e2e
434+
- run: yarn bazel build src/... --build_tag_filters=-docs-package --define=compile=aot
435+
- run: yarn bazel test src/... --build_tag_filters=-docs-package --define=compile=aot --test_tag_filters=-e2e
428436

429437
# ----------------------------------------------------------------------------------------
430438
# Workflow definitions. A workflow usually groups multiple jobs together. This is useful if
Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
11
#!/bin/bash
22

3+
# The script should immediately exit if any command in the script fails.
4+
set -e
5+
36
if [[ -z "${GCP_DECRYPT_TOKEN}" ]]; then
47
echo "Please specify the \"GCP_DECRYPT_TOKEN\" environment variable when setting up remote " \
58
"execution"
@@ -8,12 +11,12 @@ fi
811

912
# Decode the GCP token that is needed to authenticate the Bazel remote execution.
1013
openssl aes-256-cbc -d -in .circleci/gcp_token -md md5 -k ${GCP_DECRYPT_TOKEN} \
11-
-out /home/.gcp_credentials
14+
-out $HOME/.gcp_credentials
1215

1316
# Export the "GOOGLE_APPLICATION_CREDENTIALS" variable that should refer to the GCP credentials
1417
# file. Bazel automatically picks up the credentials from that variable.
1518
# https://github.com/bazelbuild/bazel/blob/master/third_party/grpc/include/grpc/grpc_security.h#L134-L137
16-
echo "export GOOGLE_APPLICATION_CREDENTIALS=/home/.gcp_credentials" >> $BASH_ENV
19+
echo "export GOOGLE_APPLICATION_CREDENTIALS=$HOME/.gcp_credentials" >> $BASH_ENV
1720

1821
# Update the CircleCI Bazel configuration to always use remote execution.
1922
echo 'build --config=remote' >> .circleci/bazel.rc
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
/**
2+
* Script that sets up the Angular snapshot github builds. We set up the snapshot builds by
3+
* overwriting the versions in the "package.json" and taking advantage of Yarn's resolutions
4+
* feature. Yarn resolutions will be used to flatten nested Angular packages because by default
5+
* Yarn does not flatten any dependency. See:
6+
*
7+
* node_modules/compiler@snapshot
8+
* node_modules/compiler-cli@snapshot
9+
* node_modules/[email protected]
10+
*
11+
* Note that we cannot just use Yarn's `--flat` option because that would mean that it tries
12+
* to flatten **all** dependencies and could cause unexpected results. We **only** want to
13+
* explicitly flatten out all `@angular/*` dependencies. This can be achieved with resolutions.
14+
* Read more here: https://yarnpkg.com/lang/en/docs/package-json/#toc-resolutions
15+
*/
16+
17+
const {yellow, green} = require('chalk');
18+
const {writeFileSync} = require('fs');
19+
const {join} = require('path');
20+
21+
const {tag} = require('minimist')(process.argv.slice(2), {string: ['tag']});
22+
const projectDir = join(__dirname, '../../');
23+
const packageJsonPath = join(projectDir, 'package.json');
24+
const packageJson = require(packageJsonPath);
25+
26+
// Initialize the "resolutions" property in case it is not present in the "package.json" yet.
27+
// See: https://yarnpkg.com/lang/en/docs/package-json/#toc-resolutions for the API.
28+
packageJson['resolutions'] = packageJson['resolutions'] || {};
29+
30+
// List that contains the names of all installed Angular packages (e.g. "@angular/core")
31+
const angularPackages = Object.keys({...packageJson.dependencies, ...packageJson.devDependencies})
32+
.filter(packageName => packageName.startsWith('@angular/'));
33+
const packageSuffix = tag ? ` (${tag})` : '';
34+
35+
console.log(green('Setting up snapshot builds for:\n'));
36+
console.log(yellow(` ${angularPackages.map(n => `${n}${packageSuffix}`).join('\n ')}\n`));
37+
38+
// Setup the snapshot version for each Angular package specified in the "package.json" file.
39+
angularPackages.forEach(packageName => {
40+
let buildsUrl = `github:angular/${packageName.split('/')[1]}-builds${tag ? `#${tag}` : ''}`;
41+
42+
// Add resolutions for each package in the format "**/{PACKAGE}" so that all
43+
// nested versions of that specific Angular package will have the same version.
44+
packageJson.resolutions[`**/${packageName}`] = buildsUrl;
45+
46+
// Since the resolutions only cover the version of all nested installs, we also need
47+
// to explicitly set the version for the package listed in the project "package.json".
48+
packageJson.dependencies[packageName] = buildsUrl;
49+
50+
// In case this dependency was previously a dev dependency, just remove it because we
51+
// re-added it as a normal dependency for simplicity.
52+
delete packageJson.devDependencies[packageName];
53+
});
54+
55+
// Write changes to the "packageJson", so that we can install the new versions afterwards.
56+
writeFileSync(packageJsonPath, JSON.stringify(packageJson, null, 2));
57+
58+
console.log(green('Successfully added the "resolutions" to the "package.json".'));

0 commit comments

Comments
 (0)