Repository: immunant/c2rust
Pull request #1232: Move Linux CI from Azure Pipelines to GitHub Actions
Author: login: joshtriplett
Created: 2025-05-08T16:25:17Z | Merged: 2025-05-13T14:03:49Z

This simplifies the CI setup substantially. In particular, this installs packages as part of the CI setup, rather than in a separate manual container build step where modifications by contributors are ineffective until the container images are regenerated.

Now, changes to provisioning will take immediate effect, allowing upgrades to new versions to be contributed and tested easily.

This does not move macOS over, because I don't have sufficient experience with macOS to easily debug the issues that occur when attempting to do so.

* Fixes Linux part of #1226.



Diff:
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
new file mode 100644
index 0000000000..133db62542
--- /dev/null
+++ b/.github/workflows/ci.yml
@@ -0,0 +1,81 @@
+name: ci
+
+on:
+  push:
+    branches: [ master ]
+  pull_request:
+
+jobs:
+  test-linux:
+    runs-on: ubuntu-latest
+    steps:
+      - uses: actions/checkout@v4
+      - run: rustup component add rustfmt rustc-dev
+      # rust-cache very carefully caches toolchains and target directories,
+      # based on the job and toolchain and other factors. See
+      # https://github.com/Swatinem/rust-cache#cache-details for what gets
+      # cached, what gets used as part of the key, and what additional handling
+      # happens to make the cache reliable and smaller.
+      - uses: Swatinem/rust-cache@v2
+      - run: |
+          sudo apt-get update
+          sudo apt-get install \
+            clang \
+            clang-tools \
+            cmake \
+            curl \
+            git \
+            gperf \
+            libbrotli-dev \
+            libclang-dev \
+            libgcrypt20 \
+            libreadline-dev \
+            libidn2-dev \
+            libldap2-dev \
+            libncurses5-dev \
+            libnghttp2-dev \
+            libpcre3-dev \
+            libpsl-dev \
+            librtmp-dev \
+            libssl-dev \
+            libtool \
+            llvm \
+            llvm-dev \
+            luarocks \
+            ninja-build \
+            pkg-config \
+            python3-pip \
+            python3-setuptools \
+            python3-wheel \
+            rcs \
+            strace \
+            unzip \
+            zlib1g-dev
+      - name: Provision Python Packages
+        run: python3 -m pip install -r $GITHUB_WORKSPACE/scripts/requirements.txt
+      - name: cargo fmt --check
+        run: |
+          export RUSTFLAGS="-D warnings"
+          export RUSTDOCFLAGS="-D warnings"
+          cargo fmt --check
+      - name: cargo build --release
+        run: |
+          export RUSTFLAGS="-D warnings"
+          export RUSTDOCFLAGS="-D warnings"
+          # Don't build with `--all-features` as `--all-features` includes `--features llvm-static`,
+          # which we don't want to test here (see https://github.com/immunant/c2rust/issues/500).
+          cargo build --release
+      - name: cargo test --release --workspace
+        run: |
+          export RUSTFLAGS="-D warnings"
+          export RUSTDOCFLAGS="-D warnings"
+          cargo test --release --workspace
+      - name: Test translator
+        run: |
+          # `test_translator.py` compiles translated code,
+          # which has tons of warnings.
+          # `RUSTFLAGS="-D warnings"` would be inherited by that,
+          # causing tons of errors, so don't set that.
+          # `test_translator.py` does not rebuild,
+          # so changing `RUSTFLAGS` will not trigger a full rebuild.
+          ./scripts/test_translator.py tests/
diff --git a/azure-pipelines.yml b/azure-pipelines.yml
index 2935039981..2347f3e8df 100644
--- a/azure-pipelines.yml
+++ b/azure-pipelines.yml
@@ -14,74 +14,6 @@ trigger:
     - docs/*
 
 jobs:
-- job: Linux
-  timeoutInMinutes: 120
-  pool:
-    vmImage: 'ubuntu-latest'
-  strategy:
-    matrix:
-      arch:
-        containerImage: immunant/c2rust:archlinux-base-latest
-      debian10:
-        containerImage: immunant/c2rust:debian-buster-latest
-      debian11:
-        containerImage: immunant/c2rust:debian-bullseye-latest
-      fedora34:
-        containerImage: immunant/c2rust:fedora-34-latest
-      ubuntu20:
-        containerImage: immunant/c2rust:ubuntu-focal-latest
-      ubuntu18:
-        containerImage: immunant/c2rust:ubuntu-bionic-latest
-  container: $[ variables['containerImage'] ]
-  steps:
-
-  # rust was installed for the `docker` user, not the user azure creates
-  # but cargo and rustup can be controlled via $CARGO_HOME and $RUSTUP_HOME.
-  # NOTE: $HOME is not set correctly for the azure user; don't rely on it.
-
-  - script: |
-      export PATH="/home/docker/.cargo/bin:$PATH"
-      export RUSTUP_HOME=/home/docker/.rustup
-      export CARGO_HOME=$AGENT_TEMPDIRECTORY/.cargo
-      export RUSTFLAGS="-D warnings"
-      export RUSTDOCFLAGS="-D warnings"
-      cargo fmt --check
-    displayName: 'cargo fmt --check'
-
-  - script: |
-      export PATH="/home/docker/.cargo/bin:$PATH"
-      export RUSTUP_HOME=/home/docker/.rustup
-      export CARGO_HOME=$AGENT_TEMPDIRECTORY/.cargo
-      export RUSTFLAGS="-D warnings"
-      export RUSTDOCFLAGS="-D warnings"
-      # Don't build with `--all-features` as `--all-features` includes `--features llvm-static`,
-      # which we don't want to test here (it doesn't work out of the box on Arch and Fedora;
-      # see https://github.com/immunant/c2rust/issues/500).
-      cargo build --release
-    displayName: 'cargo build against host clang/LLVM (fast build)'
-
-  - script: |
-      export PATH="/home/docker/.cargo/bin:$PATH"
-      export RUSTUP_HOME=/home/docker/.rustup
-      export CARGO_HOME=$AGENT_TEMPDIRECTORY/.cargo
-      export RUSTFLAGS="-D warnings"
-      export RUSTDOCFLAGS="-D warnings"
-      cargo test --release --workspace
-    displayName: 'cargo test'
-
-  - script: |
-      export PATH="/home/docker/.cargo/bin:$PATH"
-      export RUSTUP_HOME=/home/docker/.rustup
-      export CARGO_HOME=$AGENT_TEMPDIRECTORY/.cargo
-      # `test_translator.py` compiles translated code,
-      # which has tons of warnings.
-      # `RUSTFLAGS="-D warnings"` would be inherited by that,
-      # causing tons of errors, so don't set that.
-      # `test_translator.py` does not rebuild,
-      # so changing `RUSTFLAGS` will not trigger a full rebuild.
-      ./scripts/test_translator.py tests/
-    displayName: 'Test translator (fast build)'
-
 - job: Darwin
   timeoutInMinutes: 180
   pool:


Reviews:
user: login: kkysen
state: CHANGES_REQUESTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-09T06:24:22Z
user: login: joshtriplett
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-09T08:07:05Z
user: login: joshtriplett
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-09T08:08:26Z
user: login: joshtriplett
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-09T08:21:55Z
user: login: kkysen
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-09T09:49:38Z
user: login: kkysen
body: LGTM but I'd still like @thedataking to take a final look, particularly about moving from testing on multiple distros to just Ubuntu.  I think it's likely fine, and GitHub Actions have numerous benefits, but I just want to double check.
state: APPROVED
author_association: CONTRIBUTOR
submitted_at: 2025-05-13T03:40:31Z
user: login: joshtriplett
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-13T03:43:29Z
user: login: thedataking
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-13T03:46:01Z
user: login: kkysen
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-13T03:46:53Z
user: login: kkysen
body: All good now, thank you!!
state: APPROVED
author_association: CONTRIBUTOR
submitted_at: 2025-05-13T14:03:06Z

Review comments:
diff_hunk: @@ -0,0 +1,116 @@
+name: ci
+
+on:
+  push:
+    branches: [ master ]
+  pull_request:
+    branches: [ master ]
path: .github/workflows/ci.yml
user: login: kkysen
body: ```suggestion
```

I'd prefer if we still run CI on PRs not directly into `main` (e.g. if they're stacked).
created_at: 2025-05-09T05:46:22Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,116 @@
+name: ci
+
+on:
+  push:
+    branches: [ master ]
+  pull_request:
+    branches: [ master ]
+
+jobs:
+  test-linux:
+    runs-on: ubuntu-24.04
+    steps:
+      - uses: actions/checkout@v3
path: .github/workflows/ci.yml
user: login: kkysen
body: ```suggestion
      - uses: actions/checkout@v4
```
created_at: 2025-05-09T05:47:19Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,116 @@
+name: ci
+
+on:
+  push:
+    branches: [ master ]
+  pull_request:
+    branches: [ master ]
+
+jobs:
+  test-linux:
+    runs-on: ubuntu-24.04
+    steps:
+      - uses: actions/checkout@v3
+      - run: rustup component add rustfmt rustc-dev
+      # Needs adding to the safelist for c2rust GitHub Actions
+      #- uses: Swatinem/rust-cache@v2
+      - run: |
+          sudo apt-get update
+          sudo apt-get install \
+            clang \
+            clang-tools \
+            cmake \
+            curl \
+            git \
+            gperf \
+            libbrotli-dev \
+            libclang-dev \
+            libgcrypt20 \
+            libreadline-dev \
+            libidn2-dev \
+            libldap2-dev \
+            libncurses5-dev \
+            libnghttp2-dev \
+            libpcre3-dev \
+            libpsl-dev \
+            librtmp-dev \
+            libssl-dev \
+            libtool \
+            llvm \
+            llvm-dev \
+            luarocks \
+            ninja-build \
+            pkg-config \
+            python3-pip \
+            python3-setuptools \
+            python3-wheel \
+            rcs \
+            strace \
+            unzip \
+            zlib1g-dev
+      - name: Provision Python Packages
+        run: python3 -m pip install -r $GITHUB_WORKSPACE/scripts/requirements.txt
+      - name: cargo fmt --check
+        run: |
+          export RUSTFLAGS="-D warnings"
+          export RUSTDOCFLAGS="-D warnings"
+          cargo fmt --check
+      - name: cargo build --release
+        run: |
+          export RUSTFLAGS="-D warnings"
+          export RUSTDOCFLAGS="-D warnings"
+          # Don't build with `--all-features` as `--all-features` includes `--features llvm-static`,
+          # which we don't want to test here (see https://github.com/immunant/c2rust/issues/500).
+          cargo build --release
+      - name: cargo test --release --workspace
+        run: |
+          export RUSTFLAGS="-D warnings"
+          export RUSTDOCFLAGS="-D warnings"
+          cargo test --release --workspace
+      - name: Test translator
+        run: |
+          # `test_translator.py` compiles translated code,
+          # which has tons of warnings.
+          # `RUSTFLAGS="-D warnings"` would be inherited by that,
+          # causing tons of errors, so don't set that.
+          # `test_translator.py` does not rebuild,
+          # so changing `RUSTFLAGS` will not trigger a full rebuild.
+          ./scripts/test_translator.py tests/
+
+  test-mac:
+    runs-on: macos-14
+    steps:
+      - uses: actions/checkout@v3
path: .github/workflows/ci.yml
user: login: kkysen
body: ```suggestion
      - uses: actions/checkout@v4
```
created_at: 2025-05-09T05:48:06Z
author_association: CONTRIBUTOR
diff_hunk: @@ -1,120 +0,0 @@
-trigger:
-  branches:
-    include:
-    - master
-    - feature/ci-dev
-  paths:
-    exclude:
-    - README.md
-    - LICENSE
-    - .travis.yml
-    - book.toml
-    - docker/*
-    - manual/*
-    - docs/*
-
-jobs:
-- job: Linux
-  timeoutInMinutes: 120
-  pool:
-    vmImage: 'ubuntu-latest'
-  strategy:
-    matrix:
-      arch:
-        containerImage: immunant/c2rust:archlinux-base-latest
-      debian10:
-        containerImage: immunant/c2rust:debian-buster-latest
-      debian11:
-        containerImage: immunant/c2rust:debian-bullseye-latest
-      fedora34:
-        containerImage: immunant/c2rust:fedora-34-latest
-      ubuntu20:
-        containerImage: immunant/c2rust:ubuntu-focal-latest
-      ubuntu18:
-        containerImage: immunant/c2rust:ubuntu-bionic-latest
path: azure-pipelines.yml
user: login: kkysen
body: Can we test on all of these distros and versions in GitHub Actions, too, instead of just Ubuntu 24?
created_at: 2025-05-09T06:10:19Z
author_association: CONTRIBUTOR
diff_hunk: @@ -1,120 +0,0 @@
-trigger:
-  branches:
-    include:
-    - master
-    - feature/ci-dev
-  paths:
-    exclude:
-    - README.md
-    - LICENSE
-    - .travis.yml
-    - book.toml
-    - docker/*
-    - manual/*
-    - docs/*
-
-jobs:
-- job: Linux
-  timeoutInMinutes: 120
-  pool:
-    vmImage: 'ubuntu-latest'
-  strategy:
-    matrix:
-      arch:
-        containerImage: immunant/c2rust:archlinux-base-latest
-      debian10:
-        containerImage: immunant/c2rust:debian-buster-latest
-      debian11:
-        containerImage: immunant/c2rust:debian-bullseye-latest
-      fedora34:
-        containerImage: immunant/c2rust:fedora-34-latest
-      ubuntu20:
-        containerImage: immunant/c2rust:ubuntu-focal-latest
-      ubuntu18:
-        containerImage: immunant/c2rust:ubuntu-bionic-latest
path: azure-pipelines.yml
user: login: kkysen
body: Oh wait, GitHub Actions only supports Ubuntu, right?  So we'll have to drop testing on all the others.  @thedataking is this okay?
created_at: 2025-05-09T06:19:20Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,116 @@
+name: ci
+
+on:
+  push:
+    branches: [ master ]
+  pull_request:
+    branches: [ master ]
+
+jobs:
+  test-linux:
+    runs-on: ubuntu-24.04
path: .github/workflows/ci.yml
user: login: kkysen
body: I'm wondering if we should just use `ubuntu-latest`.  We often get people finding issues with updated distros with newer LLVM/clang versions, and it'd be nicer to catch that in CI rather than having users need to open an issue, even if CI might suddenly break.
created_at: 2025-05-09T06:20:55Z
author_association: CONTRIBUTOR
path: scripts/provision_mac.sh
user: login: kkysen
body: Can we fully inline this in `ci.yml`?  And the other provision scripts, too.
created_at: 2025-05-09T06:22:48Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,116 @@
+name: ci
+
+on:
+  push:
+    branches: [ master ]
+  pull_request:
+    branches: [ master ]
+
+jobs:
+  test-linux:
+    runs-on: ubuntu-24.04
path: .github/workflows/ci.yml
user: login: joshtriplett
body: @kkysen Sure, I can do that.
created_at: 2025-05-09T08:07:05Z
author_association: CONTRIBUTOR
path: scripts/provision_mac.sh
user: login: joshtriplett
body: I'd be happy to do that as an additional step, once this builds at all on macOS. Would you mind if that's a follow-up PR?
created_at: 2025-05-09T08:08:26Z
author_association: CONTRIBUTOR
diff_hunk: @@ -1,120 +0,0 @@
-trigger:
-  branches:
-    include:
-    - master
-    - feature/ci-dev
-  paths:
-    exclude:
-    - README.md
-    - LICENSE
-    - .travis.yml
-    - book.toml
-    - docker/*
-    - manual/*
-    - docs/*
-
-jobs:
-- job: Linux
-  timeoutInMinutes: 120
-  pool:
-    vmImage: 'ubuntu-latest'
-  strategy:
-    matrix:
-      arch:
-        containerImage: immunant/c2rust:archlinux-base-latest
-      debian10:
-        containerImage: immunant/c2rust:debian-buster-latest
-      debian11:
-        containerImage: immunant/c2rust:debian-bullseye-latest
-      fedora34:
-        containerImage: immunant/c2rust:fedora-34-latest
-      ubuntu20:
-        containerImage: immunant/c2rust:ubuntu-focal-latest
-      ubuntu18:
-        containerImage: immunant/c2rust:ubuntu-bionic-latest
path: azure-pipelines.yml
user: login: joshtriplett
body: @kkysen It's theoretically possible to run a custom container of an arbitrary distro on GitHub Actions, but one of the huge benefits of this change to the CI is avoiding the separate (and manual) step of building containers, which makes it impossible for contributors to modify and test (because contributors can't replace those containers). With the new approach, all the packages are installed on the fly, and it's much easier to iterate on the result.

I think that usability improvement would be worth making this change.
created_at: 2025-05-09T08:21:54Z
author_association: CONTRIBUTOR
path: scripts/provision_mac.sh
user: login: kkysen
body: Of course
created_at: 2025-05-09T09:49:38Z
author_association: CONTRIBUTOR
diff_hunk: @@ -23,8 +23,8 @@ export HOMEBREW_NO_AUTO_UPDATE=1
 brew install -q python cmake ninja gpg llvm@17 bash
 
 # Python 3 packages
-python3 -m pip install --user --upgrade pip
-python3 -m pip install --user -r "$SCRIPT_DIR/requirements.txt"
+python3 -m pip install --break-system-packages --user --upgrade pip
+python3 -m pip install --break-system-packages --user -r "$SCRIPT_DIR/requirements.txt"
path: scripts/provision_mac.sh
user: login: kkysen
body: Are these still needed if this PR is just moving Linux CI now?
created_at: 2025-05-13T03:39:28Z
author_association: CONTRIBUTOR
diff_hunk: @@ -23,8 +23,8 @@ export HOMEBREW_NO_AUTO_UPDATE=1
 brew install -q python cmake ninja gpg llvm@17 bash
 
 # Python 3 packages
-python3 -m pip install --user --upgrade pip
-python3 -m pip install --user -r "$SCRIPT_DIR/requirements.txt"
+python3 -m pip install --break-system-packages --user --upgrade pip
+python3 -m pip install --break-system-packages --user -r "$SCRIPT_DIR/requirements.txt"
path: scripts/provision_mac.sh
user: login: joshtriplett
body: No, though they'll be needed by anyone trying to port to newer macOS with newer pip. But I should remove them from this PR, good catch.
created_at: 2025-05-13T03:43:29Z
author_association: CONTRIBUTOR
diff_hunk: @@ -23,8 +23,8 @@ export HOMEBREW_NO_AUTO_UPDATE=1
 brew install -q python cmake ninja gpg llvm@17 bash
 
 # Python 3 packages
-python3 -m pip install --user --upgrade pip
-python3 -m pip install --user -r "$SCRIPT_DIR/requirements.txt"
+python3 -m pip install --break-system-packages --user --upgrade pip
+python3 -m pip install --break-system-packages --user -r "$SCRIPT_DIR/requirements.txt"
path: scripts/provision_mac.sh
user: login: thedataking
body: If this PR doesn't move macOS CI over, it shouldn't touch mac-only files. That can be considered when re-enabling macOS.
created_at: 2025-05-13T03:46:01Z
author_association: CONTRIBUTOR
diff_hunk: @@ -23,8 +23,8 @@ export HOMEBREW_NO_AUTO_UPDATE=1
 brew install -q python cmake ninja gpg llvm@17 bash
 
 # Python 3 packages
-python3 -m pip install --user --upgrade pip
-python3 -m pip install --user -r "$SCRIPT_DIR/requirements.txt"
+python3 -m pip install --break-system-packages --user --upgrade pip
+python3 -m pip install --break-system-packages --user -r "$SCRIPT_DIR/requirements.txt"
path: scripts/provision_mac.sh
user: login: kkysen
body: Yeah, they're definitely okay in general for another PR.  Although I'd personally prefer if we move all of our python dependency management to `uv` to make things simpler and more reliable.
created_at: 2025-05-13T03:46:53Z
author_association: CONTRIBUTOR

PR comments:
user: login: joshtriplett
created_at: 2025-05-08T16:45:18Z
body: @kkysen Would you mind safelisting `Swatinem/rust-cache` for GitHub Actions?
author_association: CONTRIBUTOR
user: login: kkysen
created_at: 2025-05-08T18:29:02Z
body: > @kkysen Would you mind safelisting `Swatinem/rust-cache` for GitHub Actions?

Do you know how to do that?
author_association: CONTRIBUTOR
user: login: joshtriplett
created_at: 2025-05-08T19:44:56Z
body: > > @kkysen Would you mind safelisting `Swatinem/rust-cache` for GitHub Actions?
> 
> Do you know how to do that?

I believe it'll be in the GitHub actions settings, either for the project or for the organization. There's a setting for where it can run actions from.
author_association: CONTRIBUTOR
user: login: kkysen
created_at: 2025-05-08T20:58:21Z
body: > > > @kkysen Would you mind safelisting `Swatinem/rust-cache` for GitHub Actions?
> > 
> > 
> > Do you know how to do that?
> 
> I believe it'll be in the GitHub actions settings, either for the project or for the organization. There's a setting for where it can run actions from.

@thedataking, can you see if you're able to do this?  I don't see where I can, or I probably don't have permission to do it.  See the error message here: https://github.com/immunant/c2rust/actions/runs/14911291371.
author_association: CONTRIBUTOR
user: login: joshtriplett
created_at: 2025-05-12T23:53:05Z
body: @kkysen I think this is ready to merge now.
author_association: CONTRIBUTOR
user: login: kkysen
created_at: 2025-05-13T03:50:07Z
body: Also I'm re-running CI to see how long a cached CI takes, although that should improve a bunch with `rust-cache`.
author_association: CONTRIBUTOR
user: login: thedataking
created_at: 2025-05-13T03:52:20Z
body: @joshtriplett appreciate the work to fix our CI. Thanks! 

> Would you mind safelisting Swatinem/rust-cache for GitHub Actions?

I'd prefer to use the "vanilla" cache module unless there is some clear benefit. Wouldn't the pattern below work?

```
      - name: cache rust crates
        uses: actions/cache@v4
        with:
          path: |
            ~/.cargo/bin/
            ~/.cargo/registry/index/
            ~/.cargo/registry/cache/
            ~/.cargo/git/db/
            target/
          key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }}
```
author_association: CONTRIBUTOR
user: login: kkysen
created_at: 2025-05-13T04:15:02Z
body: > * Fixes Linux part of #1226.

I updated this.  We still have macOS to do, right?
author_association: CONTRIBUTOR
user: login: joshtriplett
created_at: 2025-05-13T04:23:09Z
body: > @joshtriplett appreciate the work to fix our CI. Thanks!
> 
> > Would you mind safelisting Swatinem/rust-cache for GitHub Actions?
> 
> I'd prefer to use the "vanilla" cache module unless there is some clear benefit. Wouldn't the pattern below work?
> 
> ```
>       - name: cache rust crates
>         uses: actions/cache@v4
>         with:
>           path: |
>             ~/.cargo/bin/
>             ~/.cargo/registry/index/
>             ~/.cargo/registry/cache/
>             ~/.cargo/git/db/
>             target/
>           key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }}
> ```

Caching correctly is a lot more complicated than that, and also involves caching more than that. The cache needs to depend on the toolchain, the job, etc. And the cache should include the results of compiling the dependencies, so that most builds are relatively fast. Doing it right requires logic on par with what rust-cache already does.

If you want to lock it down to a specific version of rust-cache, we could do that, and be very deliberate about upgrading it.
author_association: CONTRIBUTOR
user: login: thedataking
created_at: 2025-05-13T04:30:05Z
body: Thanks for educating me. Khyber mentioned that rust-lang also uses this action which eases my concern somewhat.

> If you want to lock it down to a specific version of rust-cache, we could do that, and be very deliberate about upgrading it.

OK, v2 should be whitelisted now. Could we have a comment in the workflow to remind us why we're not using Github's cache action?
author_association: CONTRIBUTOR
user: login: joshtriplett
created_at: 2025-05-13T12:33:52Z
body: @kkysen OK, this is ready now, fixes all the items that have been commented on, and uses caching.
author_association: CONTRIBUTOR