build(release): use BuildBuddy RBE for release artifact builds (#4293) Speed up release deliverable and wheel builds and stream invocation results to BuildBuddy BES. Configure the local setup-bazel action to enable `buildbuddy_presubmit` on pull requests and `buildbuddy_postsubmit` on postsubmit runs when a BuildBuddy API key is provided, writing the key directly to `user.bazelrc` via `github-script` to keep it out of environment variables and process tables. Pass the CAS-only key on pull requests and the read+write key on postsubmit runs. For now, only use RBE for linux builds. While BuildBuddy supports Mac/Windows, something with our configuration is causing them to fail.
diff --git a/.github/actions/setup-bazel/action.yaml b/.github/actions/setup-bazel/action.yaml index 60aa1d1..2938ca3 100644 --- a/.github/actions/setup-bazel/action.yaml +++ b/.github/actions/setup-bazel/action.yaml
@@ -1,6 +1,16 @@ name: "Setup Bazel" description: "Configure Bazel with caching for GitHub Actions workflows" +inputs: + buildbuddy_api_key: + description: "BuildBuddy API key to use" + required: false + default: "" + buildbuddy_config: + description: "BuildBuddy config to enable when buildbuddy_api_key is set" + required: false + default: ${{ github.event_name == 'pull_request' && 'buildbuddy_presubmit' || 'buildbuddy_postsubmit' }} + runs: using: "composite" steps: @@ -26,6 +36,8 @@ # pyrefly toolchain or type-check targets before running them. build --output_groups=-pyrefly build --//python/config_settings:py_pbs_distribution=install_only_stripped + # BuildBuddy RBE workers are Linux x86_64; only enable on Linux. + ${{ runner.os == 'Linux' && inputs.buildbuddy_api_key && format('common --config={0}', inputs.buildbuddy_config) || '' }} # setup-bazel only configures Bazelisk and restores caches; the Bazel # binary itself is downloaded by Bazelisk on first invocation. Because @@ -34,3 +46,17 @@ - name: Download Bazel shell: bash run: "${GITHUB_ACTION_PATH}/download_bazel.sh" + + # Use github-script to write the key directly to user.bazelrc without + # passing it via environment variables or CLI args, keeping it out of + # process tables and child environments. + - name: Write secret to user.bazelrc + if: ${{ runner.os == 'Linux' && inputs.buildbuddy_api_key != '' }} + uses: actions/github-script@v7 + with: + script: | + const fs = require('fs'); + fs.appendFileSync( + 'user.bazelrc', + `common:${{ inputs.buildbuddy_config }} --remote_header=x-buildbuddy-api-key=${{ inputs.buildbuddy_api_key }}\n`, + );
diff --git a/.github/workflows/release_build_artifacts.yaml b/.github/workflows/release_build_artifacts.yaml index 0c254ef..ca2cdcd 100644 --- a/.github/workflows/release_build_artifacts.yaml +++ b/.github/workflows/release_build_artifacts.yaml
@@ -82,6 +82,12 @@ - name: Setup Bazel uses: ./.github/actions/setup-bazel + with: + buildbuddy_api_key: >- + ${{ github.event_name == 'pull_request' + && secrets.BUILDBUDDY_CAS_ONLY_KEY + || (github.event_name != 'pull_request' && secrets.BUILDBUDDY_READ_WRITE_KEY) + || '' }} # Release commands run main's workflows, even for patch releases of older # release branches. Skip refs without dev/platforms, since their scripts @@ -123,6 +129,12 @@ - name: Setup Bazel uses: ./.github/actions/setup-bazel + with: + buildbuddy_api_key: >- + ${{ github.event_name == 'pull_request' + && secrets.BUILDBUDDY_CAS_ONLY_KEY + || (github.event_name != 'pull_request' && secrets.BUILDBUDDY_READ_WRITE_KEY) + || '' }} - name: Build runfiles wheel run: >-
diff --git a/.github/workflows/release_publish.yaml b/.github/workflows/release_publish.yaml index 2209e67..0e17bbb 100644 --- a/.github/workflows/release_publish.yaml +++ b/.github/workflows/release_publish.yaml
@@ -57,6 +57,7 @@ uses: ./.github/workflows/release_build_artifacts.yaml with: ref: ${{ inputs.tag_name || github.ref_name }} + secrets: inherit release: name: Release
diff --git a/tests/workflows/release_build_artifacts_test.py b/tests/workflows/release_build_artifacts_test.py index 7f89a30..c3306b2 100644 --- a/tests/workflows/release_build_artifacts_test.py +++ b/tests/workflows/release_build_artifacts_test.py
@@ -73,6 +73,21 @@ ) +def test_build_jobs_use_buildbuddy_rbe(): + """Verifies that build jobs pass BuildBuddy keys to setup-bazel.""" + workflow = _load_workflow() + + for job_name in ("build", "build_wheel"): + job = workflow["jobs"][job_name] + steps = job["steps"] + setup_steps = [s for s in steps if s.get("name") == "Setup Bazel"] + assert len(setup_steps) == 1, f"Missing Setup Bazel in {job_name}" + assert setup_steps[0]["uses"] == "./.github/actions/setup-bazel" + api_key = setup_steps[0]["with"]["buildbuddy_api_key"] + assert "secrets.BUILDBUDDY_CAS_ONLY_KEY" in api_key + assert "secrets.BUILDBUDDY_READ_WRITE_KEY" in api_key + + def test_create_archive_and_notes_fetches_and_expands_tag(tmp_path: Path): """Verifies create_archive_and_notes.sh fetches missing tags and expands export-subst.""" script = (
diff --git a/tests/workflows/setup_bazel_test.py b/tests/workflows/setup_bazel_test.py index 951b9a8..335c53e 100644 --- a/tests/workflows/setup_bazel_test.py +++ b/tests/workflows/setup_bazel_test.py
@@ -40,6 +40,18 @@ assert any("download_bazel.sh" in step.get("run", "") for step in steps) +def test_action_yaml_enables_buildbuddy_only_on_linux(): + """Verifies setup-bazel action.yaml only enables BuildBuddy on Linux.""" + action = yaml.safe_load((_action_dir() / "action.yaml").read_text(encoding="utf-8")) + steps = action["runs"]["steps"] + setup_step = next(s for s in steps if s.get("name") == "Setup Bazel") + assert "runner.os == 'Linux'" in setup_step["with"]["bazelrc"] + secret_step = next( + s for s in steps if s.get("name") == "Write secret to user.bazelrc" + ) + assert "runner.os == 'Linux'" in secret_step["if"] + + def test_download_bazel_succeeds_first_try(tmp_path: Path): """Verifies download_bazel.sh succeeds without warnings when bazel --version succeeds.""" script = _action_dir() / "download_bazel.sh"