Skip to content

feat: bumpy ci deps — auto bump files for dependency update PRs - #161

Merged
theoephraim merged 3 commits into
mainfrom
claude/ci-deps-bump-files
Oct 15, 2026
Merged

theoephraim merged 3 commits into
mainfrom
claude/ci-deps-bump-files

Conversation

@theoephraim

@theoephraim theoephraim commented Oct 5, 2026 •

Copy link
Copy Markdown
Member

Adds bumpy ci deps, which writes bump files for Dependabot / Renovate PRs. It works like changesets-dependencies-action.

Why: a user hit this. Dev-only updates already pass bumpy check (ignoredPackageJsonFields, added in 1.15). Updates to runtime dependencies / peerDependencies correctly need a release, but no one is there to write the bump file on a bot PR.

What it does

bumpy ci deps, run on a PR:

  1. Compares each managed package's release-relevant dependency fields against the merge base. It uses the same rules as bumpy check: dependencies / peerDependencies / optionalDependencies, plus devDependencies listed in releaseTriggeringDevDeps, minus ignoredPackageJsonFields. catalog: refs are resolved on both sides, so a catalog-only update counts for every package that uses the entry.
  2. Writes one patch bump file per affected package at .bumpy/deps-pr<N>-<pkg>.md. Each line reads like the changesets action's, e.g. Updated dependency [`lodash@^4.17.21` ↗︎](npm link) (from `^4.0.0`, in `dependencies`).
  3. Commits the files and pushes them to the PR branch. It switches off the detached merge commit that actions/checkout leaves, and pushes with BUMPY_GH_TOKEN when it's set so CI runs again. It also sets a changed step output.

bumpy generate --deps does the same locally, names the files after the branch, and doesn't commit. --dry-run works with it.

Edge cases

  • Re-runs: files are rewritten in place, and files whose package no longer has changes are deleted. A file is deleted only if it has the frontmatter marker comment, matches the prefix, and was added on this branch. Hand-written or already-merged files are never touched.
  • directBump: false: the bump goes on the first bumpable member of the package's fixed group. If there isn't one, the other files are still pushed and the command exits 1 with a message saying what to fix.
  • ID collisions: if two managed package names slugify to the same thing (@org/a and org-a), a short hash of the full name is added to the ID.
  • Fork PRs: skipped with a warning, since their branch can't be pushed to.
  • PRs into a channel branch: compared against the PR's base (GITHUB_BASE_REF), so dependency changes already merged into the channel aren't credited to this PR.

Also fixes ci check on channel PRs

findChangedPackages compared package.json fields and catalogs against baseBranch even when the changed files came from the PR's base. It now takes a compareBranch, and ci check / bumpy check --base pass it in.

Docs

  • docs/github-actions.md: new "Dependency update PRs" section with an example workflow, which only runs on PRs opened by the bots (it checks the PR author, not github.actor). It covers the Dependabot-secrets requirement for BUMPY_GH_TOKEN, the fact that Dependabot stops auto-rebasing once someone else pushes to its branch (@dependabot recreate), and running ci deps before ci check in the same job.
  • docs/cli.md: bumpy ci deps and generate --deps.
  • docs/configuration.md: a pointer from the change-detection section.

Tests

test/core/dep-bump-files.test.ts covers formatting, ID collisions, and git-backed detection: runtime, peer and workspace: changes; dev-only changes ignored; releaseTriggeringDevDeps; catalogs; deleting stale files while keeping marked-but-merged and hand-written ones; directBump: false with and without a fixed-group member; and a channel-PR case where only changes against the PR's own base count. I also ran ci deps end to end against a local bare remote, starting from a detached checkout: it pushed the commit, a second run made no changes, and bumpy check passed.

@github-actions

github-actions Bot commented Oct 5, 2026 •

Copy link
Copy Markdown

bumpy-frog

The changes in this PR will be included in the next version bump.

minor Minor releases

  • @varlock/bumpy 1.18.1 → 1.19.0

Bump files in this PR

Click here if you want to add another bump file to this PR


This comment is maintained by bumpy.

@pullfrog pullfrog 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.

Important

The generated-file ownership and dependency classification gaps can silently lose bump coverage or delete a legitimate bump file. These should be addressed before merging.

Reviewed changes in d74bb5b cover the new dependency-update bump-file workflow end to end:

  • Dependency detection: Compares release-relevant dependency fields and catalogs against the merge base.
  • Generated bump files: Writes deterministic per-package patch files and removes stale output.
  • CI automation: Adds bumpy ci deps with commit, push, fork, token, and GitHub output handling.
  • Local generation: Adds bumpy generate --deps, including dry-run and naming options.
  • Documentation and tests: Documents Dependabot/Renovate setup and tests dependency, catalog, and stale-file behavior.

Pullfrog  | Fix all ➔ | Fix 👍s ➔ | View workflow run | Using gpt-5.6-sol | 𝕏

Comment thread packages/bumpy/src/core/dep-bump-files.ts Outdated
Comment thread packages/bumpy/src/core/dep-bump-files.ts Outdated
Comment thread packages/bumpy/src/core/dep-bump-files.ts Outdated
Comment thread packages/bumpy/src/core/dep-bump-files.ts Outdated

@pullfrog pullfrog 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.

✅ No new issues found.

Reviewed changes since the prior Pullfrog review at d74bb5b:

  • Aligned dependency detection: Preserved release-relevant workspace: range transitions so generated coverage matches bumpy check.
  • Covered non-direct bumps: Routed directBump: false dependency changes to a bumpable fixed-group member and added an actionable failure when no driver exists.
  • Hardened generated files: Added collision-safe stable IDs and a frontmatter ownership marker required before stale-file deletion.
  • Expanded regression coverage: Added focused tests for workspace ranges, fixed-group routing, ID collisions, and preservation of hand-written bump files.

Pullfrog  | View workflow run | Using gpt-5.6-sol | 𝕏

Comment thread packages/bumpy/src/commands/ci.ts Outdated
}

const { packages } = await discoverWorkspace(rootDir, config);
const baseRef = getBaseCompareRef(rootDir, config.baseBranch);

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Wrong base for PRs that target a channel branch.

baseRef comes from config.baseBranch, not from the branch the PR targets. ciCheckCommand above already handles this case: it uses process.env.GITHUB_BASE_REF || config.baseBranch so that "the whole cycle's changes" don't show up. ci deps doesn't, so on a PR into a channel branch it writes bump files for every runtime dependency change made on that channel since it split from baseBranch, not just this PR's.

Example: baseBranch: "main", with a dev channel on branch dev.

  1. Dependabot PR A updates react in @acme/web's dependencies and merges into dev. dev now differs from main there.
  2. Dependabot PR B, also into dev, only updates vitest in devDependencies, so it changes nothing release-relevant.
  3. ci deps on PR B diffs against merge-base(HEAD, origin/main). @acme/web's react range differs from that base, so it writes and pushes deps-prB-acme-web.md ("Updated dependency react@… (from <main's range>, in dependencies)").

Result: an extra patch for a PR that changes no runtime dependency, and a repeat of PR A's changelog line. Every later dependency PR in the cycle collects the same drift.

findChangedPackages in check.ts has the same problem in its package.json field diff (baseRef ??= getBaseCompareRef(rootDir, config.baseBranch)). So ci check asks for these same files, and the two agree on the wrong answer, which hides it. (There, too, the changedFiles passed in come from the PR base, but the field comparison uses baseBranch.)

Suggested fix: resolve the compare branch once, as ciCheckCommand does (process.env.GITHUB_BASE_REF || config.baseBranch), and use it both here and in findChangedPackages (it could take the compare branch as a parameter, along with getChangedCatalogEntries). A test with a channel config would cover it: merge a runtime dependency change into the channel branch, then run ci deps on a dev-only PR into that channel and expect no files.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Good catch, fixed in 9c73041. ci deps now diffs against GITHUB_BASE_REF || baseBranch. findChangedPackages takes a compareBranch param, used for both the package.json field diff and the catalog diff. ci check (both call sites) and bumpy check --base pass it through, so the drift no longer shows up there either. I added your scenario as a test: a runtime update merged into dev, then a dev-only PR into dev. With the fix it expects no files; without it, it fails.

Comment thread docs/github-actions.md Outdated

jobs:
deps:
if: github.actor == 'dependabot[bot]' || github.actor == 'renovate[bot]'

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

github.actor skips pushes made by anyone other than the bot.

github.actor is whoever triggered the run, not who opened the PR. When a maintainer pushes a commit to a Dependabot or Renovate PR, this job doesn't run. The generated files then aren't rewritten and stale ones aren't removed, though the section above says that happens on every run.

Example: Dependabot bumps foo to ^2.1.0 in dependencies, and ci deps writes "Updated dependency foo@^2.1.0". The build breaks, so a maintainer pushes a commit pinning foo to ^2.0.5, or reverting the update. The job is skipped for that push, so the bump file still claims the ^2.1.0 update (or should now be deleted), and it merges with a wrong changelog line.

Suggested fix: gate on the PR author, so every push to a bot's PR is covered:

if: github.event.pull_request.user.login == 'dependabot[bot]' || github.event.pull_request.user.login == 'renovate[bot]'

The run triggered by the BUMPY_GH_TOKEN push also matches. It finds the files up to date and commits nothing, so this doesn't loop. The "skip bumpy's regular PR check for those actors" advice below should probably key on the PR author too.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Agreed, fixed in 9c73041. The example now gates on github.event.pull_request.user.login, and the docs note that the re-run after the token push finds nothing to commit, so it doesn't loop. The "skip the regular check" advice now says to use the same condition, negated.

@pullfrog pullfrog 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.

✅ No new issues found.

Reviewed changes since the prior Pullfrog review at 3400fcd covered the channel-target comparison fix and workflow gating update:

  • Corrected dependency comparison: Diffed ci deps against GITHUB_BASE_REF so channel history is not attributed to later dependency PRs.
  • Aligned package classification: Passed the same comparison branch through ci check, local check --base, package metadata checks, and catalog checks.
  • Updated workflow gating: Gated the documented action on the PR author so maintainer pushes to bot-authored PRs still regenerate bump files.
  • Added regression coverage: Exercised a dev-only PR after runtime dependency drift had already landed on its target channel branch.

Pullfrog  | View workflow run | Using gpt-5.6-sol | 𝕏

@theoephraim
theoephraim merged commit 510cbfd into main Oct 15, 2026
5 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.

2 participants