From 7f97d6ff407c66ea27a9a5c19f19470ac5ac54c8 Mon Sep 17 00:00:00 2001 From: Luke Bennett Date: Tue, 22 Sep 2026 16:44:28 +1000 Subject: [PATCH] Pin pnpm with mise (#637) --- .github/renovate.json5 | 15 +++++++----- .github/workflows/check.yml | 11 ++++----- .github/workflows/release.yml | 7 ++---- .github/workflows/test.yml | 24 +++++++------------ .github/workflows/visual-baseline.yml | 13 ++++------ .github/workflows/visual-regression.yml | 17 ++++++------- docs/DEPENDENCIES.md | 19 ++++++++------- mise.toml | 1 + package.json | 2 +- .../react/scripts/visual-regression.ts | 4 ++-- 10 files changed, 50 insertions(+), 63 deletions(-) diff --git a/.github/renovate.json5 b/.github/renovate.json5 index b033dd14..76d1e0d8 100644 --- a/.github/renovate.json5 +++ b/.github/renovate.json5 @@ -7,9 +7,9 @@ ], labels: ['dependencies'], - // pnpm refuses to resolve any release younger than `minimumReleaseAge: 7200` (5 days) in + // pnpm refuses to resolve any release younger than `minimumReleaseAge: 4320` (3 days) in // pnpm-workspace.yaml, so a PR raised for a fresher release cannot generate a lockfile. - minimumReleaseAge: '5 days', + minimumReleaseAge: '3 days', // Hold the branch back until the release is old enough instead of opening a PR that cannot install. internalChecksFilter: 'strict', @@ -29,7 +29,7 @@ automerge: false, }, - // Security fixes skip the quarantine. pnpm does not: a fix younger than 5 days still needs a + // Security fixes skip the quarantine. pnpm does not: a fix younger than 3 days still needs a // `minimumReleaseAgeExclude` entry added by hand before the lockfile will resolve. vulnerabilityAlerts: { minimumReleaseAge: null, @@ -116,6 +116,7 @@ // `24.19.0`, and it landed in the non-major group rather than a Node one. { matchManagers: ['mise'], + matchDepNames: ['node'], groupName: 'node', rangeStrategy: 'replace', automerge: false, @@ -129,10 +130,12 @@ automerge: false, }, { - // Moving the pinned pnpm version changes how every install resolves, including the quarantine - // and trust policy checks. - matchDepTypes: ['packageManager'], + // pnpm is declared in mise and packageManager. Keep the tool mise installs and the project + // declaration in one PR, with the regenerated lockfile. + matchManagers: ['mise', 'npm'], + matchDepNames: ['pnpm'], groupName: 'pnpm', + rangeStrategy: 'replace', automerge: false, }, { diff --git a/.github/workflows/check.yml b/.github/workflows/check.yml index c7b4b40c..3e4db148 100644 --- a/.github/workflows/check.yml +++ b/.github/workflows/check.yml @@ -33,11 +33,8 @@ jobs: install: true cache: true - - name: Enable Corepack - run: corepack enable - - name: Install dependencies - run: corepack pnpm install --frozen-lockfile + run: pnpm install --frozen-lockfile - name: Run checks env: @@ -49,11 +46,11 @@ jobs: # check:cycles check:unused`), so CI and local checks are the same task graph — barrels, # root format, package format, lint, and types. `--affected` is added here only as a PR # speed optimisation and is never applied to the unscoped knip runs. - corepack pnpm exec turbo run check ${{ github.event_name == 'pull_request' && '--affected' || '' }} + pnpm exec turbo run check ${{ github.event_name == 'pull_request' && '--affected' || '' }} # knip is repo-wide, but --affected only selects packages whose own files # changed, so it must run unscoped. Running it via turbo (rather than the # bare `knip` script) pulls in its generate dependencies first. - corepack pnpm exec turbo run check:cycles check:unused - corepack pnpm exec turbo run test \ + pnpm exec turbo run check:cycles check:unused + pnpm exec turbo run test \ --filter=@luke-ui/turbo-generators \ --filter=@luke-ui/workflow-scripts diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 6196d1c5..4800b26c 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -21,18 +21,15 @@ jobs: # - name: Setup Tooling with mise # uses: jdx/mise-action@v4 - # - name: Enable Corepack - # run: corepack enable - # - name: Install Dependencies - # run: corepack pnpm install --frozen-lockfile + # run: pnpm install --frozen-lockfile # - name: Create Release Pull Request or Publish to npm # id: changesets # uses: changesets/action@v2 # with: # # This expects you to have a script called release which does a build for your packages and calls changeset publish - # publish: corepack pnpm release + # publish: pnpm release # env: # GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} # NPM_TOKEN: ${{ secrets.NPM_TOKEN }} diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index d38089f8..7432b76c 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -32,20 +32,17 @@ jobs: install: true cache: true - - name: Enable Corepack - run: corepack enable - - name: Install dependencies - run: corepack pnpm install --frozen-lockfile + run: pnpm install --frozen-lockfile - name: Install Playwright Chromium - run: corepack pnpm --filter @luke-ui/react exec playwright install --with-deps chromium + run: pnpm --filter @luke-ui/react exec playwright install --with-deps chromium - name: Build package - run: corepack pnpm build:packages + run: pnpm build:packages - name: Run component tests - run: corepack pnpm --filter @luke-ui/react run test:ci + run: pnpm --filter @luke-ui/react run test:ci docs-tests: name: docs-tests @@ -64,20 +61,17 @@ jobs: install: true cache: true - - name: Enable Corepack - run: corepack enable - - name: Install dependencies - run: corepack pnpm install --frozen-lockfile + run: pnpm install --frozen-lockfile - name: Install Playwright Chromium - run: corepack pnpm --filter docs exec playwright install --with-deps chromium + run: pnpm --filter docs exec playwright install --with-deps chromium - name: Build package - run: corepack pnpm build:packages + run: pnpm build:packages - name: Generate docs app files - run: corepack pnpm --filter docs run generate + run: pnpm --filter docs run generate - name: Run docs tests - run: corepack pnpm --filter docs run test + run: pnpm --filter docs run test diff --git a/.github/workflows/visual-baseline.yml b/.github/workflows/visual-baseline.yml index e9c3e1f0..08b089d5 100644 --- a/.github/workflows/visual-baseline.yml +++ b/.github/workflows/visual-baseline.yml @@ -39,27 +39,24 @@ jobs: install: true cache: true - - name: Enable Corepack - run: corepack enable - - name: Install dependencies - run: corepack pnpm install --frozen-lockfile + run: pnpm install --frozen-lockfile - name: Install Playwright Chromium - run: corepack pnpm --filter @luke-ui/react exec playwright install --with-deps chromium + run: pnpm --filter @luke-ui/react exec playwright install --with-deps chromium - name: Build packages - run: corepack pnpm build:packages + run: pnpm build:packages - name: Render baseline captures env: VISUAL_CAPTURE_DIR: ${{ github.workspace }}/.artifacts/visual-regression/baseline - run: corepack pnpm --filter @luke-ui/react run test:visual:capture + run: pnpm --filter @luke-ui/react run test:visual:capture - name: Fail when nothing rendered env: VISUAL_CAPTURE_DIR: ${{ github.workspace }}/.artifacts/visual-regression/baseline - run: corepack pnpm --filter @luke-ui/workflow-scripts run visual-ci check-captures + run: pnpm --filter @luke-ui/workflow-scripts run visual-ci check-captures - name: Upload baseline uses: actions/upload-artifact@v7 diff --git a/.github/workflows/visual-regression.yml b/.github/workflows/visual-regression.yml index c66237ec..fb06ee97 100644 --- a/.github/workflows/visual-regression.yml +++ b/.github/workflows/visual-regression.yml @@ -38,17 +38,14 @@ jobs: install: true cache: true - - name: Enable Corepack - run: corepack enable - - name: Install dependencies - run: corepack pnpm install --frozen-lockfile + run: pnpm install --frozen-lockfile - name: Resolve baseline id: baseline env: GITHUB_TOKEN: ${{ github.token }} - run: corepack pnpm --filter @luke-ui/workflow-scripts run visual-ci resolve-baseline + run: pnpm --filter @luke-ui/workflow-scripts run visual-ci resolve-baseline - name: Download baseline uses: actions/download-artifact@v7 @@ -60,20 +57,20 @@ jobs: run-id: ${{ steps.baseline.outputs.run-id }} - name: Fail when the baseline has no screenshots - run: corepack pnpm --filter @luke-ui/workflow-scripts run visual-ci check-captures + run: pnpm --filter @luke-ui/workflow-scripts run visual-ci check-captures - name: Install Playwright Chromium - run: corepack pnpm --filter @luke-ui/react exec playwright install --with-deps chromium + run: pnpm --filter @luke-ui/react exec playwright install --with-deps chromium - name: Build packages - run: corepack pnpm build:packages + run: pnpm build:packages - name: Compare against the baseline - run: corepack pnpm --filter @luke-ui/react run test:visual + run: pnpm --filter @luke-ui/react run test:visual - name: Summarise the comparison id: summary - run: corepack pnpm --filter @luke-ui/workflow-scripts run visual-ci summarise + run: pnpm --filter @luke-ui/workflow-scripts run visual-ci summarise - name: Upload expected, actual, and diff screenshots if: always() diff --git a/docs/DEPENDENCIES.md b/docs/DEPENDENCIES.md index 6502ee07..f0ea5be1 100644 --- a/docs/DEPENDENCIES.md +++ b/docs/DEPENDENCIES.md @@ -18,13 +18,13 @@ Two entries are not plain versions: ## The release quarantine -`minimumReleaseAge: 4320` (3 days) stops pnpm resolving any release, direct or transitive, that is -younger than five days. `.github/renovate.json5` sets the same `minimumReleaseAge: '3 days'` so -Renovate never opens a pull request for a release pnpm will refuse to install. +`minimumReleaseAge: 4320` is exactly three days. It stops pnpm resolving any release, direct or +transitive, that is younger than three days. `.github/renovate.json5` sets +`minimumReleaseAge: '3 days'`, so Renovate and pnpm use the same three-day quarantine. The two settings do not cover the same ground. Renovate's applies to the dependency it is updating. -pnpm's applies to everything the update pulls in. A bump to a five-day-old release can still drag in -a transitive package published yesterday, and the lockfile update then fails. +pnpm's applies to everything the update pulls in. A bump to a three-day-old release can still drag +in a transitive package published yesterday, and the lockfile update then fails. `trustLockfile: true` means the check is not re-run against entries already in the lockfile, so this only bites when a lockfile is generated, never on a plain `pnpm install --frozen-lockfile` in CI. @@ -80,12 +80,13 @@ an exclude list entry before they will install, which no amount of green CI will ## Tooling versions -`mise.toml` pins the Node major. Renovate's `mise` manager tracks it and its node versioning treats +`mise.toml` pins and installs pnpm. The root `package.json` `packageManager` field repeats the exact +version for metadata and tooling. Renovate groups both declarations. Omitting the hash avoids +Renovate's Corepack-based hash regeneration. + +`mise.toml` pins the Node major. Renovate's `mise` manager tracks it, and its node versioning treats odd majors as unstable, so it will only propose the next LTS line. The four workflows in `.github/workflows` pin actions at the major tag, so the only update Renovate can offer is a major tag move. They group into one `github actions` pull request and are never automerged. - -The `packageManager` field in the root `package.json` pins pnpm. Renovate updates it, including the -integrity hash, in its own pull request. diff --git a/mise.toml b/mise.toml index 6ea5a7e1..b54376ea 100644 --- a/mise.toml +++ b/mise.toml @@ -1,2 +1,3 @@ [tools] node = "24" +pnpm = "12.4.2" diff --git a/package.json b/package.json index 97029df4..7744950f 100644 --- a/package.json +++ b/package.json @@ -42,5 +42,5 @@ "engines": { "node": "24.x" }, - "packageManager": "pnpm@12.4.2+sha512.08adc6613180275c7c9edada39dcf08c9c61ad4e7eaf330a4f3461f102b0f907423454d117f98e72d47fef0616070644d7bffc973a6a57f5090a6d7c368b07c9" + "packageManager": "pnpm@12.4.2" } diff --git a/packages/@luke-ui/react/scripts/visual-regression.ts b/packages/@luke-ui/react/scripts/visual-regression.ts index ea79e7bc..8d62bbb7 100644 --- a/packages/@luke-ui/react/scripts/visual-regression.ts +++ b/packages/@luke-ui/react/scripts/visual-regression.ts @@ -48,8 +48,8 @@ async function captureCurrent() { await rm(currentDir, { force: true, recursive: true }); await mkdir(currentDir, { recursive: true }); execFileSync( - 'corepack', - ['pnpm', 'exec', 'vp', 'test', 'run', '--project=browser', "--tagsFilter='visual'", '--update'], + 'pnpm', + ['exec', 'vp', 'test', 'run', '--project=browser', "--tagsFilter='visual'", '--update'], { cwd: packageRoot, env: { ...process.env, [VISUAL_CAPTURE_DIR_ENV]: currentDir }, -- 2.51.2