Skip to content

feat(workflow): generate diff-accurate upgrade-deps PR descriptions via Claude#1402

Merged
fengmk2 merged 9 commits intomainfrom
improve-auto-update
Apr 17, 2026
Merged

feat(workflow): generate diff-accurate upgrade-deps PR descriptions via Claude#1402
fengmk2 merged 9 commits intomainfrom
improve-auto-update

Conversation

@fengmk2
Copy link
Copy Markdown
Member

@fengmk2 fengmk2 commented Apr 17, 2026

Previously the Upgrade Upstream Dependencies workflow shipped a generic
template commit message and PR body (see #1401) that didn't reflect what
actually changed. This PR rewires the workflow so the commit and PR
description are generated from the real diff on every run.

What's new

Diff-accurate descriptions

  • .github/scripts/upgrade-deps.mjs records old → new for every dep it
    touches (including rolldown/vite tag + short SHA) and writes
    versions.json, commit-message.txt, and pr-body.md to
    $UPGRADE_DEPS_META_DIR (in $RUNNER_TEMP, so they aren't committed).
  • .github/workflows/upgrade-deps.yml:
    • New Set up metadata directory step exports UPGRADE_DEPS_META_DIR
      via $GITHUB_ENV.
    • New Enhance PR description with Claude step reads the baseline
      files plus git diff and overwrites them with a Summary, a
      dependency table, a Code-changes list, and a Build-status block.
    • New Read generated PR content step exposes the files as multi-line
      step outputs (with a trailing-newline guard so the heredoc
      terminator always lands on its own line).
    • peter-evans/create-pull-request now consumes those outputs instead
      of a static template body.
  • If the enhancement step fails, continue-on-error: true keeps the
    workflow going and the baseline content from the Node script ships
    instead of a generic message.

Tightened Check upgrade dependencies prompt

  • Single authoritative checklist: Background → Fixups (in order) →
    Final validation → Commit rule. The previous prompt had three
    overlapping sections describing the same checks.
  • Final validation requires BOTH just build AND
    pnpm bootstrap-cli:ci && pnpm test to pass, plus a manual snap-test
    diff inspection (because pnpm test always exits 0 even on snapshot
    drift, so the agent has to look at the diff itself).
  • New Running long commands rule forbids backgrounding (&, nohup,
    disown, …) and polling (ps, pgrep, sleep loops, repeated ls
    on build artifacts). Run 24545325671 spent 30+ minutes spinning in a
    ps aux | grep "just build" loop before this rule landed.

Safety bounds on the Claude session

  • --max-turns 200 caps total tool calls so a runaway agent can't
    consume an entire job budget.
  • timeout-minutes: 180 on the step is a belt-and-suspenders cap on
    wall-clock time.
  • Both anthropics/claude-code-action pins bumped to v1.0.99
    (Claude Code 2.1.112).

Script hygiene

  • getLatestTag uses ?per_page=1 and the rolldown + vite fetches run
    in parallel via Promise.all.
  • updatePnpmWorkspace is now a single-pass String.replace callback
    with one capture group per pattern (avoids the foot-gun where the
    replace callback's positional suffix arg silently received the match
    offset and corrupted versions). Throws explicitly if a pattern goes
    stale instead of silently recording a no-op change.
  • updateCorePackage early-exits when @vitejs/devtools isn't present,
    skipping the no-op JSON rewrite.

@netlify
Copy link
Copy Markdown

netlify bot commented Apr 17, 2026

Deploy Preview for viteplus-preview canceled.

Name Link
🔨 Latest commit f173b91
🔍 Latest deploy log https://app.netlify.com/projects/viteplus-preview/deploys/69e1d3a291427b000826ef35

@fengmk2 fengmk2 self-assigned this Apr 17, 2026
Copy link
Copy Markdown
Member Author

fengmk2 commented Apr 17, 2026


How to use the Graphite Merge Queue

Add the label auto-merge to this PR to add it to the merge queue.

You must have a Graphite account in order to use the merge queue. Sign up using this link.

An organization admin has enabled the Graphite Merge Queue in this repository.

Please do not merge from GitHub as this will restart CI on PRs being processed by the merge queue.

This stack of pull requests is managed by Graphite. Learn more about stacking.

Copy link
Copy Markdown
Member Author

fengmk2 commented Apr 17, 2026

@cursor review

Comment thread .github/workflows/upgrade-deps.yml
Comment thread .github/scripts/upgrade-deps.mjs
Copy link
Copy Markdown
Member Author

fengmk2 commented Apr 17, 2026

@cursor review

Comment thread .github/scripts/upgrade-deps.mjs
@fengmk2 fengmk2 marked this pull request as ready for review April 17, 2026 05:52
Copy link
Copy Markdown
Member Author

fengmk2 commented Apr 17, 2026

ci works #1405

fengmk2 added 8 commits April 17, 2026 14:24
…aude

Previously the `Upgrade Upstream Dependencies` workflow produced a generic
template commit message and PR body (see #1401) that didn't reflect what
actually changed. This wires up a second claude-code-action pass whose only
job is to write a diff-accurate commit message and PR body.

- `.github/scripts/upgrade-deps.mjs` now captures old -> new for every
  dependency it touches (including rolldown/vite tag + short SHA) and
  writes `versions.json`, `commit-message.txt`, and `pr-body.md` to
  `$UPGRADE_DEPS_META_DIR` (outside the repo, so not committed).
- `.github/workflows/upgrade-deps.yml`:
  - Exports `UPGRADE_DEPS_META_DIR` via `$GITHUB_ENV` in a setup step.
  - Adds an "Enhance PR description with Claude" step that reads the
    baseline files + `git diff` and overwrites them with a concrete
    summary, a dependency table, and a real code-changes section.
  - Adds a "Read generated PR content" step that exposes the files as
    multi-line step outputs.
  - `peter-evans/create-pull-request` now consumes those outputs instead
    of a static template body.
  - Tightens the `check-upgrade-dependencies` final check to require
    BOTH `just build` AND `pnpm bootstrap-cli:ci && pnpm test` to pass
    (with manual snap-test diff inspection).
  - Bumps both `claude-code-action` pins to v1.0.99 (Claude Code 2.1.112).

If the enhancement step fails, `continue-on-error` keeps the workflow
going and the baseline content produced by the Node script is shipped
instead of a generic message.
The closing prompt instruction only pointed at `build-upstream` failures,
but the step also runs lint, `just build`, `pnpm test`, and snap tests.
Enumerate every error class Claude is expected to fix, and call out
snap-test regressions explicitly since `pnpm test` exits 0 even when
snapshot outputs diverge — the agent must inspect the snap-test git diff
and fix real regressions while leaving cosmetic version-string drift in
place.
Bare-return and single-line `if` statements tripped the `curly` rule, and
`isFullSha` was declared inside `writeMetaFiles` even though it didn't
capture any parent-scope bindings. Hoist the helper to module scope and
add braces to every single-statement `if`.
- Guarantee a trailing newline on commit-message.txt and pr-body.md
  before piping them through the heredoc into `$GITHUB_OUTPUT`. If
  Claude overwrites either file without a final `\n`, `cat` leaves the
  last line adjacent to the closing delimiter and GitHub Actions never
  terminates the multi-line value — producing a garbled body/commit.
- Fail fast in `updatePnpmWorkspace` when a version regex no longer
  matches the YAML. Previously we silently recorded `(unset) -> new`
  even though `.replace` was a no-op, which would ship a misleading
  dependency table. A stale pattern now surfaces as an explicit error
  so the script can be updated.
- Consolidate the `check-upgrade-dependencies` Claude prompt: the three
  overlapping sections (old Instructions, Final check, "Help me fix")
  all described the same test/build/snap-test checks and sometimes
  contradicted each other. Replace with a single structured prompt
  (Background → Fixups → Final validation → Commit rule) where each
  requirement appears exactly once.
- `updatePnpmWorkspace` now uses a single-pass `String.replace` with a
  callback, so the current version is captured during the substitution
  instead of via a separate `match` call. Drops the redundant
  `replacement` field from each entry and removes the "matched once but
  replace didn't match" edge case.
- `getLatestTag` fetches only the newest tag (`?per_page=1`) instead of
  the default 30.
- `updateCorePackage` now early-returns when `@vitejs/devtools` is
  absent, skipping the no-op JSON rewrite.
…e-deps

Run 24545325671 showed the `Check upgrade dependencies` step stuck for
40+ minutes in a busy-wait loop: Claude had backgrounded `just build`
and was polling `ps aux | grep "just build"` / `pgrep` / `sleep` every
few seconds to check if it was done. Each poll was a full model
round-trip, so the session never ended even though no real work was
happening.

- Add a 200-turn cap via `--max-turns 200` so a runaway agent session
  can no longer burn an unbounded amount of Actions time.
- Add an explicit "Running long commands" rule to the prompt that
  forbids backgrounding (`&`, `nohup`, `disown`, etc.) and forbids
  polling with `ps`/`pgrep`/`sleep` loops. The Bash tool's 20-minute
  per-call timeout is plenty for `just build` and `pnpm test`, and
  foreground calls give Claude the exit code and output in one shot.
…s prompt

The Bash tool's maximum per-call timeout is 10 minutes (600000 ms), not
20 minutes as the previous wording stated.
…back

Cursor Bugbot caught a high-severity bug introduced by the previous
single-pass refactor. The replace callback used:

    (_match, prefix, oldVersion, suffix = '') => `${prefix}${newVersion}${suffix}`

`String.prototype.replace` always passes the match offset (a number) as
the next positional argument after the captures, so for the 6 patterns
with only two captures (vitest, tsdown, @oxc-node/cli, @oxc-node/core,
oxfmt, oxlint-tsgolint), `suffix` received the offset instead of
`undefined`. The `= ''` default never kicked in, and the offset got
appended to every version. Example: `tsdown: ^0.21.8` was rewritten to
`tsdown: ^9.9.90`. The earlier smoke test missed this because it used
substring `includes()`, which still matched.

Restructure each entry to use ONE capture group (just the version) plus
a literal `replacement` string. The callback signature is now
`(_match, captured)` and ignores the trailing offset/string args, so
the positional ambiguity is gone. Verified with a byte-exact equality
test on a synthetic fixture covering non-zero offsets.
@fengmk2 fengmk2 force-pushed the improve-auto-update branch from 6f90169 to f8045cf Compare April 17, 2026 06:27
- Drop the redundant `[ -s ]` check in `ensure_trailing_newline`. If
  the file is empty, `tail -c1` returns nothing and `[ -n "" ]` is
  already false, so the size check adds nothing.
- Trim the upgrade-deps regex-table comment to the only WHY worth
  preserving (oxlint's trailing `\n` disambiguates from
  oxlint-tsgolint). The callback-signature explanation just narrated
  the code and added noise.
- Add `timeout-minutes: 180` to the `Check upgrade dependencies` step
  as a belt-and-suspenders guard. With `--max-turns 200` and the
  no-polling rule now in place, normal runs finish well under this
  cap; a runaway will be killed by Actions instead of consuming the
  full 6-hour job budget.
@fengmk2
Copy link
Copy Markdown
Member Author

fengmk2 commented Apr 17, 2026

@cursor review

@fengmk2 fengmk2 changed the title feat(workflow): generate accurate upgrade-deps PR descriptions via Claude feat(workflow): generate diff-accurate upgrade-deps PR descriptions via Claude Apr 17, 2026
Copy link
Copy Markdown

@cursor cursor bot left a comment

Choose a reason for hiding this comment

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

✅ Bugbot reviewed your changes and found no new issues!

Comment @cursor review or bugbot run to trigger another review on this PR

Reviewed by Cursor Bugbot for commit f173b91. Configure here.

@fengmk2 fengmk2 merged commit 4dee64d into main Apr 17, 2026
41 checks passed
@fengmk2 fengmk2 deleted the improve-auto-update branch April 17, 2026 07:50
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.

2 participants