-
Notifications
You must be signed in to change notification settings - Fork 0
feat: initial version of the pnpm/update action #1
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from 4 commits
Commits
Show all changes
13 commits
Select commit
Hold shift + click to select a range
17326a2
feat: initial version of the pnpm/update action
zkochan c47e161
fix: base updates on the base branch, keep the token off the command …
zkochan 1ecbc4f
feat: update pnpm and the pinned runtime by default, within their cur…
zkochan 9e5973c
fix: unset persisted credentials on GitHub Enterprise Server too
zkochan d8cc10c
feat: refresh the lockfile by default, add update-deps and post-updat…
zkochan 70533cf
feat: generate changesets for packages whose production dependencies …
zkochan eac38c2
feat: update GitHub Actions too, with pnpm update --include-github-ac…
zkochan d814d12
refactor: make GitHub Actions updates opt-in (default off)
zkochan d9dc264
test: extract pure logic into scripts/lib.sh with bats unit tests + CI
zkochan cb81a1c
feat: generate changesets via native pnpm update --changeset
zkochan f7f2d4e
test: end-to-end tests for the update step against a stubbed pnpm
zkochan dc7b47b
ci: run bats via npx to avoid global-install permission errors
zkochan cab2c6a
ci: run tests with pnpm's pnx instead of npx
zkochan File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,65 @@ | ||
| # pnpm/update | ||
|
|
||
| Updates the dependencies of your project with `pnpm update`, keeps the pinned | ||
| pnpm (`packageManager` / `devEngines.packageManager`) and Node.js | ||
| (`devEngines.runtime`) versions fresh — by default within their current major | ||
| versions — and opens a pull request with the result. | ||
|
|
||
| Unlike external dependency bots, this action runs pnpm itself, so it supports | ||
| every feature of your workspace: catalogs, patched dependencies, config | ||
| dependencies, overrides, and anything pnpm learns in the future. | ||
|
|
||
| The action expects pnpm (and a runtime, if your project needs one for | ||
| verification) to already be set up — pair it with [`pnpm/setup`]. | ||
|
|
||
| ## Usage | ||
|
|
||
| ```yaml | ||
| name: Update Dependencies | ||
|
|
||
| on: | ||
| schedule: | ||
| - cron: '0 0 * * 1' # Every Monday at midnight UTC | ||
| workflow_dispatch: {} | ||
|
|
||
| permissions: | ||
| contents: write | ||
| pull-requests: write | ||
|
|
||
| concurrency: | ||
| group: update-dependencies | ||
| cancel-in-progress: false | ||
|
|
||
| jobs: | ||
| update-dependencies: | ||
| if: github.repository == 'your-org/your-repo' # Don't run on forks | ||
| runs-on: ubuntu-24.04 | ||
| steps: | ||
| - uses: actions/checkout@v6 | ||
| # Installs the pnpm version from `packageManager` and the runtime | ||
| # from `devEngines.runtime`. | ||
| - uses: pnpm/setup@v1 | ||
| - uses: pnpm/update@v0 | ||
| with: | ||
| verify: | | ||
| pnpm build | ||
| pnpm test | ||
| ``` | ||
|
|
||
| [`pnpm/setup`]: https://github.com/pnpm/setup | ||
|
|
||
| ## Inputs | ||
|
|
||
| | Input | Default | Description | | ||
| |---|---|---| | ||
| | `token` | `github.token` | Token used to push the branch and create the PR. PRs created with the default `GITHUB_TOKEN` don't trigger other workflows; pass a GitHub App token or PAT if you want CI to run on the PR. | | ||
| | `branch` | `chore/update-dependencies` | Branch the updates are pushed to (force-pushed on every run, so at most one update PR stays open). | | ||
| | `base` | repository default branch | Branch the updates are based on and the pull request targets. | | ||
| | `latest` | `true` | Update to the latest versions, ignoring `package.json` ranges. Set to `false` to update within ranges. | | ||
| | `exclude` | — | Whitespace-separated package name patterns that should not be updated, e.g. `typescript @types/*`. | | ||
| | `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. | | ||
| | `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. | | ||
| | `pr-title` | `chore: update dependencies` | Title of the pull request. | | ||
| | `pr-body` | Automated dependency updates… | Body of the pull request. | |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,171 @@ | ||
| name: 'pnpm update' | ||
| description: 'Update dependencies (and optionally pnpm and the runtime) with pnpm, then open a pull request' | ||
| branding: | ||
| icon: 'refresh-cw' | ||
| color: 'orange' | ||
| inputs: | ||
| token: | ||
| description: >- | ||
| Token used to push the update branch and create the pull request. | ||
| Pull requests created with the default GITHUB_TOKEN do not trigger other | ||
| workflows; pass a GitHub App token or PAT if you want CI to run on the PR. | ||
| default: ${{ github.token }} | ||
| branch: | ||
| description: >- | ||
| Branch the updates are pushed to. It is force-pushed on every run, so at | ||
| most one update PR stays open at a time. | ||
| default: 'chore/update-dependencies' | ||
| base: | ||
| description: 'Branch the updates are based on and the pull request targets.' | ||
| default: ${{ github.event.repository.default_branch }} | ||
| latest: | ||
| description: >- | ||
| Update dependencies to their latest versions, ignoring the ranges | ||
| declared in package.json. Set to "false" to update within ranges. | ||
| default: 'true' | ||
| exclude: | ||
| description: >- | ||
| Whitespace-separated package name patterns that should not be updated. | ||
| Example: "typescript @types/*" | ||
| default: '' | ||
| update-pnpm: | ||
| description: >- | ||
| How to update the pinned pnpm version (packageManager and | ||
| devEngines.packageManager) via `pnpm self-update`. By default, updates | ||
| to the latest release of the currently pinned major version. Set to a | ||
| version, range, or dist-tag (e.g. "latest", "12", "next-12") to move | ||
| onto that instead, or "false" to skip. | ||
| default: '' | ||
| node: | ||
| description: >- | ||
| How to update the Node.js version pinned in devEngines.runtime. By | ||
| default, updates to the latest release of the currently pinned major | ||
| version (skipped when no Node.js version is pinned). Set to a spec | ||
| accepted by `pnpm runtime set node` (e.g. "24", "lts", "latest") to | ||
| move onto that instead, or "false" to skip. | ||
| default: '' | ||
| verify: | ||
| description: >- | ||
| Shell commands run after updating (e.g. build and tests). If they fail, | ||
| no pull request is created. | ||
| default: '' | ||
| commit-message: | ||
| description: 'Message of the update commit.' | ||
| default: 'chore: update dependencies' | ||
| pr-title: | ||
| description: 'Title of the pull request.' | ||
| default: 'chore: update dependencies' | ||
| pr-body: | ||
| description: 'Body of the pull request.' | ||
| default: 'Automated dependency updates generated with `pnpm update`.' | ||
| runs: | ||
| using: 'composite' | ||
| steps: | ||
| - name: Prepare the update branch | ||
| shell: bash | ||
| env: | ||
| BRANCH: ${{ inputs.branch }} | ||
| BASE: ${{ inputs.base }} | ||
| run: | | ||
| set -euo pipefail | ||
| git config user.name "github-actions[bot]" | ||
| git config user.email "github-actions[bot]@users.noreply.github.com" | ||
| # Base the update on the latest base branch, even when the workflow | ||
| # was dispatched from another ref or the checkout is shallow. | ||
| git fetch origin "$BASE" | ||
| git checkout -B "$BRANCH" FETCH_HEAD | ||
|
|
||
| - name: Update dependencies | ||
| shell: bash | ||
| env: | ||
| LATEST: ${{ inputs.latest }} | ||
| EXCLUDE: ${{ inputs.exclude }} | ||
| UPDATE_PNPM: ${{ inputs.update-pnpm }} | ||
| NODE: ${{ inputs.node }} | ||
| run: | | ||
| set -euo pipefail | ||
| # Keep patterns like "@types/*" from glob-expanding against the repo. | ||
| set -f | ||
|
|
||
| args=(--recursive) | ||
| if [ "$LATEST" = "true" ]; then | ||
| args+=(--latest) | ||
| fi | ||
| for pattern in $EXCLUDE; do | ||
| args+=("!$pattern") | ||
| done | ||
| pnpm update "${args[@]}" | ||
|
|
||
| if [ "$NODE" != "false" ]; then | ||
| if [ -n "$NODE" ]; then | ||
| pnpm runtime set node "$NODE" | ||
| else | ||
| # Stay on the pinned major and only refresh within it: crossing | ||
| # toolchain majors usually needs coordinated changes (Dockerfiles, | ||
| # CI matrices, @types/node) that this job cannot make. | ||
| PINNED="$(jq -r '.devEngines.runtime // empty | ||
| | if type == "array" then .[] else . end | ||
| | select(.name == "node") | .version // empty' package.json | head -n 1 || true)" | ||
| if [ -n "$PINNED" ]; then | ||
| pnpm runtime set node "$(printf '%s' "$PINNED" | grep -oE '[0-9]+' | head -n 1)" | ||
| else | ||
| echo "No Node.js version pinned in devEngines.runtime; skipping the runtime update." | ||
| fi | ||
| fi | ||
| fi | ||
|
|
||
| # Last, so every earlier step runs on the pnpm the workflow installed. | ||
| if [ "$UPDATE_PNPM" != "false" ]; then | ||
| if [ -n "$UPDATE_PNPM" ]; then | ||
| pnpm self-update "$UPDATE_PNPM" | ||
| else | ||
| # A major bump of pnpm can rewrite the whole lockfile; keep that | ||
| # out of routine update PRs by staying on the pinned major. | ||
| pnpm self-update "$(pnpm --version | cut -d . -f 1)" | ||
| fi | ||
| fi | ||
|
|
||
| - name: Verify the updated project | ||
| if: ${{ inputs.verify != '' }} | ||
| shell: bash | ||
| run: ${{ inputs.verify }} | ||
|
|
||
| - name: Commit, push, and create the pull request | ||
| shell: bash | ||
| env: | ||
| GH_TOKEN: ${{ inputs.token }} | ||
| BRANCH: ${{ inputs.branch }} | ||
| BASE: ${{ inputs.base }} | ||
| COMMIT_MESSAGE: ${{ inputs.commit-message }} | ||
| PR_TITLE: ${{ inputs.pr-title }} | ||
| PR_BODY: ${{ inputs.pr-body }} | ||
| run: | | ||
| set -euo pipefail | ||
|
|
||
| if [ -z "$(git status --porcelain)" ]; then | ||
| echo "Everything is up to date." | ||
| exit 0 | ||
| fi | ||
|
|
||
| git add -A | ||
| git commit -m "$COMMIT_MESSAGE" | ||
|
|
||
| # Remove any credentials persisted by actions/checkout: they would | ||
| # take precedence over the token this action was given, silently | ||
| # downgrading a user-supplied PAT or App token to GITHUB_TOKEN. | ||
| git config --local --unset-all "http.${GITHUB_SERVER_URL:-https://github.com}/.extraheader" || true | ||
| # Supply the token through a credential helper (it reads GH_TOKEN | ||
| # from the environment) so it never appears on a command line. | ||
| git -c credential.helper= \ | ||
| -c credential.helper='!f() { echo username=x-access-token; echo "password=${GH_TOKEN}"; }; f' \ | ||
| push --force origin "$BRANCH" | ||
|
|
||
| # A PR left open by a previous run already points at the branch we | ||
| # just force-pushed, so there is nothing more to do. | ||
| if [ -z "$(gh pr list --head "$BRANCH" --state open --json number --jq '.[].number')" ]; then | ||
| gh pr create \ | ||
| --title "$PR_TITLE" \ | ||
| --body "$PR_BODY" \ | ||
| --base "$BASE" \ | ||
| --head "$BRANCH" | ||
| fi | ||
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.