diff --git a/.github/actions/setup-rust/CHANGELOG.md b/.github/actions/setup-rust/CHANGELOG.md index 0b1ba1e2..0c940aa5 100644 --- a/.github/actions/setup-rust/CHANGELOG.md +++ b/.github/actions/setup-rust/CHANGELOG.md @@ -1,5 +1,10 @@ # Changelog +## v1.0.16 - 2026-08-02 + +- Update actions/cache, sccache-action, and setup-msys2 to releases that use + the GitHub Actions Node.js 24 runtime. + ## v1.0.15 - 2026-07-29 - Add `rustflags` input forwarded to `actions-rust-lang/setup-rust-toolchain`. diff --git a/.github/actions/setup-rust/README.md b/.github/actions/setup-rust/README.md index b514ea62..6365656b 100644 --- a/.github/actions/setup-rust/README.md +++ b/.github/actions/setup-rust/README.md @@ -130,10 +130,11 @@ cache compiler output. It sets `SCCACHE_GHA_ENABLED=true` and `RUSTC_WRAPPER=sccache` so subsequent build steps benefit from the cache. The compiled objects are stored in `~/.cache/sccache` and cached with a **separate cache key** from the directories above. This directory holds the sccache cache -space and does not share data with the Rust dependency cache; the sccache step -itself uses -`mozilla-actions/sccache-action@7d986dd989559c6ecdb630a3fd2557667be217ad`, -pinned to a specific commit for reproducibility. +space and does not share data with the Rust dependency cache. The revised +Node.js-backed actions are pinned to specific commits for reproducibility: +`actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9`, +`mozilla-actions/sccache-action@fc920bf0ec8de6ee65d409111f7ec508035751ba` +and `msys2/setup-msys2@66cd2cce69caa17b53920067426061ca1de3a884`. ### Extent and limitations diff --git a/.github/actions/setup-rust/action.yml b/.github/actions/setup-rust/action.yml index 0d4765b9..32ed1747 100644 --- a/.github/actions/setup-rust/action.yml +++ b/.github/actions/setup-rust/action.yml @@ -168,8 +168,8 @@ runs: echo "NIGHTLY_SYSROOT=$(rustc +$OPENBSD_NIGHTLY --print sysroot)" >> "$GITHUB_ENV" shell: bash - name: Cache cargo registry - # v4.3.0 - uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 + # v6.1.0 + uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 with: path: | ~/.cargo/registry @@ -181,12 +181,12 @@ runs: # x86_64-apple-darwin binaries were dropped after sccache v0.12.0 - name: Run sccache (x86_64 macOS) if: ${{ inputs.use-sccache == 'true' && github.event_name != 'release' && runner.os == 'macOS' && runner.arch == 'X64' }} - uses: mozilla-actions/sccache-action@7d986dd989559c6ecdb630a3fd2557667be217ad + uses: mozilla-actions/sccache-action@fc920bf0ec8de6ee65d409111f7ec508035751ba with: version: v0.12.0 - name: Run sccache if: ${{ inputs.use-sccache == 'true' && github.event_name != 'release' && !(runner.os == 'macOS' && runner.arch == 'X64') }} - uses: mozilla-actions/sccache-action@7d986dd989559c6ecdb630a3fd2557667be217ad + uses: mozilla-actions/sccache-action@fc920bf0ec8de6ee65d409111f7ec508035751ba - name: Install system dependencies if: ${{ inputs.install-postgres-deps == 'true' && runner.os == 'Linux' }} run: sudo apt-get update && sudo apt-get install -y --no-install-recommends libpq-dev @@ -206,8 +206,8 @@ runs: - name: Install MSYS2 toolchain and SQLite if: ${{ inputs.install-sqlite-deps == 'true' && runner.os == 'Windows' }} - # v2.30.0 - uses: msys2/setup-msys2@4f806de0a5a7294ffabaff804b38a9b435a73bda + # v2.32.0 + uses: msys2/setup-msys2@66cd2cce69caa17b53920067426061ca1de3a884 with: msystem: MINGW64 update: true @@ -226,8 +226,8 @@ runs: - name: Cache OpenBSD stdlib if: ${{ inputs.with-openbsd == 'true' && runner.os == 'Linux' }} id: openbsd-stdlib-cache - # v4.3.0 - uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 + # v6.1.0 + uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 with: path: ${{ env.NIGHTLY_SYSROOT }}/lib/rustlib/x86_64-unknown-openbsd key: openbsd-stdlib-${{ runner.os }}-${{ hashFiles('rust-toolchain.toml') }} diff --git a/.github/actions/setup-rust/tests/test_setup_rust_manifest.py b/.github/actions/setup-rust/tests/test_setup_rust_manifest.py index 4491ff2e..889347cb 100644 --- a/.github/actions/setup-rust/tests/test_setup_rust_manifest.py +++ b/.github/actions/setup-rust/tests/test_setup_rust_manifest.py @@ -16,6 +16,19 @@ PINNED_BINSTALL_SHA256 = ( "d3a93702160e0ec03e2a4e996855db1f01adee801fb84a43add24e0877ef8eae" ) +NODE24_ACTION_REVISIONS = { + "Cache cargo registry": "actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9", + "Run sccache (x86_64 macOS)": ( + "mozilla-actions/sccache-action@fc920bf0ec8de6ee65d409111f7ec508035751ba" + ), + "Run sccache": ( + "mozilla-actions/sccache-action@fc920bf0ec8de6ee65d409111f7ec508035751ba" + ), + "Install MSYS2 toolchain and SQLite": ( + "msys2/setup-msys2@66cd2cce69caa17b53920067426061ca1de3a884" + ), + "Cache OpenBSD stdlib": ("actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9"), +} def _load_steps() -> list[dict[str, object]]: @@ -198,6 +211,20 @@ def test_manifest_exposes_toolchain_input() -> None: assert "toolchain" in inputs +@pytest.mark.parametrize( + ("step_name", "expected_revision"), + NODE24_ACTION_REVISIONS.items(), +) +def test_node_actions_use_pinned_node24_revisions( + step_name: str, + expected_revision: str, +) -> None: + """Node-based dependencies should use the verified Node.js 24 revisions.""" + assert _get_step(step_name).get("uses") == expected_revision, ( + f"{step_name} must use the verified revision {expected_revision}" + ) + + def test_install_postgres_deps_is_linux_only() -> None: """Postgres packages should only install on Linux when requested.""" condition = _get_step_condition("Install system dependencies") diff --git a/.github/workflows/test-rustflags-export.yml b/.github/workflows/test-rustflags-export.yml index dcb6606a..f5b29414 100644 --- a/.github/workflows/test-rustflags-export.yml +++ b/.github/workflows/test-rustflags-export.yml @@ -94,3 +94,47 @@ jobs: - name: Observe RUSTFLAGS alongside an inherited value shell: bash run: echo "setup_rust_inherited_rustflags=[${RUSTFLAGS-unset}]" + + # act cannot reliably execute sccache's post-step. Disable sccache here so + # this supported Linux path can prove that setup-rust makes the Rust tools + # available to downstream steps through the composite-action boundary. + setup-rust-toolchain-available: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 + with: + persist-credentials: false + - name: Remove the preinstalled stable toolchain + shell: bash + run: | + set -euo pipefail + rustup toolchain uninstall stable || true + if rustup run stable rustc --version >/dev/null 2>&1; then + echo "stable remained installed before setup-rust" >&2 + exit 1 + fi + - name: Setup stable Rust + uses: ./.github/actions/setup-rust + with: + toolchain: stable + install-binstall: "false" + use-sccache: "false" + - name: Verify Rust tools remain available + shell: bash + run: | + set -euo pipefail + rustc_version="$(rustc --version)" + cargo_version="$(cargo --version)" + active_toolchain="$(rustup show active-toolchain)" + case "${active_toolchain}" in + stable-*) ;; + *) + echo "expected stable toolchain, got: ${active_toolchain}" >&2 + exit 1 + ;; + esac + test -n "${rustc_version}" + test -n "${cargo_version}" + echo "setup_rust_toolchain=[${active_toolchain}]" + echo "setup_rust_rustc=[${rustc_version}]" + echo "setup_rust_cargo=[${cargo_version}]" diff --git a/docs/developers-guide.md b/docs/developers-guide.md index cbef68ce..ebea4e07 100644 --- a/docs/developers-guide.md +++ b/docs/developers-guide.md @@ -153,6 +153,25 @@ act cannot execute the real `setup-uv` path on the local runner, document the reason and keep the unit or manifest tests that assert the pinned reference in sync with the new SHA. +## Maintaining `setup-rust` Node.js Action Pins + +The [`setup-rust` action manifest](../.github/actions/setup-rust/action.yml) +uses `actions/cache`, `mozilla-actions/sccache-action`, and +`msys2/setup-msys2`. Pin each action by a verified full commit SHA. + +When updating these Node.js 24 action dependencies: + +1. Inspect the upstream `action.yml` at the selected revision and verify that + its `runs.using` value declares the required Node.js runtime. +2. Update every affected `setup-rust` manifest step together so all supported + runner paths use the intended revisions. +3. Synchronize the exact revision strings in `NODE24_ACTION_REVISIONS` in the + [`setup-rust` manifest tests](../.github/actions/setup-rust/tests/test_setup_rust_manifest.py). +4. Run the manifest tests and supported runner-backed workflow validation. + +The static manifest assertions must remain in place: runner execution proves +that the action works, but cannot prove that a pin is the intended revision. + ## `setup-rust` cargo-binstall Pinning The `setup-rust` action pins `cargo-binstall` by downloading diff --git a/docs/users-guide.md b/docs/users-guide.md index a620b9c0..6c845dfe 100644 --- a/docs/users-guide.md +++ b/docs/users-guide.md @@ -14,6 +14,14 @@ for common scenarios. - [`rust-build-release` README](../.github/actions/rust-build-release/README.md) – full input and output tables. +## Node.js 24 action dependencies + +`setup-rust` pins its Node.js-backed cache, sccache and MSYS2 dependencies to +revisions that support the GitHub Actions Node.js 24 runtime. This removes the +Node.js 20 deprecation warnings without changing the action's inputs or cache +configuration. See the [`setup-rust` README](../.github/actions/setup-rust/README.md) +for the pinned revisions and cache behaviour. + ## The problem The nested `actions-rust-lang/setup-rust-toolchain` action exports diff --git a/tests/workflows/test_rustflags_export_workflow.py b/tests/workflows/test_rustflags_export_workflow.py index b22b1534..5b9e410e 100644 --- a/tests/workflows/test_rustflags_export_workflow.py +++ b/tests/workflows/test_rustflags_export_workflow.py @@ -10,9 +10,10 @@ from __future__ import annotations import re -import typing as typ +from pathlib import Path import pytest +import yaml from .conftest import ( FIXTURES_DIR, @@ -22,10 +23,8 @@ skip_unless_workflow_tests, ) -if typ.TYPE_CHECKING: - from pathlib import Path - WORKFLOW = "test-rustflags-export.yml" +WORKFLOW_PATH = Path(__file__).resolve().parents[2] / ".github" / "workflows" / WORKFLOW # The workflow runs on the release event because the nested setup-rust skips # sccache for releases, whose post-step is unreliable under act. EVENT = "release" @@ -49,6 +48,56 @@ def _run(job: str, artefact_dir: Path) -> str: return logs +def test_setup_rust_toolchain_workflow_shape() -> None: + """The runner job exercises the intended local setup-rust path.""" + workflow = yaml.safe_load(WORKFLOW_PATH.read_text(encoding="utf-8")) + assert isinstance(workflow, dict), f"{WORKFLOW_PATH} must contain a YAML mapping" + jobs = workflow.get("jobs") + assert isinstance(jobs, dict), f"{WORKFLOW_PATH} must define a jobs mapping" + job = jobs.get("setup-rust-toolchain-available") + assert isinstance(job, dict), ( + "workflow must define the setup-rust-toolchain-available job" + ) + steps = job.get("steps") + assert isinstance(steps, list), ( + "setup-rust-toolchain-available must define a steps collection" + ) + assert all(isinstance(step, dict) for step in steps), ( + "every setup-rust-toolchain-available step must be a mapping" + ) + + setup_steps = [step for step in steps if step.get("name") == "Setup stable Rust"] + assert len(setup_steps) == 1, "expected exactly one Setup stable Rust step" + setup_step = setup_steps[0] + assert setup_step["uses"] == "./.github/actions/setup-rust", ( + "Setup stable Rust must call the local setup-rust action" + ) + assert setup_step["with"] == { + "toolchain": "stable", + "install-binstall": "false", + "use-sccache": "false", + }, "Setup stable Rust must select the isolated stable toolchain path" + + verify_steps = [ + step + for step in steps + if step.get("name") == "Verify Rust tools remain available" + ] + assert len(verify_steps) == 1, ( + "expected exactly one Verify Rust tools remain available step" + ) + verify_step = verify_steps[0] + script = verify_step["run"] + assert "rustc --version" in script, "verification must execute rustc" + assert "cargo --version" in script, "verification must execute cargo" + assert 'test -n "${rustc_version}"' in script, ( + "verification must assert that rustc returned a version" + ) + assert 'test -n "${cargo_version}"' in script, ( + "verification must assert that cargo returned a version" + ) + + @skip_unless_act @skip_unless_workflow_tests def test_rust_build_release_exports_rustflags_to_later_steps( @@ -117,3 +166,20 @@ def test_setup_rust_leaves_an_inherited_rustflags_alone(artefact_dir: Path) -> N assert "debuginfo=2" not in logs.split("setup_rust_inherited_rustflags=")[-1], ( f"the input displaced the inherited value:\n{logs}" ) + + +@skip_unless_act +@skip_unless_workflow_tests +def test_setup_rust_exposes_rust_tools_to_later_steps(artefact_dir: Path) -> None: + """A supported Linux setup leaves rustc and cargo available downstream.""" + logs = _run("setup-rust-toolchain-available", artefact_dir) + + assert re.search(r"setup_rust_toolchain=\[stable-[^]]+", logs), ( + f"setup-rust did not select the required stable toolchain:\n{logs}" + ) + assert re.search(r"setup_rust_rustc=\[rustc \d+\.\d+\.\d+", logs), ( + f"rustc was not available after setup-rust:\n{logs}" + ) + assert re.search(r"setup_rust_cargo=\[cargo \d+\.\d+\.\d+", logs), ( + f"cargo was not available after setup-rust:\n{logs}" + )