Skip to content

Commit

Permalink
Loop over bazel versions in build script.
Browse files Browse the repository at this point in the history
There’s too much cache thrashing on GitHub due to large action caches.  Instead
of trying to parallelize runs using the GitHub matrix, run them sequentially to
lower the number of caches.

Since the GitHub runners don’t have enough disk space for a full Cartesian
product, only use the default Emacs toolchain for non-default Bazel versions and
vice versa.  This should still provide enough coverage.
  • Loading branch information
phst committed Apr 15, 2024
1 parent 2c000f7 commit 4a6199e
Show file tree
Hide file tree
Showing 5 changed files with 56 additions and 46 deletions.
23 changes: 2 additions & 21 deletions .github/actions/set-up/action.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,6 @@ name: Set up Bazel workspace
description: Install necessary dependencies and load remote caches

inputs:
bazel-version:
description: Bazel version to use
required: true
github-token:
description: GitHub authentication token from secrets.GITHUB_TOKEN
required: true
Expand Down Expand Up @@ -84,10 +81,9 @@ runs:
uses: actions/cache@v4
with:
path: ${{runner.temp}}/bazel-action-cache
key: bazel-actions-${{runner.os}}-${{inputs.bazel-version}}-${{inputs.cc}}-${{hashFiles('**')}}
key: bazel-actions-${{runner.os}}-${{inputs.cc}}-${{hashFiles('**')}}
restore-keys: |
bazel-actions-${{runner.os}}-${{inputs.bazel-version}}-${{inputs.cc}}-
bazel-actions-${{runner.os}}-${{inputs.bazel-version}}-
bazel-actions-${{runner.os}}-${{inputs.cc}}-
bazel-actions-${{runner.os}}-
- name: Configure system (all platforms)
shell: bash
Expand Down Expand Up @@ -116,7 +112,6 @@ runs:
# Use the Unix toolchain only on Github to make coverage generation work
# locally; see https://github.com/bazelbuild/bazel/issues/14970.
cat >> "${GITHUB_ENV:?}" <<'EOF'
USE_BAZEL_VERSION=${{inputs.bazel-version}}
BAZELISK_GITHUB_TOKEN=${{inputs.github-token}}
BAZEL_USE_CPP_ONLY_TOOLCHAIN=1
CC=${{inputs.cc}}
Expand All @@ -126,17 +121,3 @@ runs:
# using git_override.
git config --global core.autocrlf false
git config --global core.eol lf
- name: Enable Build without the Bytes
shell: bash
run: >-
echo 'common --remote_download_minimal' >> github.bazelrc
# Don’t enable Build without the Bytes in Bazel versions affected by
# https://github.com/bazelbuild/bazel/issues/19143 and
# https://github.com/bazelbuild/bazel/issues/20408. We can enable it
# unconditionally once we drop support for these versions.
if: >-
!startsWith(inputs.bazel-version, '6.') ||
!(
startsWith(inputs.bazel-version, '6.3.') ||
startsWith(inputs.bazel-version, '6.4.')
)
20 changes: 4 additions & 16 deletions .github/workflows/bazel-test.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -27,9 +27,9 @@ jobs:
name: Test
strategy:
matrix:
# We don’t use the GitHub matrix support for the Emacs toolchain to
# allow Bazel to cache intermediate results between the test runs.
bazel: [6.3.2, 6.5.0, 7.1.1, latest]
# We don’t use the GitHub matrix support for the Emacs toolchain and the
# Bazel version to allow Bazel to cache intermediate results between the
# test runs.
os: [ubuntu-latest, macos-latest, windows-latest]
cc: [gcc, clang, msvc]
exclude:
Expand All @@ -54,27 +54,15 @@ jobs:
- name: Set up workspace
uses: ./.github/actions/set-up
with:
bazel-version: ${{matrix.bazel}}
cc: ${{matrix.cc}}
github-token: ${{secrets.GITHUB_TOKEN}}
- name: Set lockfile mode
# The lockfile format differs between the Bazel versions, so only for
# one version --lockfile_mode=error can work. --lockfile_mode=update
# would be useless since we never use the updated lockfiles, so switch
# lockfiles off entirely in other Bazel versions.
shell: bash
run: >-
echo common
--lockfile_mode=${{matrix.bazel == 'latest' && 'error' || 'off'}}>>
github.bazelrc
- name: Run Bazel tests
shell: pwsh
run: python build.py --profiles='${{runner.temp}}/profiles' -- check
- name: Upload profiles
uses: actions/upload-artifact@v4
with:
name: >-
profiles for Bazel version ${{matrix.bazel}} on ${{runner.os}}
compiled with ${{matrix.cc}}
profiles on ${{runner.os}} compiled with ${{matrix.cc}}
path: ${{runner.temp}}/profiles/*.json.gz
if-no-files-found: ignore
1 change: 0 additions & 1 deletion .github/workflows/debug-cache.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,6 @@ jobs:
- name: Set up workspace
uses: ./.github/actions/set-up
with:
bazel-version: latest
github-token: ${{secrets.GITHUB_TOKEN}}
- name: Build Emacs
shell: pwsh
Expand Down
1 change: 0 additions & 1 deletion .github/workflows/update-lockfiles.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,6 @@ jobs:
- name: Set up workspace
uses: ./.github/actions/set-up
with:
bazel-version: latest
github-token: ${{secrets.GITHUB_TOKEN}}
- name: Regenerate lockfiles
shell: pwsh
Expand Down
57 changes: 50 additions & 7 deletions build.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,13 @@
Mimics a trivial version of Make."""

import argparse
from collections.abc import Callable, Iterable, Sequence
from collections.abc import Callable, Iterable, Mapping, Sequence
import functools
import io
import os
import pathlib
import platform
import re
import shlex
import shutil
import subprocess
Expand All @@ -46,21 +48,26 @@ def wrapper(self: 'Builder') -> None:


def _run(args: Sequence[str | pathlib.Path], *,
cwd: Optional[pathlib.Path] = None) -> None:
cwd: Optional[pathlib.Path] = None,
env: Optional[Mapping[str, str]] = None) -> None:
if cwd:
print('cd', shlex.quote(str(cwd)), '&&', end=' ')
env = env or None
if env is not None:
print(*(f'{k}={shlex.quote(v)}' for k, v in env.items()), end=' ')
env = dict(os.environ, **env)
print(_quote(args))
subprocess.run(args, check=True, cwd=cwd)
subprocess.run(args, check=True, cwd=cwd, env=env)


class Builder:
"""Builds the project."""

def __init__(self, *,
profiles: Optional[pathlib.Path]) -> None:
bazel = shutil.which('bazelisk') or shutil.which('bazel')
bazel = shutil.which('bazelisk')
if not bazel:
raise FileNotFoundError('neither Bazelisk nor Bazel found')
raise FileNotFoundError('Bazelisk not found')
self._bazel = pathlib.Path(bazel)
self._profiles = profiles
self._github = os.getenv('CI') == 'true'
Expand Down Expand Up @@ -91,6 +98,7 @@ def check(self) -> None:
# Test both default toolchain and versioned toolchains.
self.test()
self.versions()
self.bazels()
self.ext()

@target
Expand Down Expand Up @@ -140,8 +148,35 @@ def versions(self) -> None:
self._test(f'--extra_toolchains=//elisp:emacs_{version}_toolchain',
profile=version)

@target
def bazels(self) -> None:
"""Runs the Bazel tests for all supported Bazel versions."""
for version in sorted(_BAZEL_VERSIONS):
self._test(profile=f'bazel-{version}', bazel_version=version)

def _test(self, *args: str, profile: str,
cwd: Optional[pathlib.Path] = None) -> None:
cwd: Optional[pathlib.Path] = None,
bazel_version: str = 'latest') -> None:
# The lockfile format differs between the Bazel versions, so only for
# one version --lockfile_mode=error can work. --lockfile_mode=update
# would be useless on GitHub since we never use the updated lockfiles,
# so switch lockfiles off entirely in other Bazel versions.
if bazel_version == 'latest':
# Assume Bazel that’s new enough.
bzlmod = True
bwtb = True
lockfile_mode = 'error'
else:
match = re.match(r'(\d+)\.(\d+)', bazel_version, re.ASCII)
if not match:
raise ValueError(f'invalid version string {bazel_version}')
version = (int(match[1]), int(match[2]))
# Don’t enable Build without the Bytes in Bazel versions affected by
# https://github.com/bazelbuild/bazel/issues/19143 and
# https://github.com/bazelbuild/bazel/issues/20408. We can enable
# it unconditionally once we drop support for these versions.
bwtb = version >= (6, 5)
lockfile_mode = 'off'
for bzlmod in (True, False):
prefix = '' if bzlmod else 'no'
options = [f'--{prefix}enable_bzlmod']
Expand All @@ -153,8 +188,13 @@ def _test(self, *args: str, profile: str,
'--experimental_announce_profile_path',
'--profile=' + str(profile_file),
]
if bwtb and self._github:
options.append('--remote_download_minimal')
if lockfile_mode and self._github:
options.append(f'--lockfile_mode={lockfile_mode}')
options.extend(args)
_run([self._bazel, 'test'] + options + ['--', '//...'], cwd=cwd)
_run([self._bazel, 'test'] + options + ['--', '//...'], cwd=cwd,
env={'USE_BAZEL_VERSION': bazel_version})

@target
def ext(self) -> None:
Expand All @@ -176,6 +216,9 @@ def lock(self) -> None:
# All potentially supported Emacs versions.
_VERSIONS = frozenset({'28.1', '28.2', '29.1', '29.2', '29.3'})

# Selection of supported Bazel versions.
_BAZEL_VERSIONS = frozenset({'6.3.2', '6.5.0', '7.1.1', 'latest'})


def main() -> None:
"""Builds the project."""
Expand Down

0 comments on commit 4a6199e

Please sign in to comment.