Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 20 additions & 0 deletions updater/lib/dependabot/file_fetcher_command.rb
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ def perform_job # rubocop:disable Metrics/AbcSize
Dependabot.logger.error("Error during file fetching; aborting: #{e.message}")
end
handle_file_fetcher_error(e)
handle_missing_directory_for_pr_update(e)
service.mark_job_as_processed(@base_commit_sha)
return nil
end
Expand Down Expand Up @@ -408,5 +409,24 @@ def git_metadata_fetcher
T.nilable(Dependabot::GitMetadataFetcher)
)
end

# When updating a pull request, if the directory or dependency files
# are no longer found, we should close the PR as the dependency has
# been removed from the project.
sig { params(error: StandardError).void }
def handle_missing_directory_for_pr_update(error)
dependencies = job.dependencies

return unless job.updating_a_pull_request?
return unless dependencies
return unless error.is_a?(Dependabot::DependencyFileNotFound) ||
error.is_a?(Dependabot::DirectoryNotFound)

Dependabot.logger.info(
"Closing pull request for #{dependencies.join(', ')} " \
"as the directory or dependency files are no longer present"
)
service.close_pull_request(dependencies, :dependency_removed)
end
end
end
136 changes: 136 additions & 0 deletions updater/spec/dependabot/file_fetcher_command_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -652,5 +652,141 @@
expect(root_files.map(&:name)).to include("a.dummy")
end
end

context "when updating a pull request and directory is not found" do
let(:job_definition) do
job_def = JSON.parse(fixture("jobs/job_with_credentials.json"))
job_def["job"]["updating-a-pull-request"] = true
job_def["job"]["dependencies"] = ["dummy-pkg-a"]
job_def
end

before do
allow_any_instance_of(Dependabot::Bundler::FileFetcher)
.to receive(:commit)
.and_return("a" * 40)
allow_any_instance_of(Dependabot::Bundler::FileFetcher)
.to receive(:files)
.and_raise(Dependabot::DependencyFileNotFound.new("/some/deleted/directory"))
end

it "closes the pull request and records the error" do
expect(api_client)
.to receive(:record_update_job_error)
.with(
error_details: {
"file-path": "/some/deleted/directory",
message: "/some/deleted/directory not found"
},
error_type: "dependency_file_not_found"
)
expect(api_client)
.to receive(:close_pull_request)
.with(["dummy-pkg-a"], :dependency_removed)
expect(api_client).to receive(:mark_job_as_processed)

expect { perform_job }.to output(/Error during file fetching; aborting/).to_stdout_from_any_process
end
end

context "when updating a pull request and DirectoryNotFound is raised" do
let(:job_definition) do
job_def = JSON.parse(fixture("jobs/job_with_credentials.json"))
job_def["job"]["updating-a-pull-request"] = true
job_def["job"]["dependencies"] = ["dummy-pkg-b"]
job_def
end

before do
allow_any_instance_of(Dependabot::Bundler::FileFetcher)
.to receive(:commit)
.and_return("b" * 40)
allow_any_instance_of(Dependabot::Bundler::FileFetcher)
.to receive(:files)
.and_raise(Dependabot::DirectoryNotFound.new("/deleted/dir"))
end

it "closes the pull request and records the error" do
expect(api_client)
.to receive(:record_update_job_error)
.with(
error_details: { "directory-name": "/deleted/dir" },
error_type: "directory_not_found"
)
expect(api_client)
.to receive(:close_pull_request)
.with(["dummy-pkg-b"], :dependency_removed)
expect(api_client).to receive(:mark_job_as_processed)

expect { perform_job }.to output(/Error during file fetching; aborting/).to_stdout_from_any_process
end
end

context "when not updating a pull request and directory is not found" do
let(:job_definition) do
job_def = JSON.parse(fixture("jobs/job_with_credentials.json"))
job_def["job"]["updating-a-pull-request"] = false
job_def
end

before do
allow_any_instance_of(Dependabot::Bundler::FileFetcher)
.to receive(:commit)
.and_return("c" * 40)
allow_any_instance_of(Dependabot::Bundler::FileFetcher)
.to receive(:files)
.and_raise(Dependabot::DependencyFileNotFound.new("/some/directory"))
end

it "records the error but does not close any pull request" do
expect(api_client)
.to receive(:record_update_job_error)
.with(
error_details: {
"file-path": "/some/directory",
message: "/some/directory not found"
},
error_type: "dependency_file_not_found"
)
expect(api_client).not_to receive(:close_pull_request)
expect(api_client).to receive(:mark_job_as_processed)

expect { perform_job }.to output(/Error during file fetching; aborting/).to_stdout_from_any_process
end
end

context "when updating a pull request with nil dependencies and directory is not found" do
let(:job_definition) do
job_def = JSON.parse(fixture("jobs/job_with_credentials.json"))
job_def["job"]["updating-a-pull-request"] = true
job_def["job"]["dependencies"] = nil
job_def
end

before do
allow_any_instance_of(Dependabot::Bundler::FileFetcher)
.to receive(:commit)
.and_return("d" * 40)
allow_any_instance_of(Dependabot::Bundler::FileFetcher)
.to receive(:files)
.and_raise(Dependabot::DependencyFileNotFound.new("/some/directory"))
end

it "records the error but does not attempt to close PR" do
expect(api_client)
.to receive(:record_update_job_error)
.with(
error_details: {
"file-path": "/some/directory",
message: "/some/directory not found"
},
error_type: "dependency_file_not_found"
)
expect(api_client).not_to receive(:close_pull_request)
expect(api_client).to receive(:mark_job_as_processed)

expect { perform_job }.to output(/Error during file fetching; aborting/).to_stdout_from_any_process
end
end
end
end
Loading