zizmor's self-repository audit flags every `uses: ./.github/...` reference now that GitHub has a dedicated `$/` form. The `$/` form resolves against the workflow's own commit rather than the runtime checkout, so it cannot load an action cloned into the workspace at runtime, and GitHub treats it as pinned. Rewrites all 22 references (18 local actions, 4 reusable workflow calls). With the `$/` form the runner downloads the whole repository as an action archive at job setup, and that download fails on any broken symlink in the tree. The four broken symlinks were all test fixtures: the directory-fetcher and cafs tests now copy their fixture into a temp dir and create the broken symlink there, and the has-not-outdated-deps fixture drops two dangling node_modules links that `pnpm outdated` never followed. pnpm's GitHub Actions dependency discovery only followed `./` references into local actions and reusable workflows; both stacks now follow `$/` too.
129 lines
4.7 KiB
YAML
129 lines
4.7 KiB
YAML
name: Ecosystem E2E
|
|
|
|
# Installs real-world JS stacks (Next.js, Vite, …) with both the pnpm CLI
|
|
# and pacquet, under both the default isolated layout and the global virtual
|
|
# store, then builds and serves each app. The binary axis catches pnpm↔pacquet
|
|
# parity gaps; the layout axis catches breakage introduced by the global
|
|
# virtual store. Runs on a daily cron rather than per-PR — the installs are
|
|
# slow and track upstream framework releases, so a red cell is investigated,
|
|
# not treated as a merge blocker.
|
|
|
|
permissions:
|
|
contents: read
|
|
|
|
on:
|
|
workflow_dispatch:
|
|
schedule:
|
|
- cron: '0 6 * * *'
|
|
|
|
concurrency:
|
|
group: ${{ github.workflow }}-${{ github.ref }}
|
|
cancel-in-progress: true
|
|
|
|
jobs:
|
|
# Compile pacquet, the harness, and the pnpm bundle once, then share them
|
|
# with every stack job — building them per stack would repeat the same
|
|
# multi-minute Rust and bundle builds across the whole matrix.
|
|
build:
|
|
if: github.repository == 'pnpm/pnpm' # Only run on the main repository, not forks
|
|
name: Ecosystem E2E / Build
|
|
runs-on: blacksmith-8vcpu-ubuntu-2404
|
|
timeout-minutes: 30
|
|
steps:
|
|
- name: Checkout
|
|
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
|
with:
|
|
persist-credentials: false
|
|
|
|
- name: Install pnpm
|
|
uses: pnpm/setup@703c52620218391530e48b9e8870d5c0082e1b9b # v2.1.0
|
|
|
|
- name: Setup Rust toolchain
|
|
uses: $/.github/actions/rustup
|
|
|
|
- name: Build pnpm and the harness
|
|
run: cargo build --release --bin pnpm --bin ecosystem-e2e
|
|
|
|
- name: Build the pnpm CLI bundle
|
|
run: |
|
|
pnpm install --frozen-lockfile
|
|
pnpm --filter 'pnpm' run compile
|
|
|
|
- name: Upload build outputs
|
|
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
|
|
with:
|
|
name: ecosystem-e2e-build
|
|
path: |
|
|
target/release/pnpm
|
|
target/release/ecosystem-e2e
|
|
pnpm11/pnpm/dist
|
|
retention-days: 1
|
|
if-no-files-found: error
|
|
|
|
ecosystem-e2e:
|
|
if: github.repository == 'pnpm/pnpm' # Only run on the main repository, not forks
|
|
name: Ecosystem E2E / ${{ matrix.stack }}
|
|
needs: build
|
|
runs-on: blacksmith-8vcpu-ubuntu-2404
|
|
# Bound the blast radius: a hung build or serve subprocess can't pin a
|
|
# runner indefinitely.
|
|
timeout-minutes: 60
|
|
strategy:
|
|
fail-fast: false
|
|
matrix:
|
|
# One stack per job so a slow or flaky stack can't mask the others
|
|
# and each gets its own log artifact.
|
|
stack: [next, vite-react, angular, astro, sveltekit, nuxt, react-router]
|
|
steps:
|
|
# The pnpm shim launches the repo's committed `pnpm11/pnpm/bin/pnpm.cjs`, so the
|
|
# checkout is still needed alongside the downloaded `pnpm11/pnpm/dist` bundle.
|
|
- name: Checkout
|
|
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
|
with:
|
|
persist-credentials: false
|
|
|
|
- name: Install Node
|
|
# The runner image's system Node is older than the bundle's floor
|
|
# (`node:sqlite` needs >= 22.13). Installs the `devEngines.runtime`
|
|
# pin, which the harness passes to every subprocess through PATH.
|
|
uses: pnpm/setup@703c52620218391530e48b9e8870d5c0082e1b9b # v2.1.0
|
|
with:
|
|
install: false
|
|
|
|
- name: Download build outputs
|
|
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
|
|
with:
|
|
name: ecosystem-e2e-build
|
|
path: .
|
|
|
|
- name: Restore executable bits
|
|
# Artifacts don't preserve the executable bit.
|
|
run: chmod +x target/release/pnpm target/release/ecosystem-e2e
|
|
|
|
- name: Wrap the built pnpm bundle as an executable
|
|
# The harness takes a single executable for --pnpm; the launcher is a
|
|
# .cjs that needs `node`. Wrap the repo's bin entry (which loads
|
|
# dist/pnpm.mjs) so the run tests this repo's pnpm, not a system one.
|
|
run: |
|
|
printf '#!/usr/bin/env bash\nexec node "%s/pnpm11/pnpm/bin/pnpm.cjs" "$@"\n' "$PWD" > pnpm-built
|
|
chmod +x pnpm-built
|
|
|
|
- name: Run ecosystem E2E
|
|
run: |
|
|
./target/release/ecosystem-e2e \
|
|
--pnpm "$PWD/pnpm-built" \
|
|
--pacquet "$PWD/target/release/pnpm" \
|
|
--binary both \
|
|
--layout both \
|
|
--stack ${{ matrix.stack }} \
|
|
--work-dir "$RUNNER_TEMP/ecosystem-e2e-work"
|
|
|
|
- name: Upload cell logs
|
|
if: always()
|
|
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
|
|
with:
|
|
name: ecosystem-e2e-logs-${{ matrix.stack }}
|
|
path: ${{ runner.temp }}/ecosystem-e2e-work/**/*.log
|
|
retention-days: 7
|
|
if-no-files-found: ignore
|