Skip to content

Commit 8ec21fc

Browse files
alexeaglemhevery
authored andcommitted
ci: enable bazel remote caching on CircleCI (angular#21784)
This should cause Bazel builds to be incremental, only re-building parts of Angular affected by changes since the last build. It also fixes a potential version skew, where CI was running the Bazel linter binaries in the ngcontainer docker image, but developers built them using the versions in WORKSPACE PR Close angular#21784
1 parent eb48750 commit 8ec21fc

5 files changed

Lines changed: 86 additions & 15 deletions

File tree

.circleci/bazel.rc

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
# These options are enabled when running on CI
2+
# We do this by copying this file to /etc/bazel.bazelrc at the start of the build.
3+
# See remote cache documentation in /docs/BAZEL.md
4+
5+
# Don't be spammy in the logs
6+
build --noshow_progress
7+
8+
# Don't run manual tests
9+
test --test_tag_filters=-manual
10+
11+
# Enable experimental CircleCI bazel remote cache proxy
12+
# See remote cache documentation in /docs/BAZEL.md
13+
build --experimental_remote_spawn_cache --remote_rest_cache=http://localhost:7643
14+
15+
# Prevent unstable environment variables from tainting cache keys
16+
build --experimental_strict_action_env
17+
18+
# Workaround https://github.com/bazelbuild/bazel/issues/3645
19+
# Bazel doesn't calculate the memory ceiling correctly when running under Docker.
20+
# Limit Bazel to consuming resources that fit in CircleCI "medium" class which is the default:
21+
# https://circleci.com/docs/2.0/configuration-reference/#resource_class
22+
build --local_resources=3072,2.0,1.0
23+
24+
# Retry in the event of flakes, eg. https://circleci.com/gh/angular/angular/31309
25+
test --flaky_test_attempts=2

.circleci/config.yml

Lines changed: 22 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,13 @@
1515
var_1: &docker_image angular/ngcontainer:0.1.0
1616
var_2: &cache_key angular-{{ .Branch }}-{{ checksum "yarn.lock" }}-0.1.0
1717

18+
# See remote cache documentation in /docs/BAZEL.md
19+
var_3: &setup-bazel-remote-cache
20+
run:
21+
name: Start up bazel remote cache proxy
22+
command: ~/bazel-remote-proxy -backend circleci://
23+
background: true
24+
1825
# Settings common to each job
1926
anchor_1: &job_defaults
2027
working_directory: ~/ng
@@ -34,14 +41,16 @@ jobs:
3441
steps:
3542
- checkout:
3643
<<: *post_checkout
37-
# Check BUILD.bazel formatting before we have a node_modules directory
38-
# Then we don't need any exclude pattern to avoid checking those files
39-
- run: 'buildifier -mode=check $(find . -type f \( -name BUILD.bazel -or -name BUILD \)) ||
40-
(echo "BUILD files not formatted. Please run ''yarn buildifier''" ; exit 1)'
41-
# Run the skylark linter to check our Bazel rules
42-
- run: 'find . -type f -name "*.bzl" |
43-
xargs java -jar /usr/local/bin/Skylint_deploy.jar ||
44+
# See remote cache documentation in /docs/BAZEL.md
45+
- run: .circleci/setup_cache.sh
46+
- run: sudo cp .circleci/bazel.rc /etc/bazel.bazelrc
47+
- *setup-bazel-remote-cache
48+
49+
- run: 'yarn buildifier -mode=check ||
50+
(echo -e "\nBUILD files not formatted. Please run ''yarn buildifier''" ; exit 1)'
51+
- run: 'yarn skylint ||
4452
(echo -e "\n.bzl files have lint errors. Please run ''yarn skylint''"; exit 1)'
53+
4554
- restore_cache:
4655
key: *cache_key
4756

@@ -54,6 +63,11 @@ jobs:
5463
steps:
5564
- checkout:
5665
<<: *post_checkout
66+
# See remote cache documentation in /docs/BAZEL.md
67+
- run: .circleci/setup_cache.sh
68+
- run: sudo cp .circleci/bazel.rc /etc/bazel.bazelrc
69+
- *setup-bazel-remote-cache
70+
5771
- restore_cache:
5872
key: *cache_key
5973

@@ -62,7 +76,7 @@ jobs:
6276
# Use bazel query so that we explicitly ask for all buildable targets to be built as well
6377
# This avoids waiting for a build command to finish before running the first test
6478
# See https://github.com/bazelbuild/bazel/issues/4257
65-
- run: bazel query --output=label '//modules/... union //packages/... union //tools/...' | xargs bazel test --config=ci
79+
- run: bazel query --output=label '//modules/... union //packages/... union //tools/...' | xargs bazel test
6680

6781
# CircleCI will allow us to go back and view/download these artifacts from past builds.
6882
# Also we can use a service like https://buildsize.org/ to automatically track binary size of these artifacts.

.circleci/setup_cache.sh

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
#!/bin/sh
2+
# Install bazel remote cache proxy
3+
# This is temporary until the feature is no longer experimental on CircleCI.
4+
# See remote cache documentation in /docs/BAZEL.md
5+
6+
set -u -e
7+
8+
readonly DOWNLOAD_URL="https://5-116431813-gh.circle-artifacts.com/0/pkg/bazel-remote-proxy-$(uname -s)_$(uname -m)"
9+
10+
curl --fail -o ~/bazel-remote-proxy "$DOWNLOAD_URL"
11+
chmod +x ~/bazel-remote-proxy

docs/BAZEL.md

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,30 @@ Apple+Shift+D on Mac) and click on the green play icon next to the configuration
112112
- Open chrome at: [http://localhost:9876/debug.html](http://localhost:9876/debug.html)
113113
- Open chrome inspector
114114

115+
## Remote cache
116+
117+
Bazel supports fetching action results from a cache, allowing a clean build to pick up artifacts from prior builds.
118+
This makes builds incremental, even on CI.
119+
It works because Bazel assigns a content-based hash to all action inputs, which is used as the cache key for the action outputs.
120+
Thanks the the hermeticity property, we can skip executing an action if the inputs hash is already present in the cache.
121+
122+
Of course, non-hermeticity in an action can cause problems.
123+
At worst, you can fetch a broken artifact from the cache, making your build non-reproducible.
124+
For this reason, we are careful to implement our Bazel rules to depend only on their inputs.
125+
126+
Currently we only use remote caching on CircleCI.
127+
We could enable it for developer builds as well, which would make initial builds much faster for developers by fetching already-built artifacts from the cache.
128+
129+
This feature is experimental, and developed by the CircleCI team with guidance from Angular.
130+
Contact Alex Eagle with questions.
131+
132+
*How it's configured*:
133+
134+
1. In `.circleci/config.yml`, each CircleCI job downloads a proxy binary, which is built from https://github.com/notnoopci/bazel-remote-proxy. The download is done by running `.circleci/setup_cache.sh`. When the feature graduates from experimental, this proxy will be installed by default on every CircleCI worker, and this step will not be needed.
135+
1. Next, each job runs the `setup-bazel-remote-cache` anchor. This starts up the proxy running in the background. In the CircleCI UI, you'll see this step continues running while later steps run, and you can see logging from the proxy process.
136+
1. Bazel must be configured to connect to the proxy on a local port. This configuration lives in `.circleci/bazel.rc` and is enabled because we overwrite the system Bazel settings in /etc/bazel.bazelrc with this file.
137+
1. Each `bazel` command in `.circleci/config.yml` picks up and uses the caching flags.
138+
115139
## Known issues
116140

117141
### Xcode

tools/bazel.rc

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -41,11 +41,8 @@ test --test_output=errors
4141
build --experimental_ui
4242
test --experimental_ui
4343

44-
# Don't be spammy in the continuous integration logs
45-
build:ci --noshow_progress
44+
################################
45+
# Settings for CircleCI #
46+
################################
4647

47-
# Don't run manual tests on CI
48-
test:ci --test_tag_filters=-manual
49-
50-
# Retry in the event of flakes, eg. https://circleci.com/gh/angular/angular/31309
51-
test:ci --flaky_test_attempts=2
48+
# Bazel flags for CircleCI are in /.circleci/bazel.rc

0 commit comments

Comments
 (0)