Skip to content

Commit 16c5d34

Browse files
authored
Merge pull request #13899 from dependabot/nishnha/fix-pr-directory-comparison
Nishnha/fix pr directory comparison
2 parents 6bb397e + 520696e commit 16c5d34

File tree

5 files changed

+373
-4
lines changed

5 files changed

+373
-4
lines changed

updater/lib/dependabot/updater/group_update_creation.rb

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -534,7 +534,34 @@ def cleanup_workspace
534534

535535
sig { params(group: Dependabot::DependencyGroup).returns(T::Boolean) }
536536
def pr_exists_for_dependency_group?(group)
537-
job.existing_group_pull_requests.any? { |pr| pr["dependency-group-name"] == group.name }
537+
!find_existing_group_pr(group).nil?
538+
end
539+
540+
sig { params(group: Dependabot::DependencyGroup).returns(T.nilable(T::Hash[String, T.untyped])) }
541+
def find_existing_group_pr(group)
542+
job.existing_group_pull_requests.find do |pr|
543+
next false unless pr["dependency-group-name"] == group.name
544+
545+
existing_pr_covers_job_directories?(pr)
546+
end
547+
end
548+
549+
sig { params(pull_request: T::Hash[String, T.untyped]).returns(T::Boolean) }
550+
def existing_pr_covers_job_directories?(pull_request)
551+
dependencies = pull_request["dependencies"]
552+
553+
# Old PRs without directory info — treat as match (backward compat).
554+
# Only enforce directory matching when ALL dependencies include a directory,
555+
# consistent with DependencyChange#matches_existing_pr? and PullRequest#using_directory?.
556+
return true if dependencies.nil? || !dependencies.all? { |dep| dep["directory"] }
557+
558+
pr_directories = dependencies.filter_map { |dep| dep["directory"] }
559+
job_directories = job.source.directories || [job.source.directory || "/"]
560+
normalized_job_dirs = job_directories.map { |d| Pathname.new(d).cleanpath.to_s }.uniq
561+
normalized_pr_dirs = pr_directories.map { |d| Pathname.new(d).cleanpath.to_s }.uniq
562+
563+
# Match only when the PR directories exactly match the job directories
564+
normalized_job_dirs.sort == normalized_pr_dirs.sort
538565
end
539566

540567
sig do

updater/lib/dependabot/updater/operations/group_update_all_versions.rb

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -85,9 +85,9 @@ def run_grouped_dependency_updates
8585
# Preprocess to discover existing group PRs and add their dependencies to the handled list before processing
8686
# the rest of the groups. This prevents multiple PRs from being created for the same dependency.
8787
groups_without_pr = dependency_snapshot.groups.filter_map do |group|
88-
if pr_exists_for_dependency_group?(group)
89-
existing_pr = job.existing_group_pull_requests.find { |pr| pr["dependency-group-name"] == group.name }
90-
pr_number = existing_pr["pr_number"] if existing_pr
88+
existing_pr = find_existing_group_pr(group)
89+
if existing_pr
90+
pr_number = existing_pr["pr_number"]
9191

9292
Dependabot.logger.info(
9393
"Detected existing pull request ##{pr_number} for the dependency group '#{group.name}'."

updater/spec/dependabot/pull_request_spec.rb

Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -278,5 +278,93 @@
278278

279279
expect(pr1).not_to eq(pr2)
280280
end
281+
282+
it "is true when one has directory and the other doesn't" do
283+
pr1 = described_class.new(
284+
[
285+
Dependabot::PullRequest::Dependency.new(
286+
name: "foo",
287+
version: "1.0.0",
288+
directory: "/foo"
289+
)
290+
],
291+
pr_number: 123
292+
)
293+
pr2 = described_class.new(
294+
[
295+
Dependabot::PullRequest::Dependency.new(
296+
name: "foo",
297+
version: "1.0.0"
298+
)
299+
],
300+
pr_number: 456
301+
)
302+
303+
expect(pr1).to eq(pr2)
304+
end
305+
306+
it "is false when directories are different" do
307+
existing_pr = described_class.new(
308+
[
309+
Dependabot::PullRequest::Dependency.new(
310+
name: "rollup",
311+
version: "2.79.2",
312+
directory: "/packages/corelib"
313+
)
314+
],
315+
pr_number: 123
316+
)
317+
new_pr = described_class.new(
318+
[
319+
Dependabot::PullRequest::Dependency.new(
320+
name: "rollup",
321+
version: "2.79.2",
322+
directory: "/"
323+
)
324+
]
325+
)
326+
327+
expect(existing_pr).not_to eq(new_pr)
328+
end
329+
330+
it "is false when comparing PRs from job definition with different directories" do
331+
existing_prs = described_class.create_from_job_definition(
332+
existing_pull_requests: [
333+
[{ "dependency-name" => "rollup", "dependency-version" => "2.79.2", "directory" => "/packages/corelib" }]
334+
]
335+
)
336+
337+
updated_dependency = instance_double(
338+
Dependabot::Dependency,
339+
name: "rollup",
340+
version: "2.79.2",
341+
removed?: false,
342+
directory: "/."
343+
)
344+
new_pr = described_class.create_from_updated_dependencies([updated_dependency])
345+
346+
expect(existing_prs.find { |pr| pr == new_pr }).to be_nil
347+
end
348+
349+
it "is true when existing PR has no directory but new PR does" do
350+
existing_prs = described_class.create_from_job_definition(
351+
existing_pull_requests: [
352+
[{ "dependency-name" => "rollup", "dependency-version" => "2.79.2" }]
353+
]
354+
)
355+
356+
updated_dependency = instance_double(
357+
Dependabot::Dependency,
358+
name: "rollup",
359+
version: "2.79.2",
360+
removed?: false,
361+
directory: "/."
362+
)
363+
new_pr = described_class.create_from_updated_dependencies([updated_dependency])
364+
365+
expect(existing_prs.first.using_directory?).to be false
366+
expect(new_pr.using_directory?).to be true
367+
expect(existing_prs.find { |pr| pr == new_pr }).not_to be_nil
368+
end
281369
end
282370
end

updater/spec/dependabot/updater/operations/group_update_all_versions_spec.rb

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -284,6 +284,87 @@
284284
end
285285
end
286286

287+
context "when PR exists for same group but different directory" do
288+
before do
289+
allow(job).to receive_messages(
290+
existing_group_pull_requests: [
291+
{
292+
"dependency-group-name" => "dummy-group",
293+
"pr_number" => 123,
294+
"dependencies" => [
295+
{
296+
"dependency-name" => "rollup",
297+
"dependency-version" => "2.79.2",
298+
"directory" => "/packages/corelib"
299+
}
300+
]
301+
}
302+
],
303+
source: mock_source
304+
)
305+
allow(mock_source).to receive(:directory).and_return("/")
306+
end
307+
308+
it "creates a new PR for the different directory" do
309+
allow(mock_create_group_update).to receive(:perform).and_return(mock_dependency_change)
310+
expect(mock_create_group_update).to receive(:perform)
311+
expect(dependency_snapshot).not_to receive(:mark_group_handled).with(dependency_group)
312+
perform
313+
end
314+
end
315+
316+
context "when PR exists for same group and same directory" do
317+
before do
318+
allow(job).to receive_messages(
319+
existing_group_pull_requests: [
320+
{
321+
"dependency-group-name" => "dummy-group",
322+
"pr_number" => 123,
323+
"dependencies" => [
324+
{
325+
"dependency-name" => "rollup",
326+
"dependency-version" => "2.79.2",
327+
"directory" => "/"
328+
}
329+
]
330+
}
331+
],
332+
source: mock_source
333+
)
334+
allow(mock_source).to receive(:directory).and_return("/")
335+
end
336+
337+
it "skips creating a new PR" do
338+
expect(mock_create_group_update).not_to receive(:perform)
339+
expect(dependency_snapshot).to receive(:mark_group_handled).with(dependency_group)
340+
perform
341+
end
342+
end
343+
344+
context "when existing PR has no directory info" do
345+
before do
346+
allow(job).to receive_messages(
347+
existing_group_pull_requests: [
348+
{
349+
"dependency-group-name" => "dummy-group",
350+
"pr_number" => 123,
351+
"dependencies" => [
352+
{ "dependency-name" => "rollup", "dependency-version" => "2.79.2" }
353+
]
354+
}
355+
],
356+
source: mock_source
357+
)
358+
allow(mock_source).to receive(:directory).and_return("/")
359+
end
360+
361+
it "treats the existing PR as a match" do
362+
expect(mock_create_group_update).not_to receive(:perform)
363+
expect(dependency_snapshot).to receive(:mark_group_handled).with(dependency_group)
364+
perform
365+
end
366+
end
367+
287368
context "when group update fails" do
288369
before do
289370
allow(mock_create_group_update).to receive(:perform).and_return(nil)

0 commit comments

Comments
 (0)