Files
pnpm/.github/workflows/ecosystem-e2e.yml
T
Zoltan KochanandClaude Opus 5.5 8b906af900 test: run pnpm in a StackBlitz WebContainer on the ecosystem e2e cron (#16260)
* test: run pnpm in a StackBlitz WebContainer on the ecosystem e2e cron

WebContainers run Node.js in the browser, and their fs errors and
node:sqlite differ from Node.js in ways no local test reproduces. Two
such differences broke pnpm install there (pnpm/pnpm#15649).

The new harness boots a WebContainer in headless Chromium through
`@webcontainer/api`, mounts the files the published pnpm package ships,
and runs install without a lockfile, a repeat install, a reinstall from
the store, add, remove, and list, failing on any non-zero exit. It
lives next to the Rust ecosystem-e2e harness, and a webcontainer job in
the same daily workflow runs it against the bundle the build job makes.
It needs StackBlitz's servers, so it stays off the per-PR checks.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* test(webcontainer-e2e): open the page on the address the server listens on

The server binds 127.0.0.1, while the page was opened at localhost,
which reached it only through Chromium falling back from ::1.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* test(webcontainer-e2e): reinstall offline and check the removal

A reinstall that could reach the registry passed even when the store
index was unreadable, and a remove that left is-odd in place passed too.
The reinstall now runs with --offline, and a new step checks that is-odd
left package.json and no longer resolves. The server helper now rejects
when it cannot listen and documents that.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-30 01:04:19 +02:00

168 lines
6.2 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.
#
# The webcontainer job installs a small project with the pnpm bundle inside a
# StackBlitz WebContainer, whose in-browser Node.js differs from Node.js in its
# `fs` errors and `node:sqlite`. It depends on StackBlitz's servers, which is
# another reason this runs on a cron.
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: Setup Rust toolchain
uses: $/.github/actions/rustup
- name: Install pnpm
uses: pnpm/setup@fbda4c85fc2e1e08721cd8763afea8f48d60f024 # v3.0.0
- 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@fbda4c85fc2e1e08721cd8763afea8f48d60f024 # v3.0.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
webcontainer:
if: github.repository == 'pnpm/pnpm' # Only run on the main repository, not forks
name: Ecosystem E2E / webcontainer
needs: build
runs-on: blacksmith-8vcpu-ubuntu-2404
timeout-minutes: 30
steps:
# The harness mounts the committed `pnpm11/pnpm/package.json` and `bin/`
# alongside the downloaded `dist/` bundle.
- name: Checkout
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false
- name: Install pnpm
uses: pnpm/setup@fbda4c85fc2e1e08721cd8763afea8f48d60f024 # v3.0.0
with:
install: false
- name: Install the harness
run: pnpm install --frozen-lockfile --filter @pnpm-private/ecosystem-e2e-webcontainer
- name: Install Chromium
run: pnpm --filter @pnpm-private/ecosystem-e2e-webcontainer exec playwright-core install --with-deps --only-shell chromium
- name: Download build outputs
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
with:
name: ecosystem-e2e-build
path: .
- name: Run the WebContainer e2e
run: node pnpm/tasks/ecosystem-e2e/webcontainer/run.mjs