Skip to content
Merged
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
30 changes: 25 additions & 5 deletions updater/lib/dependabot/update_graph_processor.rb
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,12 @@ def process_directory(branch:, directory:)
directory_dependency_files = dependency_files_for(directory)

submission = if directory_dependency_files.empty?
empty_submission(branch, directory_source)
empty_submission(
branch,
directory_source,
GithubApi::DependencySubmission::SnapshotStatus::SKIPPED,
GithubApi::DependencySubmission::SNAPSHOT_REASON_NO_MANIFESTS
)
else
create_submission(branch, directory_source, directory_dependency_files)
end
Expand All @@ -102,7 +107,13 @@ def process_directory(branch:, directory:)
return unless Dependabot::Environment.github_actions?

# Send an empty submission so the snapshot service has a record that the job id has been completed.
empty_submission = empty_submission(branch, T.must(directory_source))
error_details = Dependabot.updater_error_details(e) || { "error-type": "unknown_error" }
empty_submission = empty_submission(
branch,
T.must(directory_source),
GithubApi::DependencySubmission::SnapshotStatus::FAILED,
error_details.fetch(:"error-type")
)
service.create_dependency_submission(dependency_submission: empty_submission)
end

Expand All @@ -118,15 +129,24 @@ def dependency_files_for(directory)
dependency_files.select { |f| f.directory == directory }
end

sig { params(branch: String, source: Dependabot::Source).returns(GithubApi::DependencySubmission) }
def empty_submission(branch, source)
sig do
params(
branch: String,
source: Dependabot::Source,
status: GithubApi::DependencySubmission::SnapshotStatus,
reason: T.nilable(String)
).returns(GithubApi::DependencySubmission)
end
def empty_submission(branch, source, status, reason)
GithubApi::DependencySubmission.new(
job_id: job.id.to_s,
branch: branch,
sha: base_commit_sha,
package_manager: job.package_manager,
manifest_file: DependencyFile.new(name: "", content: "", directory: T.must(source.directory)),
resolved_dependencies: {}
resolved_dependencies: {},
status: status,
reason: reason
)
end

Expand Down
41 changes: 38 additions & 3 deletions updater/lib/github_api/dependency_submission.rb
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,17 @@ class DependencySubmission
SNAPSHOT_DETECTOR_NAME = "dependabot"
SNAPSHOT_DETECTOR_URL = "https://github.com/dependabot/dependabot-core"

class SnapshotStatus < T::Enum
enums do
SUCCESS = new("ok")
FAILED = new("failed")
SKIPPED = new("skipped")
end
end

# Expected when the graph change corresponds to a deleted manifest file
SNAPSHOT_REASON_NO_MANIFESTS = "missing-manifest-files"

sig { returns(String) }
attr_reader :job_id

Expand All @@ -35,24 +46,44 @@ class DependencySubmission
sig { returns(T::Hash[String, Dependabot::DependencyGraphers::ResolvedDependency]) }
attr_reader :resolved_dependencies

sig { returns(SnapshotStatus) }
attr_reader :status

sig { returns(T.nilable(String)) }
attr_reader :reason

sig do
params(
job_id: String,
branch: String,
sha: String,
package_manager: String,
manifest_file: Dependabot::DependencyFile,
resolved_dependencies: T::Hash[String, Dependabot::DependencyGraphers::ResolvedDependency]
resolved_dependencies: T::Hash[String, Dependabot::DependencyGraphers::ResolvedDependency],
status: SnapshotStatus,
reason: T.nilable(String)
).void
end
def initialize(job_id:, branch:, sha:, package_manager:, manifest_file:, resolved_dependencies:)
def initialize(
job_id:,
branch:,
sha:,
package_manager:,
manifest_file:,
resolved_dependencies:,
status: SnapshotStatus::SUCCESS,
reason: nil
)
@job_id = job_id
@branch = branch
@sha = sha
@package_manager = package_manager

@manifest_file = manifest_file
@resolved_dependencies = resolved_dependencies

@status = status
@reason = reason
end

# TODO: Change to a typed structure?
Expand All @@ -73,7 +104,11 @@ def payload
version: detector_version,
url: SNAPSHOT_DETECTOR_URL
},
manifests: manifests
manifests: manifests,
metadata: {
status: status.serialize,
reason: reason
}.compact
}
end

Expand Down
34 changes: 34 additions & 0 deletions updater/spec/dependabot/update_graph_processor_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -384,6 +384,10 @@

# It should be empty
expect(payload[:manifests].length).to be_zero

# It should contain the expected metadata
expect(payload[:metadata][:status]).to eql(GithubApi::DependencySubmission::SnapshotStatus::FAILED.serialize)
expect(payload[:metadata][:reason]).to eql("dependency_file_not_evaluatable")
end

it "correctly snapshots the second directory" do
Expand All @@ -410,6 +414,10 @@
expect(dependency1[:package_url]).to eql("pkg:gem/dummy-pkg-a@2.0.0")
dependency2 = lockfile[:resolved]["pkg:gem/dummy-pkg-b@1.1.0"]
expect(dependency2[:package_url]).to eql("pkg:gem/dummy-pkg-b@1.1.0")

# We should have metadata indicating a successful snapshot
expect(payload[:metadata][:status]).to eql(GithubApi::DependencySubmission::SnapshotStatus::SUCCESS.serialize)
expect(payload[:metadata][:reason]).to be_nil
end
end
end
Expand Down Expand Up @@ -529,6 +537,32 @@
end
end

# This is expected for graph updates corresponding to deleted files
context "with non-existent dependency files" do
let(:directories) { [directory] }
let(:directory) { "/" }
let(:repo_contents_path) { build_tmp_repo("bundler/original", path: "") }

let(:dependency_files) do
[]
end

it "generates an empty snapshot with metadata" do
expect(service).to receive(:create_dependency_submission) do |args|
payload = args[:dependency_submission].payload

expect(payload[:job][:correlator]).to eq("dependabot-bundler")
expect(payload[:manifests]).to be_empty

# It should contain the expected metadata
expect(payload[:metadata][:status]).to eq(GithubApi::DependencySubmission::SnapshotStatus::SKIPPED.serialize)
expect(payload[:metadata][:reason]).to eq(GithubApi::DependencySubmission::SNAPSHOT_REASON_NO_MANIFESTS)
end

update_graph_processor.run
end
end

describe "job validation" do
let(:dependency_files) do
[
Expand Down
Loading