Bazel is a build system that was recently open sourced by Google. Bazel operates on configuration files - a WORKSPACE file for your entire project, and then per-directory BUILD.bazel files. These declare all of the dependencies for your project, using a language called Skylark. There are a number of Skylark rules for things like downloading and caching HTTP archives, and language-specific rules.
Anyway there are some gotchas about running Bazel on Travis CI that I wanted to cover, and when I was looking at instructions they weren't great.
1) Install Bazel
The official instructions ask you to add the Bazel apt repository, and then install from there. You can shave a few seconds by only updating that repository, instead of all of them.
echo "deb [arch=amd64] http://storage.googleapis.com/bazel-apt stable jdk1.8" | sudo tee /etc/apt/sources.list.d/bazel.list curl --silent https://bazel.build/bazel-release.pub.gpg | sudo apt-key add - sudo apt-get update -o Dir::Etc::sourcelist="sources.list.d/bazel.list" \ -o Dir::Etc::sourceparts="-" \ -o APT::Get::List-Cleanup="0" sudo apt-get install openjdk-8-jdk bazel
You can shave a few more seconds by just getting and installing the deb
directly, though this requires you to manually update the version number when
Bazel releases a new version. (This is in a Makefile, you'll need to change the
syntax for Bash or a
BAZEL_VERSION := "0.7.0" BAZEL_DEB := "bazel_$(BAZEL_VERSION)_amd64.deb" curl --silent --output /tmp/$(BAZEL_DEB) "https://storage.googleapis.com/bazel-apt/pool/jdk1.8/b/bazel/$(BAZEL_DEB)" sudo dpkg --force-all -i /tmp/$(BAZEL_DEB)
2) Run Tests
Bazel ships with a ton of flags but these are probably the ones you want to know about/use:
--batch: Run in batch mode, as opposed to client-server mode.
--noshow_loading_progress: Travis pretends to be a TTY so it can show colors, but this causes Bazel to dump a whole bunch of progress messages to the screen. It would be nice if you could say "I can handle ANSI escape sequences relating to colors, but not screen redraws" but you only get the binary "I'm a TTY" / "I'm not", which is unfortunate. Anyway these options turn off the "show progress" log spam.
--test_output=errors: By default Bazel logs test failures to a log file. This option will print them to the screen instead.
--features: Enable features specific to a test runner. In particular for Go you may want the
--features=racerule to run tests with the race detector enabled.
3) Cache Results
Bazel is much faster when it can load the intermediate results from a cache; on one library I maintain, tests run in 13 seconds (versus 47 seconds) when they are run with a full cache.
However, the Bazel caches are enormous. Caches for Go tests include the Go binary and source tree, which runs about 95MB alone. Add on other artifacts (including the Java JDK's used to run Bazel) and it's common to see over 200MB. If you are uploading or downloading caches from somewhere like S3, this can be a really slow operation. Also, it's difficult to remove large items from Bazel's cache without removing everything; the file structure makes the cache a little tough to remove parts of.
In particular, Travis's cache does go to S3, which means it skips the local caching proxies Travis sets up for e.g. apt and npm. Travis times out the cache download after 3 minutes, and Bazel quits if the cache is corrupt. In my experience Travis will not complete a 200MB cache download in 3 minutes, so your builds will fail.
For now it's probably best to eat the cold cache startup time. That's really unfortunate though; I hope we can find a better solution in the future. One way may be for Travis to run a local "remote cache", which responds to the WebDAV protocol. This would allow closer caching of Bazel objects.
It would also be nice if Travis had a "language: bazel" mode, which would come with the right version of Bazel installed for you.
Liked what you read? I am available for hire.
Thanks for the write-up!
I recently set up travis for our company (with bazel), and I ran into the same issue with caching bazel’s cache dir on travis. I wanted to ask you if you have come up with any workaround since this article was written?
For now, I just build with no cache, but we have a lot of dependencies so it takes ~20-30 minutes to run travis. It works fine, but it’d really killer to somehow utilize bazel’s caching mechanisms.