From 5ba3c2107409726a3798e9afd921b4fc46b7dae5 Mon Sep 17 00:00:00 2001 From: Zoltan Kochan Date: Thu, 30 Jul 2026 21:08:10 +0200 Subject: [PATCH] feat: add update-pnpm-minimum-release-age input pnpm 12 defaults minimumReleaseAge to 24 hours, and pnpm self-update deliberately drops the repository's release-age settings (including minimumReleaseAgeExclude) so a repo cannot decide whether the binary may be replaced. On CI, where no user-level config exists, the built-in cutoff therefore applies to pnpm itself: a dist-tag pointing at a release younger than 24 hours is silently resolved to the newest mature version, and update-pnpm cannot move to a same-day release. The new input sets PNPM_CONFIG_MINIMUM_RELEASE_AGE for the self-update invocation only (env-level policy is honored by design), so workflows that follow prereleases can pass 0 and pick up a release immediately. The dependency update keeps the repository's own release-age settings. Co-Authored-By: Claude Fable 5 --- README.md | 5 +++++ action.yml | 12 ++++++++++++ scripts/update.sh | 5 +++++ test/stubs/pnpm | 12 +++++++++--- test/update.bats | 17 +++++++++++++++++ 5 files changed, 48 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index ebc1558..6c93303 100644 --- a/README.md +++ b/README.md @@ -85,6 +85,10 @@ prereleases while propagating updated versions into other files): with: update-deps: false update-pnpm: next-12 + # Follow prereleases as soon as they are published: pnpm 12's + # default 24-hour minimumReleaseAge would otherwise hold a + # same-day release back from self-update. + update-pnpm-minimum-release-age: 0 post-update: pnpm update-manifests token: ${{ secrets.UPDATE_TOKEN }} ``` @@ -124,6 +128,7 @@ CI runs both on every push and pull request. | `post-update` | — | Shell commands run after the updates, before verification; their changes are included in the PR. | | `changesets` | `true` | In repositories that use changesets: generate a changeset for the updated dependencies via `pnpm update --changeset` (patch for production deps, major for peer deps, and the same for packages consuming a changed `catalog:` entry). Private, ignored, and dev-only changes are skipped. Only applies in `latest`/`ranges` mode and when the installed pnpm supports `--changeset`. Set to `false` to disable. | | `update-pnpm` | pinned major | Bump pnpm itself via `pnpm self-update`. Defaults to the latest release of the currently pinned major; set a version, range, or dist-tag (`latest`, `12`, `next-12`) to move onto it, or `false` to skip. | +| `update-pnpm-minimum-release-age` | — | Override pnpm's `minimumReleaseAge` (in minutes) for the `pnpm self-update` step. pnpm 12 defaults the cutoff to 24 hours and self-update deliberately ignores the repository's `minimumReleaseAgeExclude`, so a freshly published pnpm release is held back until it matures. Set `0` to always move to the newest release the `update-pnpm` spec resolves to. Only affects the pnpm self-update; the dependency update keeps the repository's own release-age settings. | | `node` | pinned major | Bump the Node.js version pinned in `devEngines.runtime`. Defaults to the latest release of the currently pinned major (skipped when nothing is pinned); set `24`, `lts`, or `latest` to move onto it, or `false` to skip. | | `verify` | — | Shell commands run after updating (build, tests). If they fail, no PR is created. | | `commit-message` | `chore: update dependencies` | Message of the update commit. | diff --git a/action.yml b/action.yml index e5cbfb4..31ac5a1 100644 --- a/action.yml +++ b/action.yml @@ -78,6 +78,17 @@ inputs: version, range, or dist-tag (e.g. "latest", "12", "next-12") to move onto that instead, or "false" to skip. default: '' + update-pnpm-minimum-release-age: + description: >- + Override pnpm's `minimumReleaseAge` (in minutes) for the `pnpm + self-update` step, via `PNPM_CONFIG_MINIMUM_RELEASE_AGE`. pnpm 12 + defaults the cutoff to 24 hours and self-update deliberately ignores the + repository's `minimumReleaseAgeExclude`, so a freshly published pnpm + release is silently held back until it matures. Set to "0" to always + move to the newest release the update-pnpm spec resolves to. Empty + keeps pnpm's default behavior. Only affects the pnpm self-update; the + dependency update keeps the repository's own release-age settings. + default: '' node: description: >- How to update the Node.js version pinned in devEngines.runtime. By @@ -127,6 +138,7 @@ runs: INCLUDE_GITHUB_ACTIONS: ${{ inputs.github-actions }} CHANGESETS: ${{ inputs.changesets }} UPDATE_PNPM: ${{ inputs.update-pnpm }} + UPDATE_PNPM_MINIMUM_RELEASE_AGE: ${{ inputs.update-pnpm-minimum-release-age }} NODE: ${{ inputs.node }} run: bash "$GITHUB_ACTION_PATH/scripts/update.sh" diff --git a/scripts/update.sh b/scripts/update.sh index b6efa7f..3bcdc71 100755 --- a/scripts/update.sh +++ b/scripts/update.sh @@ -69,6 +69,11 @@ fi # Last, so every earlier step runs on the pnpm the workflow installed. if [ "$UPDATE_PNPM" != "false" ]; then + # Scoped to self-update: everything before this point already ran, so the + # dependency update keeps the repository's own release-age settings. + if [ -n "$UPDATE_PNPM_MINIMUM_RELEASE_AGE" ]; then + export PNPM_CONFIG_MINIMUM_RELEASE_AGE="$UPDATE_PNPM_MINIMUM_RELEASE_AGE" + fi if [ -n "$UPDATE_PNPM" ]; then pnpm self-update "$UPDATE_PNPM" else diff --git a/test/stubs/pnpm b/test/stubs/pnpm index cf33b08..5e62e26 100755 --- a/test/stubs/pnpm +++ b/test/stubs/pnpm @@ -1,9 +1,15 @@ #!/usr/bin/env bash -# Test stub for `pnpm`: records every invocation to $PNPM_LOG and answers the -# few queries scripts/update.sh makes. Behavior is tuned via env vars: +# Test stub for `pnpm`: records every invocation to $PNPM_LOG (prefixed with +# PNPM_CONFIG_MINIMUM_RELEASE_AGE= when that variable is set, so tests +# can assert on its scoping) and answers the few queries scripts/update.sh +# makes. Behavior is tuned via env vars: # STUB_SUPPORTS_CHANGESET "1" (default) => `update --help` lists --changeset # STUB_PNPM_VERSION version printed by `pnpm --version` (default 11.5.0) -printf '%s\n' "$*" >> "$PNPM_LOG" +prefix='' +if [ -n "${PNPM_CONFIG_MINIMUM_RELEASE_AGE:-}" ]; then + prefix="PNPM_CONFIG_MINIMUM_RELEASE_AGE=$PNPM_CONFIG_MINIMUM_RELEASE_AGE " +fi +printf '%s\n' "$prefix$*" >> "$PNPM_LOG" if [ "$1" = "--version" ]; then echo "${STUB_PNPM_VERSION:-11.5.0}" diff --git a/test/update.bats b/test/update.bats index e9e32ef..88f64c8 100644 --- a/test/update.bats +++ b/test/update.bats @@ -23,6 +23,7 @@ setup() { export INCLUDE_GITHUB_ACTIONS=false export CHANGESETS=true export UPDATE_PNPM=false + export UPDATE_PNPM_MINIMUM_RELEASE_AGE='' export NODE='' printf '%s' '{"name":"fixture","devEngines":{"runtime":{"name":"node","version":"^24.4.0"}}}' > package.json } @@ -135,3 +136,19 @@ teardown() { run bash "$SCRIPT" ! grep -Fq 'self-update' "$PNPM_LOG" } + +@test "update-pnpm-minimum-release-age applies to self-update only" { + export UPDATE_PNPM=next-12 + export UPDATE_PNPM_MINIMUM_RELEASE_AGE=0 + run bash "$SCRIPT" + [ "$status" -eq 0 ] + grep -Fqx 'update --recursive --latest --changeset' "$PNPM_LOG" + grep -Fqx 'PNPM_CONFIG_MINIMUM_RELEASE_AGE=0 self-update next-12' "$PNPM_LOG" +} + +@test "update-pnpm-minimum-release-age unset leaves self-update env alone" { + export UPDATE_PNPM=next-12 + run bash "$SCRIPT" + grep -Fqx 'self-update next-12' "$PNPM_LOG" + ! grep -Fq 'PNPM_CONFIG_MINIMUM_RELEASE_AGE' "$PNPM_LOG" +}