Fix gomod tag resolution for monorepos with path-prefixed tags#15121
Open
alkalescent wants to merge 1 commit into
Open
Fix gomod tag resolution for monorepos with path-prefixed tags#15121alkalescent wants to merge 1 commit into
alkalescent wants to merge 1 commit into
Conversation
In Go monorepos where multiple modules share the same version number (e.g., otdfctl/v0.31.0 and protocol/go/v0.31.0), Dependabot's CommitsFinder and ReleaseFinder pick the wrong tag for compare links and release notes. The existing heuristic falls back to the shortest matching tag, which may belong to a different component. This commit fixes the issue by: 1. Setting source.directory in GoModules::MetadataFinder to the module's subdirectory path (e.g., "protocol/go" for github.com/owner/repo/protocol/go). 2. Adding a preferred_tag_by_directory fallback in CommitsFinder that matches tags by the source directory prefix before falling back to the first tag. 3. Adding a similar directory-based filter in ReleaseFinder's all_dep_releases to scope release notes to the correct module. This is the gomod equivalent of dependabot#11286, which fixed the same class of bug for the github_actions ecosystem. Fixes dependabot#15119 Signed-off-by: Krish Suchak <suchak.krish@gmail.com>
Contributor
There was a problem hiding this comment.
Pull request overview
Note
Copilot was unable to run its full agentic suite in this review.
This PR improves Go module metadata discovery for monorepos by recognizing subdirectory modules and using path-prefixed tags/releases when generating changelogs and compare URLs.
Changes:
- Set
source.directoryfor Go module dependencies that live in a repository subdirectory. - Prefer tags/releases that match the Go module subdirectory prefix (e.g.,
protocol/go/vX.Y.Z) when dependency-name-prefixed tags aren’t available. - Add fixtures and specs covering path-prefixed releases/tags for a Go monorepo.
Reviewed changes
Copilot reviewed 7 out of 7 changed files in this pull request and generated 5 comments.
Show a summary per file
| File | Description |
|---|---|
| go_modules/lib/dependabot/go_modules/metadata_finder.rb | Derives and sets source.directory for subdirectory Go modules in monorepos. |
| go_modules/spec/dependabot/go_modules/metadata_finder_spec.rb | Adds specs validating source.directory behavior for subdirectory vs root modules. |
| common/lib/dependabot/metadata_finders/base/release_finder.rb | Filters GitHub releases by module directory prefix when dependency-name prefix isn’t present. |
| common/lib/dependabot/metadata_finders/base/commits_finder.rb | Prefers directory-prefixed tags when selecting compare endpoints for monorepo modules. |
| common/spec/dependabot/metadata_finders/base/release_finder_spec.rb | Adds spec ensuring only the correct module’s releases are included. |
| common/spec/dependabot/metadata_finders/base/commits_finder_spec.rb | Adds spec ensuring compare URLs use the correct directory-prefixed tags. |
| common/spec/fixtures/github/go_monorepo_releases.json | Adds fixture data for a monorepo with directory-prefixed release tags. |
Comment on lines
+25
to
+28
| repo_import_path = url.gsub(%r{^https?://}, "").chomp("/").chomp(".git") | ||
| if dependency.name.start_with?("#{repo_import_path}/") | ||
| source.directory = dependency.name.delete_prefix("#{repo_import_path}/") | ||
| end |
Comment on lines
+113
to
+120
| if source&.directory && ![".", "/"].include?(source.directory) | ||
| releases_with_dir_prefix = | ||
| releases | ||
| .reject { |r| r.tag_name.nil? } | ||
| .select { |r| r.tag_name.start_with?("#{T.must(source).directory}/") } | ||
|
|
||
| return releases_with_dir_prefix if releases_with_dir_prefix.any? | ||
| end |
Comment on lines
+88
to
+90
| tags.find { |t| t.include?(dependency.name) } || | ||
| preferred_tag_by_directory(tags) || | ||
| tags.first |
Comment on lines
+110
to
+112
| tags.find { |t| t.include?(dependency.name) } || | ||
| preferred_tag_by_directory(tags) || | ||
| tags.first |
Comment on lines
+127
to
+129
| tags.find { |t| t.include?(dependency.name) } || | ||
| preferred_tag_by_directory(tags) || | ||
| tags.first |
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
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
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.
What are you trying to accomplish?
In Go monorepos with multiple independently versioned modules (like opentdf/platform), Dependabot generates wrong compare links and includes release notes from the wrong component in PR descriptions.
The root cause: when two modules share the same version number (e.g.,
otdfctl/v0.31.0andprotocol/go/v0.31.0),CommitsFinderandReleaseFindercan't disambiguate the tags and fall back to the shortest or first match. This produces compare links likeprotocol/go/v0.30.0...otdfctl/v0.31.0instead of the correctprotocol/go/v0.30.0...protocol/go/v0.31.0.This is the gomod equivalent of #11286 which fixed the same bug for the
github_actionsecosystem.Fixes #15119
Anything you want to highlight for special attention from reviewers?
The fix is split across three layers, all additive:
GoModules MetadataFinder now derives the module's subdirectory path from the dependency name and sets
source.directory. Forgithub.com/opentdf/platform/protocol/go, this is"protocol/go". Root-level modules get no directory set, so existing behavior is preserved.CommitsFinder gets a new
preferred_tag_by_directoryhelper that tries to match tags starting with thesource.directoryprefix. This sits between the existinginclude?(dependency.name)check and thetags.firstfallback, so it only activates when the directory is set.ReleaseFinder gets a similar fallback in
all_dep_releasesthat filters releases by the directory prefix before falling through to returning all releases.I considered putting all the logic in the gomod-specific MetadataFinder, but the tag selection happens in the common layer's
CommitsFinderandReleaseFinder. Overriding those at the ecosystem level would have required subclassing or monkey-patching, which felt heavier than adding a clean fallback path. The common layer changes only activate whensource.directoryis set, so other ecosystems are unaffected.Note that
go_modulesis intentionally NOT added toPACKAGE_MANAGERS_WITH_RELIABLE_DIRECTORIES. This meanspart_of_monorepo?stays false and the compare URL format remainscompare/tag1...tag2(not the directory-scoped commits view).How will you know you've accomplished your goal?
The PR that originally surfaced this issue (opentdf/platform#3496) shows
otdfctl: v0.31.0release notes in a PR aboutprotocol/go. With this fix, the tag resolution would correctly pickprotocol/go/v0.31.0and only show the relevant release notes.I've added tests for all three changes:
source.directoryis set for subdirectory modules and nil for root modulesChecklist