chore(deps): update all non-major dependencies #1080
Workflow file for this run
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: CI | |
| on: | |
| push: | |
| branches: [main] | |
| pull_request: | |
| branches: [main] | |
| # Supersede in-flight runs for the same PR; see .claude/CLAUDE.md "Superseding CI runs". | |
| concurrency: | |
| group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.run_id }} | |
| cancel-in-progress: true | |
| permissions: | |
| contents: read | |
| jobs: | |
| gazelle-check: | |
| name: Gazelle BUILD file check | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 | |
| - uses: ./.github/actions/setup-bazel-remote | |
| with: | |
| buildbuddy-api-key: ${{ secrets.BUILDBUDDY_API_KEY }} | |
| - run: bazel run --config=ci //:gazelle -- -mode=diff | |
| # MODULE.bazel.lock is the one derived file with no CI backstop of its own: builds run with | |
| # `--lockfile_mode=update`, which rewrites the lock in memory and stays green, so a `bazel mod | |
| # tidy` hook that never ran is invisible until it blocks someone's commit. Fail-only on | |
| # purpose — the regenerated lock belongs in the authoring commit, not in a CI push. | |
| # | |
| # `bazel mod tidy` also rewrites MODULE.bazel's `use_repo` lines, so both files are diffed. | |
| bazel-lock-check: | |
| name: MODULE.bazel.lock freshness | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 | |
| - uses: ./.github/actions/setup-bazel-remote | |
| with: | |
| buildbuddy-api-key: ${{ secrets.BUILDBUDDY_API_KEY }} | |
| - run: | | |
| set -euo pipefail | |
| # `--config=ci` for consistency with gazelle-check next door. It changes nothing | |
| # here — `mod tidy` executes no actions, so BES and remote execution are moot. | |
| bazel mod tidy --config=ci | |
| if ! git diff --exit-code -- MODULE.bazel MODULE.bazel.lock; then | |
| MSG="stale — run 'bazel mod tidy' and commit the result." | |
| echo "::error file=MODULE.bazel.lock::${MSG}" | |
| exit 1 | |
| fi | |
| echo "MODULE.bazel and MODULE.bazel.lock are what 'bazel mod tidy' produces." | |
| # The repo's `meta/scripts/*.py` target Python 3.14 (matches the rules_python | |
| # toolchain pin in MODULE.bazel and the `target-version` in pyproject.toml's | |
| # [tool.ruff]). Ubuntu-24.04 still ships 3.12 as `python3`, so the language- | |
| # toolchain pin needs to be applied explicitly on every job that runs a script | |
| # outside Bazel. The `# renovate:` comment above each `python-version` is | |
| # picked up by the regex matcher in renovate.json and grouped with the | |
| # MODULE.bazel python_version under "Language toolchain SDKs". | |
| # Polyglot module/project completeness check. Per language (Go, Python): | |
| # config-file reachability + workflow matrix consistency. Python-only: | |
| # root pyproject.toml has the required tool sections, every per-project | |
| # pyproject is covered by [tool.uv.workspace].members, and | |
| # requirements_lock.txt is fresh relative to uv.lock. uv is needed for the | |
| # last check — setup-uv brings both uv and a 3.14 Python interpreter. | |
| modules-check: | |
| name: Module completeness check | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 | |
| - uses: astral-sh/setup-uv@20cfd1bf945f4377ade1205e4dbc17946fc9a30d # v10.0.1 | |
| - uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0 | |
| with: | |
| # renovate: datasource=python-version depName=python | |
| python-version: "3.14" | |
| - run: python3 meta/scripts/check_modules.py | |
| go-work-check: | |
| name: go.work consistency/completeness check | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 | |
| - uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0 | |
| with: | |
| # renovate: datasource=python-version depName=python | |
| python-version: "3.14" | |
| - run: python3 meta/scripts/check_go_work.py | |
| secrets-check: | |
| name: Secrets check | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 | |
| - uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0 | |
| with: | |
| # renovate: datasource=python-version depName=python | |
| python-version: "3.14" | |
| - run: python3 meta/scripts/check_secrets_dir.py | |
| no-cgo-check: | |
| name: No-cgo policy check | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 | |
| - uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0 | |
| with: | |
| # renovate: datasource=python-version depName=python | |
| python-version: "3.14" | |
| # `go list -deps` is what surfaces transitive cgo, so the runner needs Go in PATH. | |
| # Use go.work as the source-of-truth — it's the workspace-level Go version directive | |
| # and matches the version Bazel installs in MODULE.bazel (per-module go.mod files | |
| # only declare each module's minimum, which can drift below the workspace version). | |
| - uses: actions/setup-go@b7ad1dad31e06c5925ef5d2fc7ad053ef454303e # v7.0.0 | |
| with: | |
| go-version-file: go.work | |
| # This step only runs `go list -deps` via check_no_cgo.py — no `go build` | |
| # of our code, no `go mod download`. With cache enabled (the default), | |
| # setup-go searches for go.mod/go.sum at the repo root to build a cache | |
| # key and warns when it can't find them (this is a Bazel monorepo with | |
| # per-module go.mod files, none at the root). | |
| cache: false | |
| - run: python3 meta/scripts/check_no_cgo.py | |
| # TEND(lang-expand): this job lints Go only. When a new language is adopted, add a sibling | |
| # job (e.g. ruff for Python) — do not extend this matrix, the linter is Go-specific. | |
| golangci-lint: | |
| name: golangci-lint (${{ matrix.go_module }}) | |
| runs-on: ubuntu-latest | |
| needs: [modules-check] | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| go_module: | |
| - tools/network_infrastructure_maintenance | |
| steps: | |
| - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 | |
| - uses: golangci/golangci-lint-action@ba0d7d2ec06a0ea1cb5fa41b2e4a3ab91d21278a # v9.3.0 | |
| with: | |
| working-directory: ${{ matrix.go_module }} | |
| # Python's sibling of golangci-lint. Format + lint in one job; config lives in | |
| # `[tool.ruff]` in //:pyproject.toml. Renovate's regex manager tracks the | |
| # version pin via the comment above (matches the Dockerfile pattern). | |
| # TEND(project-expand): repo-wide today because there is no per-project | |
| # tuning. When real Python projects land and want per-project ruff config, | |
| # convert this to a matrix-per-project job (mirroring golangci-lint) and | |
| # add a matching matrix-completeness callsite to check_modules.py keyed off | |
| # a Python matrix key (matrix.module: is currently Go-only). | |
| ruff: | |
| name: ruff | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 | |
| - uses: astral-sh/ruff-action@278981a28ce3188b1e39527901f38254bf3aac89 # v4.1.0 | |
| with: | |
| # renovate: datasource=pypi depName=ruff | |
| version: "0.16.4" | |
| args: format --check | |
| - run: ruff check | |
| # shellcheck: the enforcing half. The editor surfaces the same findings inline on save | |
| # (timonwong.shellcheck, configured in .vscode/settings.json), but nothing blocks a commit on | |
| # them, so this job is where shell lint is actually gated. Scoped to *.sh, which today means | |
| # .devcontainer/'s host stub and lifecycle hooks plus meta/devcontainer-base/scripts/ — | |
| # privileged writes against /etc and host-absolute paths, where `set -e` foot-guns (errexit | |
| # suspension inside `||` callees, most recently) are worth catching mechanically rather than | |
| # in review. | |
| # The version is the devcontainer's, read out of its Dockerfile rather than restated here — | |
| # the runner image ships its own shellcheck, and using it would make the gating job and the | |
| # editor separately versioned, with a finding's presence depending on where you looked. | |
| shellcheck: | |
| name: shellcheck | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 | |
| - name: Install the pinned shellcheck | |
| run: | | |
| set -euo pipefail | |
| version="$(sed -n 's/^ARG SHELLCHECK_VERSION=//p' .devcontainer/Dockerfile)" | |
| # An ARG that moved or got renamed must fail here, not silently fall through to | |
| # whatever the runner image happens to ship. | |
| if [ -z "${version}" ]; then | |
| echo "no SHELLCHECK_VERSION in .devcontainer/Dockerfile" >&2 | |
| exit 1 | |
| fi | |
| curl -fsSL \ | |
| "https://github.com/koalaman/shellcheck/releases/download/${version}/shellcheck-${version}.linux.x86_64.tar.xz" \ | |
| | tar -xJ -C /tmp | |
| # Ahead of the runner's own copy on PATH. | |
| sudo install -m 0755 "/tmp/shellcheck-${version}/shellcheck" /usr/local/bin/shellcheck | |
| # That ordering is an assumption about the runner image, and the whole point of the | |
| # pin is that the gate and the editor cannot disagree — so a shadowed binary has to | |
| # fail here rather than lint green under some other version. | |
| on_path="$(shellcheck --version | sed -n 's/^version: //p')" | |
| if [ "${on_path}" != "${version#v}" ]; then | |
| echo "shellcheck on PATH is ${on_path}, expected ${version#v}" >&2 | |
| exit 1 | |
| fi | |
| - run: | | |
| set -euo pipefail | |
| shellcheck --version | sed -n '2p' | |
| mapfile -t files < <(git ls-files '*.sh') | |
| # shellcheck itself exits 1 on an empty argument list; can't happen today, but a | |
| # future .sh-free tree should report "nothing to check", not a red job. | |
| if [ "${#files[@]}" -eq 0 ]; then | |
| echo "no shell scripts tracked; nothing to check" | |
| exit 0 | |
| fi | |
| printf 'checking %d file(s)\n' "${#files[@]}" | |
| shellcheck "${files[@]}" | |
| # ty: Astral's static type checker. Config lives in `[tool.ty]` in | |
| # //:pyproject.toml — same single-source-of-truth posture as ruff. No | |
| # dedicated GitHub Action exists yet (ty is still alpha), so we install uv | |
| # and run `uvx ty@<pin> check`. The pin is Renovate-tracked via the comment | |
| # above TY_VERSION. | |
| # TEND(project-expand): see the ruff job's TEND — same reasoning. When | |
| # per-project ty config is needed, convert to a matrix-per-project job and | |
| # extend check_modules.py with the matching matrix-completeness callsite. | |
| ty: | |
| name: ty | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 | |
| - uses: astral-sh/setup-uv@20cfd1bf945f4377ade1205e4dbc17946fc9a30d # v10.0.1 | |
| # `uv sync` materializes `.venv` from uv.lock so ty can resolve | |
| # third-party imports (e.g. the smoke target's `requests`). Without it, | |
| # ty's only search paths are first-party + stdlib and any non-stdlib | |
| # import fails with `unresolved-import`. | |
| - run: uv sync | |
| - name: ty check | |
| env: | |
| # renovate: datasource=pypi depName=ty | |
| TY_VERSION: "0.0.74" | |
| run: uvx "ty@${TY_VERSION}" check | |
| # Build and test runs once per supported target platform, on a runner whose host matches | |
| # the target. (Running tests natively per platform is the only way (without an emulation | |
| # layer we do not have) to actually exercise platform-specific code paths and catch regressions | |
| # early.) A failure on any matrix entry blocks the merge because build-and-test-all is a | |
| # required status check. | |
| # | |
| # If a future supported target lacks a matching GitHub-hosted runner, that entry would | |
| # build-only (drop `test`); none of our current targets are in that situation. | |
| build-and-test-per-target: | |
| name: Build and test (${{ matrix.platform }}) | |
| runs-on: ${{ matrix.runner }} | |
| needs: [ | |
| gazelle-check, | |
| modules-check, | |
| go-work-check, | |
| secrets-check, | |
| no-cgo-check, | |
| golangci-lint, | |
| ruff, | |
| ty, | |
| ] | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| include: | |
| - platform: linux_x86_64 | |
| runner: ubuntu-latest | |
| - platform: linux_arm64 | |
| runner: ubuntu-24.04-arm | |
| - platform: darwin_arm64 | |
| runner: macos-latest | |
| steps: | |
| - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 | |
| - uses: ./.github/actions/setup-bazel-remote | |
| with: | |
| buildbuddy-api-key: ${{ secrets.BUILDBUDDY_API_KEY }} | |
| # `--config=ci` brings in remote cache + BES; `--config=<platform>` pins the target | |
| # platform explicitly. Each row's runner matches its target arch — required for | |
| # Python (`@pypi` wheel resolution is host-bound; see | |
| # docs/adr/0001-go-builds-are-pure-python-is-not.md). The matching runner also keeps | |
| # test execution native: BB | |
| # executors of the same arch are registered as candidates via `--config=<platform>`, | |
| # darwin executes on the runner itself since BB has no macOS executors. | |
| - run: bazel test --config=ci --config=${{ matrix.platform }} //... | |
| build-and-test-all: | |
| name: Build and test (all targets) | |
| runs-on: ubuntu-latest | |
| needs: [build-and-test-per-target] | |
| if: always() | |
| steps: | |
| - name: Verify all build-and-test-per-target jobs passed | |
| run: | | |
| if [ "${{ needs.build-and-test-per-target.result }}" != "success" ]; then | |
| echo "build-and-test-all result: ${{ needs.build-and-test-per-target.result }}" | |
| exit 1 | |
| fi | |
| echo "All build-and-test-per-target jobs passed" | |
| coverage: | |
| name: Coverage | |
| runs-on: ubuntu-latest | |
| needs: [build-and-test-all] | |
| steps: | |
| - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 | |
| - uses: ./.github/actions/setup-bazel-remote | |
| with: | |
| buildbuddy-api-key: ${{ secrets.BUILDBUDDY_API_KEY }} | |
| # Coverage-specific flags (--combined_report, --experimental_fetch_all_coverage_outputs, | |
| # --strategy=CoverageReport=local under :remote_bb) live in .bazelrc under the `coverage` | |
| # command scope, so `bazel coverage //...` produces an identical report locally and in CI. | |
| # | |
| # Coverage runs on a single platform (linux_x86_64) by deliberate choice: it measures | |
| # source-line coverage, which is platform-independent for pure-Go code without build | |
| # tags. If we ever introduce platform-conditional code that needs per-target coverage | |
| # measurement, this job would become a matrix like build-and-test. | |
| # | |
| # TEND(lang-expand): `bazel coverage //...` picks up every language whose rules emit | |
| # coverage (rules_go does automatically; rules_python is wired via | |
| # `configure_coverage_tool = True` on `python.toolchain` in MODULE.bazel). When adopting | |
| # a new language, confirm its ruleset is wired into Bazel's coverage collection — e.g. | |
| # rules_java needs JaCoCo. If coverage output is silently missing for a language, | |
| # that's the thing to check. | |
| - run: bazel coverage --config=ci --config=linux_x86_64 //... | |
| - name: Locate merged lcov | |
| id: lcov | |
| run: echo "path=$(bazel info output_path)/_coverage/_coverage_report.dat" >> "$GITHUB_OUTPUT" | |
| - uses: codecov/codecov-action@fb8b3582c8e4def4969c97caa2f19720cb33a72f # v7.0.0 | |
| with: | |
| files: ${{ steps.lcov.outputs.path }} | |
| disable_search: true | |
| fail_ci_if_error: true | |
| token: ${{ secrets.CODECOV_TOKEN }} |