Skip to content

feat: initial version of the pnpm/update action - #1

Merged
zkochan merged 13 commits into
mainfrom
init-action
Jul 23, 2026
Merged

feat: initial version of the pnpm/update action#1
zkochan merged 13 commits into
mainfrom
init-action

Conversation

@zkochan

@zkochan zkochan commented Jul 21, 2026

Copy link
Copy Markdown
Member

Initial implementation of the pnpm/update action: a composite action that updates the dependencies of a project with pnpm update, optionally bumps the pinned pnpm (packageManager / devEngines.packageManager) and Node.js (devEngines.runtime) versions, and opens a pull request with the result.

Design

  • Composite action — plain bash steps, no dist bundle to build and commit (unlike action-setup).
  • Composable — expects pnpm to already be installed, so it pairs with pnpm/setup (or pnpm/action-setup + actions/setup-node).
  • One persistent update branch — force-pushed on every run and reused by any still-open PR, so at most one update PR is open at a time (the same pattern as pnpm/pnpm's update-lockfile.yml workflow).
  • Token-explicit push — pushes via a single-use x-access-token URL, so it works with persist-credentials: false checkouts and with a GitHub App token / PAT (needed if the update PR should trigger CI workflows, which the default GITHUB_TOKEN does not).
  • Optional in-job verification — a verify input runs the project's own build/test commands after updating; if they fail, no PR is created.
  • Lockfile refresh by defaultpnpm-lock.yaml and node_modules are deleted before updating, so transitive dependencies of unchanged packages are freshly resolved too (the strategy of pnpm/pnpm's update-lockfile.yml); disable with refresh-lockfile: false.
  • Can update GitHub Actions too — opt-in (github-actions: true) bump of the actions pinned in .github/workflows/*.yml and action.yml via pnpm update --include-github-actions. Off by default because pushing workflow-file changes needs a token with the workflow scope (PAT) or workflows: write (App), which the default GITHUB_TOKEN lacks; the zero-secret default path leaves workflow files untouched.

Inputs

Input Default Purpose
update-deps latest latest ignores package.json ranges, ranges stays within them, false skips manifest updates (lockfile-refresh-only mode)
refresh-lockfile true Regenerate the lockfile from scratch so transitive deps are refreshed too; false keeps existing resolutions where possible
exclude Package name patterns whose ranges are held back, e.g. typescript @types/*
github-actions false Opt-in: also update GitHub Actions pinned in workflow / action.yml files (only in latest/ranges mode); needs a workflow-scoped token to push the changes
post-update Commands run after the updates, before verification (e.g. pnpm update-manifests); their changes are included in the PR
changesets true In changesets repos: generate a changeset via pnpm update --changeset (patch for prod deps, major for peer deps, catalog consumers included; skips private/ignored/dev-only). Needs a pnpm with --changeset support
update-pnpm pinned major Bump pnpm itself via pnpm self-update — within the pinned major by default; a version/dist-tag (latest, 12, next-12) to cross majors, or false to skip
node pinned major Bump the devEngines.runtime Node.js pin — within the pinned major by default (skipped when nothing is pinned); 24, lts, or latest to cross majors, or false to skip
verify Shell commands that must pass before a PR is opened
token, branch, base, commit-message, pr-title, pr-body sensible defaults Plumbing

After merging

Versioning starts at 0: tag v0.0.0 and point a floating v0 tag at it, matching how pnpm/setup is tagged. The usage example in the README references pnpm/update@v0.

The Automated Dependency Updates page being added to pnpm.io can then be simplified to recommend this action.

@coderabbitai

coderabbitai Bot commented Jul 21, 2026

Copy link
Copy Markdown

Review Change Stack

Warning

Review limit reached

@zkochan, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 55 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 6999d7b3-44b1-4ff9-9f86-179eec232b9b

📥 Commits

Reviewing files that changed from the base of the PR and between c47e161 and cab2c6a.

📒 Files selected for processing (8)
  • .github/workflows/test.yml
  • README.md
  • action.yml
  • scripts/lib.sh
  • scripts/update.sh
  • test/lib.bats
  • test/stubs/pnpm
  • test/update.bats
📝 Walkthrough

Walkthrough

Adds the pnpm/update composite GitHub Action and documentation. The action refreshes an update branch, updates dependencies and optional runtimes, verifies changes, then commits, pushes, and conditionally opens a pull request.

Changes

Dependency update action

Layer / File(s) Summary
Action contract and usage
action.yml, README.md
Defines public inputs for dependency updates, runtime changes, verification, branch selection, authentication, and pull request metadata, with an example workflow and behavior documentation.
Branch preparation and dependency updates
action.yml
Fetches the base branch, recreates the update branch, runs configured pnpm updates, optionally changes the Node runtime and pnpm version, and executes optional verification.
Commit, push, and pull request
action.yml
Skips unchanged trees, commits and pushes updates with token credentials, and creates a pull request only when no open pull request exists for the branch.

Estimated code review effort: 3 (Moderate) | ~20 minutes

Sequence Diagram(s)

sequenceDiagram
  participant GitHub Actions
  participant Git
  participant pnpm
  participant GitHub CLI

  GitHub Actions->>Git: Fetch base and recreate update branch
  GitHub Actions->>pnpm: Update dependencies and optional runtimes
  pnpm-->>GitHub Actions: Return updated working tree
  GitHub Actions->>Git: Commit and push changes
  GitHub Actions->>GitHub CLI: Check for existing open PR
  GitHub CLI-->>GitHub Actions: Return PR status
  GitHub Actions->>GitHub CLI: Create PR when none exists
Loading

Poem

A rabbit hops through pnpm’s lane,
Updating packages in the rain.
A branch is trimmed, a PR takes flight,
With checks performed and tokens right.
“Hop, hop!” says Bun, “the tree is bright!”

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly matches the PR’s main change: introducing the initial pnpm/update GitHub Action.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch init-action

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@qodo-code-review

Copy link
Copy Markdown

PR Summary by Qodo

Add initial pnpm/update composite action to open dependency update PRs

✨ Enhancement 📝 Documentation 🕐 20-40 Minutes

Grey Divider

AI Description

• Add a composite GitHub Action that runs pnpm update with optional exclude patterns.
• Optionally bump pinned Node (devEngines.runtime) and pnpm (pnpm self-update) versions.
• Commit, force-push a persistent update branch, and create/reuse a single open PR.
Diagram

graph TD
  A["Scheduled / manual workflow"] --> B["Run pnpm update"] --> C{"verify set?"}
  C --> D["Run verify commands"] --> E["Commit + force-push branch"] --> F{"PR already open?"}
  F --> G["Create PR"] --> H["GitHub PR"]
  C --> E
  F --> H
Loading
High-Level Assessment

The following are alternative approaches to this PR:

1. Use `peter-evans/create-pull-request` for PR management
  • ➕ Avoids relying on the gh CLI being available/configured
  • ➕ Provides a well-tested PR update/reuse flow and handles edge cases (labels, assignees, etc.)
  • ➕ Can reduce custom git/PR scripting surface area
  • ➖ Adds a third-party dependency and its opinionated behavior
  • ➖ May not match the ‘single persistent force-pushed branch’ pattern as directly
  • ➖ Less direct control over token-explicit push URL behavior
2. Implement as a JS/TS action (non-composite)
  • ➕ More robust input parsing/validation and better error handling
  • ➕ Easier to unit test logic (exclude parsing, PR existence checks, etc.)
  • ➕ Potentially more portable across runner environments/shells
  • ➖ Requires building and committing a dist bundle, increasing maintenance overhead
  • ➖ More moving parts (tooling, releases) for an action intended to stay simple
3. Create PR via GitHub REST API (curl) instead of `gh pr create`
  • ➕ Removes dependency on gh CLI behavior/availability
  • ➕ Keeps the action composite while making PR creation more explicit
  • ➖ More verbose and error-prone scripting (API pagination, status codes, JSON)
  • ➖ Still requires careful auth handling and PR existence checks

Recommendation: The composite approach is a good fit for an initial release: it stays transparent, avoids a build/dist workflow, and matches the intended ‘one persistent update branch’ model. If reviewers are concerned about gh availability or edge cases around PR detection, the most pragmatic alternative is swapping PR creation to a dedicated PR action (or REST API) while keeping the rest of the composite flow unchanged.

Files changed (2) +192 / -0

Enhancement (1) +127 / -0
action.ymlAdd composite action to update dependencies and open a PR +127/-0

Add composite action to update dependencies and open a PR

• Introduces the 'pnpm update' composite action with inputs for update behavior, optional Node/pnpm bumping, optional verify commands, and PR plumbing. Implements git commit/force-push to a persistent branch using an explicit x-access-token URL and creates/reuses a PR via 'gh'.

action.yml

Documentation (1) +65 / -0
README.mdDocument pnpm/update usage and inputs +65/-0

Document pnpm/update usage and inputs

• Adds initial README describing what the action does, a recommended scheduled workflow example, and a table of supported inputs with defaults and behavior notes (notably token/CI triggering semantics).

README.md

@qodo-code-review

qodo-code-review Bot commented Jul 21, 2026

Copy link
Copy Markdown

Code Review by Qodo

🐞 Bugs (0) 📘 Rule violations (0) 📎 Requirement gaps (0) 🎨 UX issues (0) 🔗 Cross-repo conflicts (0) 📜 Skill insights (0)

Grey Divider


Action required

1. Wrong update branch base ✓ Resolved 🐞 Bug ≡ Correctness
Description
The update branch is created from whatever ref the workflow currently has checked out (`git checkout
-B "$BRANCH"), while the base input is only used for gh pr create`. If the job isn’t already on
the intended base branch, the resulting PR can include unrelated commits/diffs and be based on an
unexpected merge base.
Code

action.yml[R96-126]

+        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 config user.name "github-actions[bot]"
+        git config user.email "github-actions[bot]@users.noreply.github.com"
+        git checkout -B "$BRANCH"
+        git add -A
+        git commit -m "$COMMIT_MESSAGE"
+        # Push with an explicit single-use URL so the provided token is used
+        # even when the checkout persisted different (or no) credentials.
+        git push --force "https://x-access-token:${GH_TOKEN}@github.com/${GITHUB_REPOSITORY}.git" "$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"
Evidence
BASE is defined as an input/env var and used when creating the PR, but the action never checks out
BASE; it resets the update branch from the currently checked-out commit, which can differ from
BASE depending on the caller’s checkout ref.

action.yml[18-20]
action.yml[58-87]
action.yml[96-126]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

### Issue description
The action accepts a `base` input but never checks out/fetches it before running `pnpm update` and creating the update branch. As a result, the update commit is based on the workflow’s current `HEAD`, not necessarily the intended base branch.

### Issue Context
- `BASE` is only passed to `gh pr create`.
- The update branch is reset/created via `git checkout -B "$BRANCH"` without referencing `BASE`.

### Fix Focus Areas
- action.yml[58-87]
- action.yml[93-126]

### Suggested fix approach
1. Ensure the repository state is based on `BASE` before updating dependencies (handle shallow checkouts):
  - `git fetch origin "$BASE" --depth=1` (or appropriate depth)
  - `git checkout "$BASE"` (or `git switch --detach "origin/$BASE"`)
2. Create/reset the update branch from the fetched base explicitly (either before running updates, or ensure you are on base first):
  - e.g. `git checkout -B "$BRANCH" "origin/$BASE"` (before `pnpm update`), then run updates on that branch.
3. Keep the PR creation using `--base "$BASE"` as-is.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools



Remediation recommended

2. Token in push URL ✓ Resolved 🐞 Bug ⛨ Security
Description
The action interpolates the auth token directly into the git push HTTPS URL, which puts
credentials into a command-line argument. Even with GitHub secret masking and no shell tracing, this
can still be exposed via git diagnostics on failure or through process/command inspection on the
runner.
Code

action.yml[R115-117]

+        # Push with an explicit single-use URL so the provided token is used
+        # even when the checkout persisted different (or no) credentials.
+        git push --force "https://x-access-token:${GH_TOKEN}@github.com/${GITHUB_REPOSITORY}.git" "$BRANCH"
Evidence
The push command explicitly constructs a URL containing ${GH_TOKEN} and supplies it to git push,
which is the direct source of the credential-in-CLI exposure risk.

action.yml[115-117]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

### Issue description
The push step embeds `${GH_TOKEN}` in the remote URL passed to `git push`. This places the token in a command-line argument, which is a known credential exposure risk (e.g., in some error messages or via process inspection).

### Issue Context
The current implementation:
- Uses `https://x-access-token:${GH_TOKEN}@github.com/...` directly in the `git push` command.

### Fix Focus Areas
- action.yml[110-118]

### Suggested fix approach
Switch to an approach that does not include the token in the URL argument, for example:
- Keep the remote URL token-free (`https://github.com/${GITHUB_REPOSITORY}.git`) and pass auth via a temporary header for the command:
 - `git -c http.https://github.com/.extraheader="AUTHORIZATION: basic $(printf 'x-access-token:%s' "$GH_TOKEN" | base64 -w0)" push --force https://github.com/${GITHUB_REPOSITORY}.git "$BRANCH"`
- Or configure a short-lived credential helper for the duration of the step and push to the normal remote.
Ensure the chosen method does not echo the token in logs and does not persist credentials beyond the job.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


Grey Divider

Qodo Logo

Comment thread action.yml
Comment thread action.yml Outdated
@zkochan

zkochan commented Jul 21, 2026

Copy link
Copy Markdown
Member Author

Both review findings are addressed in c47e161:

  1. Wrong update branch base — the action now starts with a "Prepare the update branch" step that runs git fetch origin "$BASE" and git checkout -B "$BRANCH" FETCH_HEAD before updating, so the update is always based on the latest base branch even when the workflow was dispatched from another ref or the checkout is shallow. This mirrors what pnpm/pnpm's update-lockfile.yml does. The base input description was updated accordingly.

  2. Token in push URL — the push no longer embeds the token in the remote URL. It now unsets any http.https://github.com/.extraheader persisted by actions/checkout (which would otherwise take precedence and silently downgrade a user-supplied PAT/App token to GITHUB_TOKEN), and supplies the token through a one-shot credential helper that reads GH_TOKEN from the environment, so the token never appears on a command line.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@action.yml`:
- Line 130: Update the credential cleanup command in the action configuration to
construct the `http` URL from `GITHUB_SERVER_URL`, falling back to
`https://github.com` when unset. Preserve the existing `git config --local
--unset-all` behavior and `|| true`, while ensuring the URL-specific key matches
the server used by `actions/checkout` on both GitHub.com and GHES.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 096f4b7a-1de3-4a1c-8816-5af0bbd63e29

📥 Commits

Reviewing files that changed from the base of the PR and between cb537a0 and c47e161.

📒 Files selected for processing (2)
  • README.md
  • action.yml
📜 Review details
🧰 Additional context used
🪛 LanguageTool
README.md

[uncategorized] ~55-~55: The official name of this software platform is spelled with a capital “H”.
Context: ...Description | |---|---|---| | token | github.token | Token used to push the branch ...

(GITHUB)

🔇 Additional comments (1)
README.md (1)

1-66: LGTM!

Comment thread action.yml Outdated
@zkochan
zkochan merged commit 76f98d7 into main Jul 23, 2026
2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant