mirror of
https://github.com/pnpm/pnpm.git
synced 2026-07-18 03:32:36 -04:00
* ci: run required checks on merge_group so the merge queue works The merge queue dispatches a merge_group event against a temporary gh-readonly-queue/main ref, but neither TS CI (ci.yml) nor Rust CI (pacquet-ci.yml) listened for it. Their required status checks therefore never ran in the queue, so every queued PR waited forever on the missing contexts (e.g. Rust CI / Success never starting). Add merge_group to both workflows' triggers and force the change detection true for that event. Forcing matters because TS CI / Compile & Lint is itself a required context: a skipped job never reports its context, which would keep the queue waiting, so it has to actually run. It also makes the queue test the fully merged result, which is the point of a merge queue. The Rust deny job's nested path filter, which has no push/PR base to diff against in the queue, runs unconditionally on merge_group instead. * ci: gate compile-and-lint and build-pnpr on merge_group explicitly The merge queue tests the merged commit, so the gating jobs must run on merge_group. build-pnpr (added by the Windows-sharding work) carries the same event guard as compile-and-lint and feeds test-smoke/test/test-windows, so it needs the merge_group clause too — otherwise the queue would skip the whole test suite.
254 lines
9.8 KiB
YAML
254 lines
9.8 KiB
YAML
name: TS CI
|
|
|
|
on: [push, pull_request, merge_group]
|
|
|
|
permissions:
|
|
contents: read # to fetch code (actions/checkout)
|
|
|
|
jobs:
|
|
changes:
|
|
name: TS CI / Detect Changes
|
|
runs-on: ubuntu-latest
|
|
permissions:
|
|
contents: read
|
|
pull-requests: read
|
|
outputs:
|
|
ts: ${{ steps.force.outputs.ts || steps.filter.outputs.ts }}
|
|
steps:
|
|
# In the merge queue the full suite must run: `TS CI / Compile & Lint`
|
|
# is itself a required check, and a skipped job never reports its
|
|
# context, which would leave the queue waiting forever. Forcing
|
|
# detection true also tests the merged result, which is the point of
|
|
# the queue.
|
|
- name: Force TS CI for merge queue
|
|
if: github.event_name == 'merge_group'
|
|
id: force
|
|
run: echo "ts=true" >> "$GITHUB_OUTPUT"
|
|
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
|
|
if: github.event_name != 'merge_group'
|
|
with:
|
|
persist-credentials: false
|
|
- uses: dorny/paths-filter@fbd0ab8f3e69293af611ebaee6363fc25e6d187d # v4.0.1
|
|
if: github.event_name != 'merge_group'
|
|
id: filter
|
|
with:
|
|
# The TypeScript pnpm stack lives under pnpm11/, plus the
|
|
# workspace-root tooling that drives its build/lint/test.
|
|
filters: |
|
|
ts:
|
|
- 'pnpm11/**'
|
|
- '.meta-updater/**'
|
|
- '__patches__/**'
|
|
- 'package.json'
|
|
- 'pnpm-workspace.yaml'
|
|
- 'pnpm-lock.yaml'
|
|
- '.pnpmfile.cjs'
|
|
- 'eslint.config.mjs'
|
|
- 'tsconfig.lint.json'
|
|
- 'cspell.json'
|
|
- '.github/workflows/ci.yml'
|
|
- '.github/workflows/test.yml'
|
|
- '.github/scripts/**'
|
|
|
|
compile-and-lint:
|
|
needs: changes
|
|
# Run only when TypeScript-relevant files changed. Also skip
|
|
# pull_request events from PRs in the same repo to prevent duplicate
|
|
# build jobs (the push event already covers them).
|
|
# Exception: chore/update-lockfile PRs (created by automation with GITHUB_TOKEN, which doesn't trigger push events)
|
|
if: ${{ !cancelled() && needs.changes.outputs.ts == 'true' && (github.event_name == 'push' || github.event_name == 'merge_group' || github.event.pull_request.head.repo.full_name != github.repository || github.head_ref == 'chore/update-lockfile') }}
|
|
|
|
name: TS CI / Compile & Lint
|
|
runs-on: ubuntu-latest
|
|
|
|
steps:
|
|
- name: Checkout Commit
|
|
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
|
|
with:
|
|
persist-credentials: false
|
|
- name: Install pnpm
|
|
uses: pnpm/setup@b1cac37306e39c21283b9dd6cb0ac288fb35ba6b
|
|
- name: Compile TypeScript
|
|
run: pn compile-only
|
|
- name: Lint
|
|
run: pn lint
|
|
- name: Package compiled artifacts
|
|
shell: bash
|
|
run: |
|
|
mapfile -d '' -t lib_dirs < <(find . -type d -name lib -not -path '*/node_modules/*' -print0)
|
|
mapfile -d '' -t tsbuildinfo_files < <(find . -name 'tsconfig.tsbuildinfo' -not -path '*/node_modules/*' -print0)
|
|
tar -czf compiled.tar.gz --exclude='node_modules' "${lib_dirs[@]}" "${tsbuildinfo_files[@]}" pnpm11/pnpm/dist
|
|
- name: Upload compiled artifacts
|
|
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
|
|
with:
|
|
name: compiled-packages
|
|
path: compiled.tar.gz
|
|
retention-days: 1
|
|
|
|
# Build the pnpr server and registry fixture preparer once per OS, then
|
|
# share the binaries with every test job/shard as an artifact. Building
|
|
# inside each test job instead rebuilt pnpr once per shard, because the
|
|
# parallel shards all miss the build cache at job start.
|
|
build-pnpr:
|
|
needs: changes
|
|
if: ${{ !cancelled() && needs.changes.outputs.ts == 'true' && (github.event_name == 'push' || github.event_name == 'merge_group' || github.event.pull_request.head.repo.full_name != github.repository || github.head_ref == 'chore/update-lockfile') }}
|
|
name: TS CI / Build pnpr / ${{ matrix.os }}
|
|
strategy:
|
|
fail-fast: false
|
|
matrix:
|
|
os: [ubuntu-latest, windows-latest]
|
|
runs-on: ${{ matrix.os }}
|
|
steps:
|
|
- name: Free up runner disk space
|
|
if: ${{ runner.os == 'Linux' }}
|
|
run: |
|
|
sudo rm -rf /usr/share/dotnet /usr/local/lib/android /opt/ghc /opt/hostedtoolcache/CodeQL
|
|
df -h /
|
|
- name: Checkout Commit
|
|
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
|
|
with:
|
|
persist-credentials: false
|
|
# The binaries are cached and keyed on the Rust sources that produce them,
|
|
# so a run that only touches TypeScript restores them in seconds instead of
|
|
# recompiling. They are copied out of `target/` into a stable dir so
|
|
# `Swatinem/rust-cache`'s `target/` cleanup can't strip them before the
|
|
# cache saves.
|
|
- name: Restore prebuilt pnpr binaries
|
|
id: pnpr-bins
|
|
uses: actions/cache/restore@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5
|
|
with:
|
|
path: .pnpr-bin
|
|
key: pnpr-bins-${{ runner.os }}-${{ hashFiles('rust-toolchain.toml', '**/Cargo.lock', '**/Cargo.toml', 'pnpr/**/*.rs', 'pacquet/**/*.rs') }}
|
|
- name: Install Rust
|
|
if: steps.pnpr-bins.outputs.cache-hit != 'true'
|
|
uses: ./.github/actions/rustup
|
|
with:
|
|
save-cache: ${{ github.ref_name == 'main' }}
|
|
shared-key: registry-prepare
|
|
- name: Build the pnpr server and registry fixture preparer
|
|
if: steps.pnpr-bins.outputs.cache-hit != 'true'
|
|
shell: bash
|
|
run: |
|
|
cargo build --locked --release -p pnpr --bin pnpr -p pnpr-fixtures --bin pnpr-prepare
|
|
mkdir -p .pnpr-bin
|
|
ext=""
|
|
[ -f target/release/pnpr.exe ] && ext=".exe"
|
|
cp "target/release/pnpr$ext" "target/release/pnpr-prepare$ext" .pnpr-bin/
|
|
# Save the binaries to the cache right after they build, not in a post-job
|
|
# step: a later step failing would otherwise skip the save and force a full
|
|
# Rust rebuild on the next run.
|
|
- name: Save prebuilt pnpr binaries
|
|
if: steps.pnpr-bins.outputs.cache-hit != 'true'
|
|
uses: actions/cache/save@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5
|
|
with:
|
|
path: .pnpr-bin
|
|
key: ${{ steps.pnpr-bins.outputs.cache-primary-key }}
|
|
- name: Upload pnpr binaries
|
|
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
|
|
with:
|
|
name: pnpr-bins-${{ runner.os }}
|
|
path: .pnpr-bin
|
|
# `.pnpr-bin` is a dotfile dir, which upload-artifact skips by default.
|
|
include-hidden-files: true
|
|
if-no-files-found: error
|
|
retention-days: 1
|
|
|
|
test-smoke:
|
|
name: TS CI / Test / ubuntu
|
|
needs: [compile-and-lint, build-pnpr]
|
|
uses: ./.github/workflows/test.yml
|
|
with:
|
|
node: '24.0.0'
|
|
node_major: '24'
|
|
platform: ubuntu-latest
|
|
garnet: true
|
|
secrets:
|
|
GARNET_API_TOKEN: ${{ secrets.GARNET_API_TOKEN }}
|
|
|
|
test:
|
|
name: TS CI / Test / ${{ matrix.platform_label }}
|
|
needs: test-smoke
|
|
strategy:
|
|
fail-fast: false
|
|
matrix:
|
|
include:
|
|
- node: '22.13.0'
|
|
node_major: '22'
|
|
platform: ubuntu-latest
|
|
platform_label: ubuntu
|
|
test_chunk: '1'
|
|
test_chunk_total: '1'
|
|
- node: '26.3.1'
|
|
node_major: '26'
|
|
platform: ubuntu-latest
|
|
platform_label: ubuntu
|
|
test_chunk: '1'
|
|
test_chunk_total: '1'
|
|
uses: ./.github/workflows/test.yml
|
|
with:
|
|
node: ${{ matrix.node }}
|
|
node_major: ${{ matrix.node_major }}
|
|
platform: ${{ matrix.platform }}
|
|
test_chunk: ${{ matrix.test_chunk }}
|
|
test_chunk_total: ${{ matrix.test_chunk_total }}
|
|
|
|
# Windows is the slowest platform. Gate it only on compile-and-lint so its
|
|
# shards run in parallel with the ubuntu smoke job, instead of waiting for
|
|
# the smoke job like the other Node.js versions do.
|
|
test-windows:
|
|
name: TS CI / Test / ${{ matrix.platform_label }}
|
|
needs: [compile-and-lint, build-pnpr]
|
|
strategy:
|
|
fail-fast: false
|
|
matrix:
|
|
include:
|
|
- node: '22.13.0'
|
|
node_major: '22'
|
|
platform: windows-latest
|
|
platform_label: windows 1/3
|
|
test_chunk: '1'
|
|
test_chunk_total: '3'
|
|
- node: '22.13.0'
|
|
node_major: '22'
|
|
platform: windows-latest
|
|
platform_label: windows 2/3
|
|
test_chunk: '2'
|
|
test_chunk_total: '3'
|
|
- node: '22.13.0'
|
|
node_major: '22'
|
|
platform: windows-latest
|
|
platform_label: windows 3/3
|
|
test_chunk: '3'
|
|
test_chunk_total: '3'
|
|
uses: ./.github/workflows/test.yml
|
|
with:
|
|
node: ${{ matrix.node }}
|
|
node_major: ${{ matrix.node_major }}
|
|
platform: ${{ matrix.platform }}
|
|
test_chunk: ${{ matrix.test_chunk }}
|
|
test_chunk_total: ${{ matrix.test_chunk_total }}
|
|
|
|
# Single aggregate gate — the only TS CI context branch protection needs
|
|
# to require. Listing the individual jobs as required checks does not
|
|
# work: they skip on non-TypeScript PRs, and a matrix job skipped at the
|
|
# job level never expands its `${{ matrix.* }}` name, so the per-platform
|
|
# contexts it would report never appear and the PR blocks forever waiting
|
|
# for them. This job always runs (it reports under a static name in every
|
|
# state) and fails only if a dependency actually failed or was cancelled —
|
|
# skipped dependencies count as a pass.
|
|
success:
|
|
name: TS CI / Success
|
|
if: ${{ always() }}
|
|
needs:
|
|
- changes
|
|
- compile-and-lint
|
|
- build-pnpr
|
|
- test-smoke
|
|
- test
|
|
- test-windows
|
|
runs-on: ubuntu-latest
|
|
steps:
|
|
- name: Fail if any dependency failed or was cancelled
|
|
if: ${{ contains(needs.*.result, 'failure') || contains(needs.*.result, 'cancelled') }}
|
|
run: exit 1
|