Skip to content

Raise individual pull requests for group members that update-types rejects - #16113

Merged
v-thavaahariharangit merged 3 commits into
dependabot:mainfrom
FReptar0:fix/individual-prs-for-semver-excluded-group-deps
Oct 9, 2026
Merged

v-thavaahariharangit merged 3 commits into
dependabot:mainfrom
FReptar0:fix/individual-prs-for-semver-excluded-group-deps

Conversation

@FReptar0

Copy link
Copy Markdown
Contributor

What are you trying to accomplish?

Fixes #14202.

A group that restricts update-types is documented to leave the updates it rejects to individual pull requests:

  • Dependabot will create a grouped pull request for all Angular dependencies that have a minor or patch update.
  • All major updates will continue to be raised as individual pull requests.

That is what happens on the first run of a job. It stops happening as soon as the group has an open pull request — which is the steady state for a patterns: ["*"] minor/patch group — so in practice the rejected updates are never raised at all. The same happens whenever the group itself produces no change, e.g. when every remaining update in it is a major one.

GroupUpdateAllVersions defers a group that already has an open pull request to its own refresh job and calls DependencySnapshot#mark_group_handled, which marks every dependency matching the group's patterns as handled. DependencyGroup#contains? cannot take update-types into account — the semver level of an update is only known once an update checker has resolved the latest version — so dependencies the group is going to reject are marked handled as well. They drop out of ungrouped_dependencies and get no pull request from either path.

compile_updates_for is careful not to mark those dependencies as handled (group_update_creation.rb#L306, and the spec asserting it at group_update_creation_spec.rb#L658), so the intent is already in the code; the blanket marking one level up overrides it.

This is the same bug #14475 fixed for NuGet ("if a group matches but the update type isn't allowed in that group, then proceed as an ungrouped update"). This change brings the Ruby updater to parity for every other ecosystem.

The change. When GroupUpdateAllVersions skips a group that sets update-types, its members are deferred rather than marked handled: DependencySnapshot records which groups are still waiting on them and they stay in ungrouped_dependencies. UpdateAllVersions — which resolves the latest version for those dependencies anyway — then applies the group's update-types rules: if the group accepts the update, the group's own job will raise it and no individual pull request is opened; if the group rejects it, the dependency is updated individually, exactly as it is on a first run today.

The semver rules themselves are unchanged. They moved out of GroupUpdateCreation into Dependabot::Updater::SemverGroupingRules so both the grouped and the individual paths apply the same logic; semver_rules_allow_grouping? keeps its signature and delegates.

Anything you want to highlight for special attention from reviewers?

  • Feature flag. Everything is behind individual_prs_for_semver_excluded_dependencies and off by default, since this changes how many pull requests affected repositories receive. Happy to drop the gate if you would rather ship it directly.
  • Scope. Only the two mark_group_handled call sites in GroupUpdateAllVersions opt in via the new defer_update_types: keyword — those are the ones that decide whether a dependency gets a pull request at all. The refresh operation's call site is untouched, since a refresh job never runs the individual update path.
  • Cost. Deferred dependencies now get an update check in the individual run where previously they were skipped. This is the same work CreateGroupUpdatePullRequest already does for them when the group has no open pull request, and it only applies to groups that set update-types.
  • Overlap. #15289 touches semver_rules_allow_grouping?; if that lands first I am happy to rebase the extraction on top of it.

How will you know you've accomplished your goal?

silent/tests/testdata/vu-group-semver-existing-pr.txt is a regression test for exactly the reported scenario: a minor/patch group with an open pull request, and a dependency whose only available update is a major one. On main it produces no pull request at all; with this change it produces the individual major pull request.

Also covered by unit specs for the deferral (dependency_snapshot_spec.rb) and for both outcomes of the re-check in the individual run (update_all_versions_spec.rb). The existing vu-group-semver* integration tests and the grouping specs are unchanged and still pass.

Checklist

  • I have run the complete test suite to ensure all tests and linters pass.
  • I have thoroughly tested my code changes to ensure they work as expected, including adding additional tests for new functionality.
  • I have written clear and descriptive commit messages.
  • I have provided a detailed description of the changes in the pull request, including the problem it addresses, how it fixes the problem, and any relevant details about the implementation.
  • I have ensured that the code is well-documented and easy to understand.

@FReptar0
FReptar0 requested a review from a team as a code owner August 31, 2026 16:07
Copilot AI balanced review requested due to automatic review settings August 31, 2026 16:07

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

…jects

A group that sets `update-types` cannot tell whether it claims a dependency
until an update checker has resolved the latest version, so
`DependencyGroup#contains?` matches on patterns alone. When
`GroupUpdateAllVersions` skips such a group -- because it already has an open
pull request, or because it produced no change -- it marks every pattern match
as handled, which also swallows the dependencies the group is going to reject.
Those drop out of `ungrouped_dependencies` and are never raised individually,
so a repository whose minor/patch group has an open pull request silently stops
receiving the major updates that the group excludes.

Defer those dependencies instead of marking them handled. The snapshot records
which groups are still waiting on them, they stay in `ungrouped_dependencies`,
and the individual update run -- which resolves the latest version anyway --
applies the group's update-types rules to decide between leaving the update to
the group and raising a pull request of its own.

The semver rules move to `Dependabot::Updater::SemverGroupingRules` so both the
grouped and the individual paths share them. The new behaviour is gated behind
the `individual_prs_for_semver_excluded_dependencies` experiment.
@FReptar0
FReptar0 force-pushed the fix/individual-prs-for-semver-excluded-group-deps branch from 4d2473e to 42906ec Compare August 31, 2026 16:09
@FReptar0

Copy link
Copy Markdown
Contributor Author

Heads up on the one red check: e2e (python, pip, smoke-python-pip-compile.yaml) is a pre-existing failure, not something this branch introduces.

The same job fails identically on unrelated branches right now, including bump-to-v0.394.0 — the automated version-bump PR that only touches common/lib/dependabot.rb and the lockfiles — as well as generate-hashes-null and migrate-to-turbo-tests2.

The diff is upstream drift in transitive dependencies of django[argon2]:

-argon2-cffi-bindings==25.1.0
+argon2-cffi-bindings==26.1.0
-cffi==2.0.0
+cffi==2.1.1

That smoke test also has no dependency-groups and sets no experiments, so nothing in this change is reachable from it: mark_group_handled is only called from run_grouped_dependency_updates, which is guarded by if dependency_snapshot.groups.any?, and the new behaviour additionally requires the individual_prs_for_semver_excluded_dependencies experiment to be enabled.

Every other check is green, including Updater, Lint, Sorbet (plus the typing-mode and T.untyped ratchet jobs), integration, arm64-build and CodeQL.

Copilot AI review requested due to automatic review settings September 1, 2026 21:35

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🟡 Changes recommended

SHA-pinned dependencies can incorrectly receive individual PRs despite matching a deferred group’s accepted update types.

1 open finding

🧠 Review effort: Balanced

Comment on lines +52 to +53
unless version_class.correct?(dependency.version.to_s) && version_class.correct?(checker.latest_version)
return false
Copilot AI balanced review requested due to automatic review settings October 8, 2026 21:26

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

@v-thavaahariharangit v-thavaahariharangit left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

LGTM

@v-thavaahariharangit
v-thavaahariharangit merged commit c96ebb6 into dependabot:main Oct 9, 2026
159 of 160 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

Dependencies matched by group patterns are marked as "handled" regardless of update-types, suppressing major version PRs

5 participants