Skip to content

Remove the Kotlin implementation; the Rust CLI is now the only one #1318

Remove the Kotlin implementation; the Rust CLI is now the only one

Remove the Kotlin implementation; the Rust CLI is now the only one #1318

Workflow file for this run

name: CI
on:
push:
branches: [ master ]
pull_request:
branches: [ master ]
# Job ids and display names are load-bearing: branch protection on master
# requires them by name (`Rust candidate (Bazel 8.x)`, `test-jre21 (...)`,
# `test-jre11-run-example (...)`, `release-artifacts (...)`). Several predate
# the Kotlin implementation's removal and no longer describe what they run;
# rename them only together with the branch-protection rule.
jobs:
# Every Rust check here runs through Bazel, with no cargo and no host Rust
# toolchain: rules_rust downloads the compiler pinned in MODULE.bazel, so CI
# and a local `bazel test` agree on the exact rustc. //:rust_clippy_check and
# //:rust_format_check below stand in for `cargo clippy -- -D warnings` and
# `cargo fmt --all -- --check`. //tools/... is the Python/Go release, e2e-split
# and coverage tooling.
rust-candidate:
name: Rust candidate (Bazel ${{ matrix.bazel }})
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
bazel: ['8.x', '9.x']
steps:
- name: Setup Go environment
uses: actions/setup-go@v5
with:
go-version: ^1.17
- name: Setup Bazelisk
# Retries guard against transient proxy.golang.org/sum.golang.org module-fetch errors.
run: |
for i in 1 2 3; do
go install github.com/bazelbuild/bazelisk@latest && break
echo "bazelisk install failed (attempt $i); retrying in 10s..."
sleep 10
done
- uses: actions/checkout@v4
- name: Check Bazel build and tests
env:
USE_BAZEL_VERSION: ${{ matrix.bazel }}
CARGO_BAZEL_ISOLATED: 'false'
run: ~/go/bin/bazelisk test //:rust_tests //:rust_clippy_check //:rust_format_check //tools/... --enable_bzlmod=true --enable_workspace=false
rust-candidate-e2e:
name: Rust candidate E2E
runs-on: ubuntu-latest
steps:
# bazel-diff itself needs no JDK, but the suite drives a nested Bazel over
# fixture workspaces with Java targets, and Bazel's default
# --java_runtime_version=local_jdk wants a host JDK for those.
- name: Setup Java JDK
uses: actions/setup-java@v4
with:
distribution: 'temurin'
java-version: '21'
- name: Setup Go environment
uses: actions/setup-go@v5
with:
go-version: ^1.17
- name: Setup Bazelisk
# $BAZEL is the nested Bazel //tests:e2e_test spawns for each fixture
# workspace. Set explicitly because the fallback -- first `bazel` on
# PATH -- resolves to the *outer* Bazel's own binary inside a test,
# which ignores USE_BAZEL_VERSION. It reaches the test through the
# target's env_inherit.
run: |
for i in 1 2 3; do
go install github.com/bazelbuild/bazelisk@latest && break
echo "bazelisk install failed (attempt $i); retrying in 10s..."
sleep 10
done
echo "$(go env GOPATH)/bin" >> "$GITHUB_PATH"
echo "BAZEL=$(go env GOPATH)/bin/bazelisk" >> "$GITHUB_ENV"
- uses: actions/checkout@v4
- name: Run native behavioral suite
env:
# Read twice: by the outer bazelisk, and by the nested one.
USE_BAZEL_VERSION: '8.x'
run: bazelisk test //tests:e2e_test --enable_bzlmod=true --enable_workspace=false
# The e2e suites are split into one Bazel test target per case by
# //tools/e2e:regen, whose output is checked in. This job is the gate that
# keeps the checked-in split honest: :regen_check re-derives the case list
# from the sources and fails when they differ, so an e2e test added, renamed
# or removed without `make regen-e2e` cannot merge.
# :split_e2e_tests_test covers the generator itself.
e2e-split-regen:
name: E2E split regen
runs-on: ubuntu-latest
steps:
- name: Setup Go environment
uses: actions/setup-go@v5
with:
go-version: ^1.17
- name: Setup Bazelisk
# Retries guard against transient proxy.golang.org/sum.golang.org module-fetch errors.
run: |
for i in 1 2 3; do
go install github.com/bazelbuild/bazelisk@latest && break
echo "bazelisk install failed (attempt $i); retrying in 10s..."
sleep 10
done
- uses: actions/checkout@v4
- name: Check the e2e test split is up to date
env:
USE_BAZEL_VERSION: '8.x'
run: ~/go/bin/bazelisk test //tools/e2e:regen_check //tools/e2e:split_e2e_tests_test --enable_bzlmod=true --enable_workspace=false --test_output=errors
rust-candidate-msrv:
name: Rust candidate MSRV
runs-on: ubuntu-latest
steps:
- name: Setup Go environment
uses: actions/setup-go@v5
with:
go-version: ^1.17
- name: Setup Bazelisk
# Retries guard against transient proxy.golang.org/sum.golang.org module-fetch errors.
run: |
for i in 1 2 3; do
go install github.com/bazelbuild/bazelisk@latest && break
echo "bazelisk install failed (attempt $i); retrying in 10s..."
sleep 10
done
- uses: actions/checkout@v4
# Builds the crate with the toolchain pinned to `rust-version` in
# Cargo.toml instead of the repo default. --extra_toolchains outranks the
# registered toolchains, which is what makes the swap take: the MSRV
# toolchain is declared in MODULE.bazel but deliberately not preferred.
# Bazel has no `cargo check` equivalent, so this is a full build -- which
# is strictly stronger, since it links as well as type-checks.
#
# The lint output groups are dropped because this job asks one question:
# does the crate still compile on the oldest Rust it claims to support.
# 1.85's clippy has a different lint set than the pinned toolchain's, so
# leaving them on would fail this job for warnings that say nothing about
# MSRV. //:rust_clippy_check and //:rust_format_check own that gate.
- name: Check declared minimum Rust version
env:
USE_BAZEL_VERSION: '8.x'
run: |
~/go/bin/bazelisk build //src:bazel-diff \
--extra_toolchains=@rust_toolchains//:rust_msrv__x86_64-unknown-linux-gnu__stable \
--output_groups=-clippy_checks,-rustfmt_checks \
--enable_bzlmod=true --enable_workspace=false
# The coverage gate. The job id is historical (it used to run the JVM suites
# on a JDK 21) and is kept because branch protection requires the
# `test-jre21 (<os>, <bazel>)` checks by that name.
test-jre21:
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
include:
- os: ubuntu-latest
bazel: '8.x'
- os: ubuntu-latest
bazel: '9.x'
- os: macos-latest
bazel: '8.x'
- os: macos-latest
bazel: '9.x'
steps:
- name: Setup Go environment
uses: actions/setup-go@v5
with:
go-version: ^1.17
id: go
- name: Setup Bazelisk
# Retries guard against transient proxy.golang.org/sum.golang.org module-fetch errors.
run: |
for i in 1 2 3; do
go install github.com/bazelbuild/bazelisk@latest && break
echo "bazelisk install failed (attempt $i); retrying in 10s..."
sleep 10
done
export PATH=$PATH:$(go env GOPATH)/bin
- uses: actions/checkout@v4
- name: Build license target
env:
USE_BAZEL_VERSION: ${{ matrix.bazel }}
run: ~/go/bin/bazelisk build //:license --enable_bzlmod=true --enable_workspace=false
- name: Run bazel-diff tests with coverage
env:
USE_BAZEL_VERSION: ${{ matrix.bazel }}
# Retries guard against transient toolchain/crate fetch errors failing the whole job.
run: |
for i in 1 2 3; do
~/go/bin/bazelisk coverage --combined_report=lcov //src:cli_tests //src:rust_tests //tools:coverage_check_test //tools/coverage/... //tools/go/... --enable_bzlmod=true --enable_workspace=false && break
if [ "$i" = 3 ]; then exit 1; fi
echo "coverage run failed (attempt $i); retrying in 15s..."
sleep 15
done
- name: Upload coverage report
uses: actions/upload-artifact@v4
if: always()
with:
name: coverage-report-jre21-${{ matrix.os }}-bazel-${{ matrix.bazel }}
path: bazel-out/_coverage/_coverage_report.dat
if-no-files-found: warn
- name: Enforce coverage threshold (>= 90% main-source line coverage)
env:
# Must match the coverage step above, otherwise bazelisk downloads the
# default bazel from .bazelversion and starts a fresh server whose
# output base loses track of the coverage report symlink (seen flaking
# on macos-latest x bazel 9.x).
USE_BAZEL_VERSION: ${{ matrix.bazel }}
COVERAGE_THRESHOLD: '90'
run: ~/go/bin/bazelisk run //tools:coverage-check -- --badge-json coverage.json bazel-out/_coverage/_coverage_report.dat
- name: Enforce Go coverage threshold (>= 90% line coverage under tools/go/)
env:
# Must match the coverage step above; see the note on the previous step.
USE_BAZEL_VERSION: ${{ matrix.bazel }}
# Gate Go independently of the Rust overall so thin Go coverage can't hide
# behind well-covered Rust (and vice versa). --include scopes the report to
# Go production source only (tools/go/, which excludes tools/coverage_check.py).
run: ~/go/bin/bazelisk run //tools:coverage-check -- --include tools/go/ --threshold 90 bazel-out/_coverage/_coverage_report.dat
- name: Upload test logs
uses: actions/upload-artifact@v4
if: always()
with:
name: test-logs-jre21-${{ matrix.os }}-bazel-${{ matrix.bazel }}
path: bazel-testlogs/
if-no-files-found: warn
# Runs the example script end to end against this repository, on every Bazel
# version and workspace mode the tool supports. The job id is historical (the
# JVM CLI was exercised on a JDK 11 here) and is kept because branch protection
# requires the `test-jre11-run-example (...)` checks by that name.
test-jre11-run-example:
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
include:
- os: ubuntu-latest
bazel: '7.x'
disable_workspace: 'false'
extra_flags: ''
- os: ubuntu-latest
bazel: '7.x'
disable_workspace: 'false'
extra_flags: '--incompatible_disable_native_repo_rules'
- os: ubuntu-latest
bazel: '8.x'
disable_workspace: 'true'
extra_flags: ''
- os: ubuntu-latest
bazel: '8.6.0rc1'
disable_workspace: 'true'
extra_flags: ''
- os: ubuntu-latest
bazel: '8.x'
disable_workspace: 'true'
extra_flags: '--incompatible_disable_native_repo_rules'
- os: ubuntu-latest
bazel: '9.x'
disable_workspace: 'true'
extra_flags: ''
- os: ubuntu-latest
bazel: '9.x'
disable_workspace: 'true'
extra_flags: '--incompatible_disable_native_repo_rules'
# Skip Windows + Bazel 7.x due to protobuf compilation issues on MSVC
# Windows is tested with Bazel 8.x and 9.x which are more current
- os: windows-latest
bazel: '8.x'
disable_workspace: 'true'
extra_flags: ''
- os: windows-latest
bazel: '9.x'
disable_workspace: 'true'
extra_flags: ''
steps:
- name: Setup Go environment
uses: actions/setup-go@v5
with:
go-version: ^1.17
id: go
- name: Setup Bazelisk (Linux/macOS)
if: runner.os != 'Windows'
# Retries guard against transient proxy.golang.org/sum.golang.org module-fetch errors.
run: |
for i in 1 2 3; do
go install github.com/bazelbuild/bazelisk@latest && break
echo "bazelisk install failed (attempt $i); retrying in 10s..."
sleep 10
done
export PATH=$PATH:$(go env GOPATH)/bin
- name: Setup Bazelisk (Windows)
if: runner.os == 'Windows'
shell: pwsh
run: |
for ($i = 1; $i -le 3; $i++) {
go install github.com/bazelbuild/bazelisk@latest
if ($LASTEXITCODE -eq 0) { break }
Write-Host "bazelisk install failed (attempt $i); retrying in 10s..."
Start-Sleep -Seconds 10
}
$env:PATH = "$env:PATH;$(go env GOPATH)\bin"
echo "$env:USERPROFILE\go\bin" | Out-File -FilePath $env:GITHUB_PATH -Encoding utf8 -Append
- uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Run bazel-diff example script (Linux)
if: runner.os != 'Windows'
env:
USE_BAZEL_VERSION: ${{ matrix.bazel }}
BAZEL_DIFF_DISABLE_WORKSPACE: ${{ matrix.disable_workspace }}
BAZEL_DIFF_FORCE_CHECKOUT: true
BAZEL_EXTRA_COMMAND_OPTIONS: ${{ matrix.extra_flags }}
# Retries guard against transient release-asset fetch errors (e.g. a 500 from
# GitHub Releases downloading Bazel module deps).
run: |
for i in 1 2 3; do
./bazel-diff-example.sh "$GITHUB_WORKSPACE" ~/go/bin/bazelisk $(git rev-parse HEAD~1) $(git rev-parse HEAD) && break
if [ "$i" = 3 ]; then exit 1; fi
echo "example script failed (attempt $i); retrying in 15s..."
sleep 15
done
- name: Run bazel-diff example script (Windows)
if: runner.os == 'Windows'
env:
USE_BAZEL_VERSION: ${{ matrix.bazel }}
BAZEL_DIFF_DISABLE_WORKSPACE: ${{ matrix.disable_workspace }}
BAZEL_DIFF_FORCE_CHECKOUT: true
BAZEL_EXTRA_COMMAND_OPTIONS: ${{ matrix.extra_flags }}
shell: pwsh
# Retries guard against transient release-asset fetch errors (e.g. a 500 from
# GitHub Releases downloading Bazel module deps).
run: |
$prevRev = git rev-parse HEAD~1
$currRev = git rev-parse HEAD
for ($i = 1; $i -le 3; $i++) {
.\bazel-diff-example.ps1 -WorkspacePath "$env:GITHUB_WORKSPACE" -BazelPath "$env:USERPROFILE\go\bin\bazelisk.exe" -PreviousRevision $prevRev -FinalRevision $currRev
if ($LASTEXITCODE -eq 0) { break }
if ($i -eq 3) { exit 1 }
Write-Host "example script failed (attempt $i); retrying in 15s..."
Start-Sleep -Seconds 15
}
# Verifies per-PR that everything a release ships still builds, on every
# platform it ships for. It publishes nothing: release.yaml owns that, via
# release_prep.sh (source archive) and its rust-binaries matrix. This
# job predates that flow -- it used to *be* the deploy -- so its uploads are
# a build check whose output happens to be downloadable, nothing more.
release-artifacts:
# Explicit name so the status check is stable. Left implicit, GitHub derives
# it from every matrix value -- which is how branch protection ended up
# requiring `deploy (11)`, a check that stopped existing the moment this job
# grew an os/rust_asset matrix. Adding a matrix key must not rename a check.
name: release-artifacts (${{ matrix.os }})
needs: [test-jre21]
runs-on: ${{ matrix.os }}
permissions:
# Read-only: nothing here attests or publishes. The id-token/attestations
# writes this job used to request were left over from the old deploy.
contents: read
strategy:
fail-fast: false
matrix:
# rust_asset is the name //release:bazel-diff-rust gives the binary on
# that platform -- it is asserted, not applied (see the upload step).
#
# The two Windows-only Bazel flags can't move into --config=release:
# startup flags can't live in a --config at all, and .bazelrc expands
# platform-specific config for the bare `build` config name only.
# bazel_startup_flags shortens the output root because MSVC's link.exe
# is MAX_PATH-bound (260): under the default root, the Rust stdlib path
# ...rust_toolchain\lib\rustlib\x86_64-pc-windows-msvc\lib\
# librustc_std_workspace_alloc-<hash>.rlib comes to 263 characters and
# the link fails with LNK1181. C:/b buys back 35.
#
# release_config is `release-musl` on Linux: the published Linux amd64
# binary is statically linked against musl so it does not inherit the
# runner's glibc as a floor. It is a cross-compile, not a different
# runner, so it stays in this row. The linux-arm64 musl asset is built
# in extra steps on this same job (not a second matrix row) so the
# check name stays `release-artifacts (ubuntu-latest)`. macOS and
# Windows link their platform's own libc and use the plain `release`
# config.
include:
- os: ubuntu-latest
rust_asset: bazel-diff-rust-linux-amd64
release_config: release-musl
bazel_startup_flags: ''
bazel_extra_flags: ''
upload_archive: true
- os: macos-latest
rust_asset: bazel-diff-rust-macos-arm64
release_config: release
bazel_startup_flags: ''
bazel_extra_flags: ''
upload_archive: false
- os: windows-latest
rust_asset: bazel-diff-rust-windows-amd64.exe
release_config: release
bazel_startup_flags: '--output_user_root=C:/b'
bazel_extra_flags: '--legacy_external_runfiles'
upload_archive: false
steps:
- name: Setup Go environment
uses: actions/setup-go@v5
with:
go-version: ^1.17
id: go
- name: Setup Bazelisk (Linux/macOS)
if: runner.os != 'Windows'
# Retries guard against transient proxy.golang.org/sum.golang.org module-fetch errors.
run: |
for i in 1 2 3; do
go install github.com/bazelbuild/bazelisk@latest && break
echo "bazelisk install failed (attempt $i); retrying in 10s..."
sleep 10
done
echo "$(go env GOPATH)/bin" >> "$GITHUB_PATH"
- name: Setup Bazelisk (Windows)
if: runner.os == 'Windows'
shell: pwsh
run: |
for ($i = 1; $i -le 3; $i++) {
go install github.com/bazelbuild/bazelisk@latest
if ($LASTEXITCODE -eq 0) { break }
Write-Host "bazelisk install failed (attempt $i); retrying in 10s..."
Start-Sleep -Seconds 10
}
echo "$(go env GOPATH)\bin" | Out-File -FilePath $env:GITHUB_PATH -Encoding utf8 -Append
- uses: actions/checkout@v4
# The same script release_prep.sh packs the shipped archive with, so this
# check can't pass on an archive the release would not produce. It used to
# call `make release_source_archive`, a second tar recipe that had already
# drifted (no __pycache__/*.pyc excludes).
- name: Build release source archive
if: matrix.upload_archive
run: .github/workflows/pack_release_archive.sh archives/release.tar.gz
- uses: actions/upload-artifact@v4
if: matrix.upload_archive
with:
name: release.tar.gz
path: archives/release.tar.gz
if-no-files-found: error
# //release:bazel-diff-rust names the binary for the platform Bazel built
# it for, so this step neither renames nor relocates anything: whatever
# lands in bazel-bin/release/ is the published asset. matrix.release_config
# carries the flags (see .bazelrc) -- including, on Linux, the musl target
# platform. `if-no-files-found: error` below is the assertion that Bazel's
# name still matches matrix.rust_asset.
- name: Build Rust binary
shell: bash
env:
# Windows runs this under Git bash, whose MSYS runtime rewrites any
# argument starting with `//package` into a `/package` Windows path --
# Bazel then rejects "invalid package name '/release'". (`//:target`
# survived only because it has no path-like segment to convert.)
MSYS2_ARG_CONV_EXCL: '//'
run: bazelisk ${{ matrix.bazel_startup_flags }} build //release:bazel-diff-rust --config=${{ matrix.release_config }} ${{ matrix.bazel_extra_flags }}
- name: Assert Linux binary is statically linked
if: runner.os == 'Linux'
run: .github/workflows/assert_static_binary.sh "bazel-bin/release/${{ matrix.rust_asset }}"
- uses: actions/upload-artifact@v4
with:
name: ${{ matrix.rust_asset }}
path: bazel-bin/release/${{ matrix.rust_asset }}
if-no-files-found: error
# Second published Linux asset, built in this same job so the status check
# stays `release-artifacts (ubuntu-latest)`. A matrix row with the same
# `os` would duplicate that name and break branch protection.
- name: Build Rust binary (linux-arm64 musl)
if: runner.os == 'Linux'
run: bazelisk build //release:bazel-diff-rust --config=release-musl-arm64
- name: Assert Linux arm64 binary is statically linked
if: runner.os == 'Linux'
run: .github/workflows/assert_static_binary.sh bazel-bin/release/bazel-diff-rust-linux-arm64
- uses: actions/upload-artifact@v4
if: runner.os == 'Linux'
with:
name: bazel-diff-rust-linux-arm64
path: bazel-bin/release/bazel-diff-rust-linux-arm64
if-no-files-found: error