豆豆友情提示:这是一个非官方 GitHub 代理镜像,主要用于网络测试或访问加速。请勿在此进行登录、注册或处理任何敏感信息。进行这些操作请务必访问官方网站 github.com。 Raw 内容也通过此代理提供。
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
1 change: 1 addition & 0 deletions .rubocop_todo.yml
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,7 @@ Metrics/AbcSize:
# Offense count: 354/350
Metrics/ClassLength:
Exclude:
- 'common/lib/dependabot/dependency.rb'
- 'opentofu/lib/dependabot/opentofu/file_parser.rb'
Comment on lines 156 to 159
Copy link

Copilot AI Mar 9, 2026

Choose a reason for hiding this comment

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

Adding common/lib/dependabot/dependency.rb to the global RuboCop todo exclusions (Metrics/ClassLength) increases long-term lint debt. Since the class-length increase here is driven by the new humanized_previous_version refactor, it would be better to adjust the implementation (e.g., keep the existing logic inline, or extract functionality into a separate helper/module) so the file remains compliant without extending .rubocop_todo.yml exclusions.

Copilot generated this review using guidance from repository custom instructions.

# Offense count: 8
Expand Down
77 changes: 60 additions & 17 deletions common/lib/dependabot/dependency.rb
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,10 @@ class Dependency
)
@display_name_builders = T.let({}, T::Hash[String, T.proc.params(arg0: String).returns(String)])
@name_normalisers = T.let({}, T::Hash[String, T.proc.params(arg0: String).returns(String)])
@humanized_previous_version_builders = T.let(
{},
T::Hash[String, T.proc.params(arg0: Dependency).returns(T.nilable(String))]
)

sig do
params(package_manager: String).returns(T.proc.params(arg0: T::Array[T.untyped]).returns(T::Boolean))
Expand Down Expand Up @@ -61,6 +65,25 @@ def self.register_name_normaliser(package_manager, name_builder)
@name_normalisers[package_manager] = name_builder
end

sig do
params(
package_manager: String
).returns(T.nilable(T.proc.params(arg0: Dependency).returns(T.nilable(String))))
end
def self.humanized_previous_version_builder_for_package_manager(package_manager)
@humanized_previous_version_builders[package_manager]
end

sig do
params(
package_manager: String,
builder: T.proc.params(arg0: Dependency).returns(T.nilable(String))
).void
end
def self.register_humanized_previous_version_builder(package_manager, builder)
@humanized_previous_version_builders[package_manager] = builder
end

sig { returns(String) }
attr_reader :name

Expand Down Expand Up @@ -225,24 +248,10 @@ def display_name

sig { returns(T.nilable(String)) }
def humanized_previous_version
# If we don't have a previous version, we *may* still be able to figure
# one out if a ref was provided and has been changed (in which case the
# previous ref was essentially the version).
if previous_version.nil?
return ref_changed? ? previous_ref : nil
end

if T.must(previous_version).match?(/^[0-9a-f]{40}/)
return previous_ref if ref_changed? && previous_ref
custom_version = custom_humanized_previous_version
return custom_version if custom_version

"`#{T.must(previous_version)[0..6]}`"
elsif version == previous_version &&
package_manager == "docker"
digest = docker_digest_from_reqs(T.must(previous_requirements))
"`#{T.must(T.must(digest).split(':').last)[0..6]}`"
else
previous_version
end
default_humanized_previous_version
end

sig { returns(T.nilable(String)) }
Expand Down Expand Up @@ -391,6 +400,40 @@ def requirements_changed?

private

sig { returns(T.nilable(String)) }
def custom_humanized_previous_version
builder = self.class.humanized_previous_version_builder_for_package_manager(package_manager)
return nil unless builder

builder.call(self)
end

sig { returns(T.nilable(String)) }
def default_humanized_previous_version
# If we don't have a previous version, we *may* still be able to figure
# one out if a ref was provided and has been changed (in which case the
# previous ref was essentially the version).
return (ref_changed? ? previous_ref : nil) if previous_version.nil?

return humanized_sha_previous_version if T.must(previous_version).match?(/^[0-9a-f]{40}/)
return humanized_docker_previous_version if version == previous_version && package_manager == "docker"

previous_version
end

sig { returns(T.nilable(String)) }
def humanized_sha_previous_version
return previous_ref if ref_changed? && previous_ref

"`#{T.must(previous_version)[0..6]}`"
end

sig { returns(String) }
def humanized_docker_previous_version
digest = docker_digest_from_reqs(T.must(previous_requirements))
"`#{T.must(T.must(digest).split(':').last)[0..6]}`"
end

sig { void }
def check_values
check_requirement_fields
Expand Down
108 changes: 108 additions & 0 deletions common/spec/dependabot/dependency_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -392,4 +392,112 @@
expect(dependency.all_versions).to eq(["1.0.0", "2.0.0"])
end
end

describe "#humanized_previous_version" do
context "with a registered humanized_previous_version_builder" do
before do
described_class.register_humanized_previous_version_builder(
"test_pm",
->(dep) { dep.previous_requirements&.dig(0, :metadata, :comment_version) }
)
end

it "uses the registered builder when it returns a value" do
dependency = described_class.new(
name: "dep",
version: "abc123def456789012345678901234567890abcd",
previous_version: "6f6a02c2c85a1b45e39c1aa5e6cc40f7a3d6df5e",
requirements: [{
file: "config.yaml",
requirement: nil,
groups: [],
source: { type: "git", ref: "abc123def456789012345678901234567890abcd" }
}],
previous_requirements: [{
file: "config.yaml",
requirement: nil,
groups: [],
source: { type: "git", ref: "6f6a02c2c85a1b45e39c1aa5e6cc40f7a3d6df5e" },
metadata: { comment_version: "v2.2.1" }
}],
package_manager: "test_pm"
)

expect(dependency.humanized_previous_version).to eq("v2.2.1")
end

it "falls back to default behavior when builder returns nil" do
dependency = described_class.new(
name: "dep",
version: "abc123def456789012345678901234567890abcd",
previous_version: "6f6a02c2c85a1b45e39c1aa5e6cc40f7a3d6df5e",
requirements: [{
file: "config.yaml",
requirement: nil,
groups: [],
source: { type: "git", ref: "abc123def456789012345678901234567890abcd" }
}],
previous_requirements: [{
file: "config.yaml",
requirement: nil,
groups: [],
source: { type: "git", ref: "6f6a02c2c85a1b45e39c1aa5e6cc40f7a3d6df5e" }
}],
package_manager: "test_pm"
)

# Falls back to previous_ref when ref changed and previous_ref exists
expect(dependency.humanized_previous_version).to eq("6f6a02c2c85a1b45e39c1aa5e6cc40f7a3d6df5e")
end
end

context "without a registered builder" do
it "returns the previous_version when it's not a SHA" do
dependency = described_class.new(
name: "dep",
version: "v2.0.0",
previous_version: "v1.0.0",
requirements: [{
file: "config.yaml",
requirement: nil,
groups: [],
source: nil
}],
previous_requirements: [{
file: "config.yaml",
requirement: nil,
groups: [],
source: nil
}],
package_manager: "no_builder_pm"
)

expect(dependency.humanized_previous_version).to eq("v1.0.0")
end

it "returns previous_ref when previous_version is a SHA and ref changed" do
dependency = described_class.new(
name: "dep",
version: "abc123def456789012345678901234567890abcd",
previous_version: "6f6a02c2c85a1b45e39c1aa5e6cc40f7a3d6df5e",
requirements: [{
file: "config.yaml",
requirement: nil,
groups: [],
source: { type: "git", ref: "abc123def456789012345678901234567890abcd" }
}],
previous_requirements: [{
file: "config.yaml",
requirement: nil,
groups: [],
source: { type: "git", ref: "6f6a02c2c85a1b45e39c1aa5e6cc40f7a3d6df5e" }
}],
package_manager: "no_builder_pm"
)

# Returns previous_ref when ref changed and previous_ref exists
expect(dependency.humanized_previous_version).to eq("6f6a02c2c85a1b45e39c1aa5e6cc40f7a3d6df5e")
end
end
end
end
21 changes: 20 additions & 1 deletion pre_commit/lib/dependabot/pre_commit.rb
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# typed: strong
# typed: strict
# frozen_string_literal: true

# These all need to be required so the various classes can be registered in a
Expand All @@ -11,10 +11,29 @@
require "dependabot/pre_commit/version"
require "dependabot/pre_commit/requirement"
require "dependabot/pre_commit/helpers"
require "dependabot/pre_commit/comment_version_helper"

require "dependabot/pull_request_creator/labeler"
Dependabot::PullRequestCreator::Labeler
.register_label_details("pre_commit", name: "pre_commit", colour: "000000")

require "dependabot/dependency"
Dependabot::Dependency.register_production_check("pre_commit", ->(_) { true })

# Register a humanized previous version builder for pre_commit that extracts
# the version from the comment when using frozen SHA format (e.g., rev: <sha> # v2.2.1)
Dependabot::Dependency.register_humanized_previous_version_builder(
"pre_commit",
lambda { |dep|
previous_reqs = dep.previous_requirements
return nil unless previous_reqs

comment = previous_reqs
.filter_map { |r| r.dig(:metadata, :comment) }
.first
return nil unless comment

match = comment.match(Dependabot::PreCommit::CommentVersionHelper::COMMENT_VERSION_PATTERN)
match&.[](0)
}
)
Loading
Loading