Files
carbon-lang/.github/workflows/tests.yaml
T
Chandler Carruth 07cee1b82a Switch to the Bazel disk cache (locally and in CI). (#579)
The Bazel disk cache provides a stable, durable, and supported
persistent cache of the intermediate steps of Bazel builds. This is like
`ccache` but covering more steps and more reliable.

It is based on the same fundamental infrastructure that enables
a *remote* build cache, and at some point we may want to enable that so
that our CI can pre-seed a cache for users. But for now, this just
enables local support for this.

For local builds this will ensure that intermediate artifacts are
re-used when changing branches, syncing, across Bazel server restarts or
even upgrades. It should dramatically reduce the need to re-build large
and slow components like all of Clang and LLVM. Largely, those should
only be rebuilt when we update our pinned revision of upstream and then
cached persistently on a given machine. Enabling this by default
requires hard-coding a path, and so I've also added built-in support for
importing a user config file if present so that folks can customize this
(and any other Bazel features) as desired.

This also wires the disk cache up for the GitHub cache in our CI. By
using the designated Bazel disk cache for this, we get a *much* simpler
and *much* more robust solution. So much so that I've re-arranged the
key structure so we can more aggressively re-use old caches. The only
downside is that nothing ever gets removed automatically from the cache.
I've added a layer that will trim any unused file roughly once a day.

For CI, the benefits of this are huge. None of the previous hacks are
needed to locate and preserve the cache. The design of the cache is
deeply durable and so we don't need to aggressively invalidate it. Last
but not least, it focuses the cache on the raw artifacts, which compress
exceptionally well. With the other changes to shrink the build outputs
and this one combined, I expect we will be able to enable all of the
build targets across all four config/os combinations without any
significant pressure on our space quota for GitHub action caches.
2021-06-16 16:25:52 -07:00

172 lines
6.3 KiB
YAML

# Part of the Carbon Language project, under the Apache License v2.0 with LLVM
# Exceptions. See /LICENSE for license information.
# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
name: test
on:
push:
branches: [trunk]
paths:
# Conservatively run the tests. However, skip them if the only paths in
# the pull request match files that we know don't impact the build.
- '**'
- '!**/*.md'
- '!LICENSE'
- '!CODEOWNERS'
- '!.git*'
pull_request:
paths:
# Conservatively run the tests. However, skip them if the only paths in
# the pull request match files that we know don't impact the build.
- '**'
- '!**/*.md'
- '!LICENSE'
- '!CODEOWNERS'
- '!.git*'
jobs:
test:
strategy:
matrix:
os: [ubuntu-latest, macos-latest]
build_mode: [fastbuild, opt]
runs-on: ${{ matrix.os }}
steps:
- name: Create environment variables
run: |
echo "BAZEL_DISK_CACHE_PATH=$HOME/.cache/carbon-lang-build-cache" >> $GITHUB_ENV
- name: Checkout
uses: actions/checkout@v2
with:
submodules: true
# Setup Python and related tools.
- uses: actions/setup-python@v2
with:
# Match the min version listed in docs/project/contribution_tools.md
python-version: '3.6'
# On macOS we need Go and to use it to install Bazelisk.
- uses: actions/setup-go@v2
if: matrix.os == 'macos-latest'
- name: Install bazelisk
if: matrix.os == 'macos-latest'
run: |
go get github.com/bazelbuild/bazelisk
echo "$(go env GOPATH)/bin" >> $GITHUB_PATH
# Setup to the latest LLVM and Clang release on Linux runners.
#
# Ideally we would use the pre-installed versions in the image, but the
# debian packages for LLVM-12 are broken due to several bugs:
# https://bugs.llvm.org/show_bug.cgi?id=43604
# https://bugs.llvm.org/show_bug.cgi?id=46321
#
# For now, we rely on Homebrew to manage installing a correctly built
# toolchain. We also take some care to be as resilient as possible to
# issues fetching and installing the toolchain.
- name: Setup LLVM and Clang on Ubuntu
if: matrix.os == 'ubuntu-latest'
run: |
brew update
brew install --force-bottle --only-dependencies llvm
brew install --force-bottle --force --verbose llvm
brew info llvm
brew config
echo "$(brew --prefix llvm)/bin" >> $GITHUB_PATH
# Just add the Homebrew installed LLVM to the path on macOS, the image has
# LLVM-12 pre-installed.
- name: Setup LLVM and Clang on macOS
if: matrix.os == 'macos-latest'
run: |
echo "$(brew --prefix llvm)/bin" >> $GITHUB_PATH
# Print the various tool paths and versions to help in debugging.
- name: Print tool debugging info
run: |
echo $PATH
which bazelisk
bazelisk --version
which python
python --version
which clang
clang --version
which clang++
clang++ --version
which clang-format
clang-format --version
# Make the date available to subsequent steps.
- name: Get date
id: date
shell: bash
run: |
echo "::set-output name=date::$(/bin/date -u "+%Y%m%d")"
# Preserve and restore the Bazel cache across builds.
- name: Cache Bazel build data
uses: actions/cache@v2
with:
path: |
${{ env.BAZEL_DISK_CACHE_PATH }}
# The `bazel-1` string here and below in the key acts as a counter
# that can be incremented to rebase the cache in the event of
# persistent corruption or other rare bug. The `-1-` prefix to the
# date can be incremented when adding new targets or updating this
# configuration and a new cache should be created but there is no
# reason to discard prior caches.
key: |
bazel-1-${{ matrix.os }}-${{ matrix.build_mode }}-1-${{ steps.date.outputs.date }}
# When we get a cache miss, try finding the most recent previous day's
# cache to start.
restore-keys: |
bazel-1-${{ matrix.os }}-${{ matrix.build_mode }}-
# Reset all the access-times for the bazel disk cache to 1984. We really
# just need a time far in the past to ensure even with `relatime` or
# similar, the filesystem will track how much of the disk cache is
# actually still *used* in the course of the build. This lets us GC
# anything unused before potentially creating a new cache entry.
- name: Reset Bazel disk cache atimes
run: |
mkdir -p ${{ env.BAZEL_DISK_CACHE_PATH }}
find ${{ env.BAZEL_DISK_CACHE_PATH }}/ -type f -exec touch -a -t 198401010000 '{}' '+'
# Print Bazel diagnostics to make debugging easier.
- name: Print Bazel info
run: |
bazelisk info
# Build all targets first to isolate build failures.
- name: Build (${{ matrix.build_mode }})
run: |
bazelisk build -c ${{ matrix.build_mode }} --verbose_failures \
--deleted_packages=migrate_cpp,migrate_cpp/cpp_refactoring \
//...:all
# Run all test targets.
- name: Test (${{ matrix.build_mode }})
run: |
bazelisk test -c ${{ matrix.build_mode }} --test_output errors \
--deleted_packages=migrate_cpp,migrate_cpp/cpp_refactoring \
--verbose_failures //...:all
# We manually shut down the Bazel server to make sure the cached files
# don't interact with it.
- name: Shutdown Bazel
run: |
bazelisk shutdown
# Since we reset the `atime`s of the disk cache to ancient history,
# everything that ended up accessed by the build and test should have a
# recent `atime`. Delete any files whose `atime` is more than 7 days old.
# We print some statistics to try to help with any debugging later on.
- name: Remove unused disk cache files
run: |
find ${{ env.BAZEL_DISK_CACHE_PATH }}/ -type f | wc -l
find ${{ env.BAZEL_DISK_CACHE_PATH }}/ -type f -atime +7 | wc -l
find ${{ env.BAZEL_DISK_CACHE_PATH }}/ -type f -atime +7 -delete