Skip to content

Commit

Permalink
Merge pull request dependabot#8902 from dependabot/jamiemagee/strict-…
Browse files Browse the repository at this point in the history
…type-changelog-pruner

Strict type `Dependabot::MetadataFinders::Base::ChangelogPruner`
  • Loading branch information
abdulapopoola authored Jan 26, 2024
2 parents 9219b0c + 9a70f11 commit 6efbf16
Showing 1 changed file with 45 additions and 14 deletions.
59 changes: 45 additions & 14 deletions common/lib/dependabot/metadata_finders/base/changelog_pruner.rb
Original file line number Diff line number Diff line change
@@ -1,43 +1,60 @@
# typed: true
# typed: strict
# frozen_string_literal: true

require "sorbet-runtime"
require "dependabot/metadata_finders/base"

module Dependabot
module MetadataFinders
class Base
class ChangelogPruner
attr_reader :dependency, :changelog_text
extend T::Sig

sig { returns(Dependabot::Dependency) }
attr_reader :dependency

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

sig do
params(
dependency: Dependabot::Dependency,
changelog_text: T.nilable(String)
)
.void
end
def initialize(dependency:, changelog_text:)
@dependency = dependency
@changelog_text = changelog_text
end

sig { returns(T::Boolean) }
def includes_new_version?
!new_version_changelog_line.nil?
end

sig { returns(T::Boolean) }
def includes_previous_version?
!old_version_changelog_line.nil?
end

def pruned_text
changelog_lines = changelog_text.split("\n")
sig { returns(T.nilable(String)) }
def pruned_text # rubocop:disable Metrics/PerceivedComplexity
changelog_lines = changelog_text&.split("\n")

slice_range =
if old_version_changelog_line && new_version_changelog_line
if old_version_changelog_line < new_version_changelog_line
if T.must(old_version_changelog_line) < T.must(new_version_changelog_line)
Range.new(old_version_changelog_line, -1)
else
Range.new(new_version_changelog_line,
old_version_changelog_line - 1)
T.must(old_version_changelog_line) - 1)
end
elsif old_version_changelog_line
return if old_version_changelog_line.zero?
return if T.must(old_version_changelog_line).zero?

# Assumes changelog is in descending order
Range.new(0, old_version_changelog_line - 1)
Range.new(0, T.must(old_version_changelog_line) - 1)
elsif new_version_changelog_line
# Assumes changelog is in descending order
Range.new(new_version_changelog_line, -1)
Expand All @@ -49,33 +66,36 @@ def pruned_text
Range.new(0, -1)
end

changelog_lines.slice(slice_range).join("\n").rstrip
changelog_lines&.slice(slice_range)&.join("\n")&.rstrip
end

private

sig { returns(T.nilable(Integer)) }
def old_version_changelog_line
old_version = git_source? ? previous_ref : dependency.previous_version
return nil unless old_version

changelog_line_for_version(old_version)
end

sig { returns(T.nilable(Integer)) }
def new_version_changelog_line
return nil unless new_version

changelog_line_for_version(new_version)
end

# rubocop:disable Metrics/PerceivedComplexity
sig { params(version: T.nilable(String)).returns(T.nilable(Integer)) }
def changelog_line_for_version(version)
raise "No changelog text" unless changelog_text
return nil unless version

version = version.gsub(/^v/, "")
escaped_version = Regexp.escape(version)

changelog_lines = changelog_text.split("\n")
changelog_lines = T.must(changelog_text).split("\n")

changelog_lines.find_index.with_index do |line, index|
next false unless line.match?(/(?<!\.)#{escaped_version}(?![.\-])/)
Expand All @@ -92,13 +112,14 @@ def changelog_line_for_version(version)

# rubocop:enable Metrics/PerceivedComplexity

sig { returns(T::Boolean) }
def changelog_contains_relevant_versions?
# Assume the changelog is relevant if we can't parse the new version
return true unless version_class.correct?(dependency.version)

# Assume the changelog is relevant if it mentions the new version
# anywhere
return true if changelog_text.include?(dependency.version)
return true if changelog_text&.include?(T.must(dependency.version))

# Otherwise check if any intermediate versions are included in headers
versions_in_changelog_headers.any? do |version|
Expand All @@ -110,8 +131,9 @@ def changelog_contains_relevant_versions?
end
end

sig { returns(T::Array[String]) }
def versions_in_changelog_headers
changelog_lines = changelog_text.split("\n")
changelog_lines = T.must(changelog_text).split("\n")
header_lines =
changelog_lines.select.with_index do |line, index|
next true if line.start_with?("#", "!")
Expand All @@ -132,18 +154,25 @@ def versions_in_changelog_headers
versions
end

sig { returns(T.nilable(String)) }
def new_version
@new_version ||= git_source? ? new_ref : dependency.version
@new_version ||=
T.let(
git_source? ? new_ref : dependency.version,
T.nilable(String)
)
@new_version&.gsub(/^v/, "")
end

sig { returns(T.nilable(String)) }
def previous_ref
previous_refs = dependency.previous_requirements.filter_map do |r|
previous_refs = T.must(dependency.previous_requirements).filter_map do |r|
r.dig(:source, "ref") || r.dig(:source, :ref)
end.uniq
previous_refs.first if previous_refs.count == 1
end

sig { returns(T.nilable(String)) }
def new_ref
new_refs = dependency.requirements.filter_map do |r|
r.dig(:source, "ref") || r.dig(:source, :ref)
Expand All @@ -152,6 +181,7 @@ def new_ref
end

# TODO: Refactor me so that Composer doesn't need to be special cased
sig { returns(T::Boolean) }
def git_source?
# Special case Composer, which uses git as a source but handles tags
# internally
Expand All @@ -164,6 +194,7 @@ def git_source?
sources.all? { |s| s[:type] == "git" || s["type"] == "git" }
end

sig { returns(T.class_of(Dependabot::Version)) }
def version_class
dependency.version_class
end
Expand Down

0 comments on commit 6efbf16

Please sign in to comment.