Skip to content

Commit

Permalink
update package manager to support keeping ecosystem, language and pac…
Browse files Browse the repository at this point in the history
…kage manager information
  • Loading branch information
kbukum1 committed Oct 23, 2024
1 parent 9979b6a commit e4c54e1
Show file tree
Hide file tree
Showing 3 changed files with 198 additions and 74 deletions.
41 changes: 19 additions & 22 deletions bundler/lib/dependabot/bundler/package_manager.rb
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
module Dependabot
module Bundler
PACKAGE_MANAGER = "bundler"
ECOSYSTEM = "bundler"

# Keep versions in ascending order
SUPPORTED_BUNDLER_VERSIONS = T.let([Version.new("2")].freeze, T::Array[Dependabot::Version])
Expand All @@ -21,30 +22,26 @@ module Bundler
class PackageManager < PackageManagerBase
extend T::Sig

# Initialize Bundler's PackageManager class
# @param version [String, Dependabot::Version] the current version of Bundler
sig { params(version: T.any(String, Dependabot::Version)).void }
def initialize(version)
@version = T.let(Version.new(version), Dependabot::Version)
@name = T.let(PACKAGE_MANAGER, String)
@deprecated_versions = T.let(DEPRECATED_BUNDLER_VERSIONS, T::Array[Dependabot::Version])
@supported_versions = T.let(SUPPORTED_BUNDLER_VERSIONS, T::Array[Dependabot::Version])
end

sig { override.returns(String) }
attr_reader :name

sig { override.returns(Dependabot::Version) }
attr_reader :version

sig { override.returns(T::Array[Dependabot::Version]) }
attr_reader :deprecated_versions

sig { override.returns(T::Array[Dependabot::Version]) }
attr_reader :supported_versions

sig { override.returns(T::Boolean) }
def unsupported?
# Check if the version is not supported
supported_versions.all? { |supported| supported > version }
# Set up the version information for the package manager
package_manager_info = Dependabot::VersionInformation.new(
PACKAGE_MANAGER,
version.to_s,
Version.new(version),
nil # No specific requirements for Bundler
)

# Call the superclass constructor, passing ecosystem, nil for language, and version info
super(
ECOSYSTEM, # ecosystem name is mandatory
package_manager_info,
nil, # TODO: language info is not yet implemented
DEPRECATED_BUNDLER_VERSIONS,
SUPPORTED_BUNDLER_VERSIONS
)
end
end
end
Expand Down
189 changes: 157 additions & 32 deletions common/lib/dependabot/package_manager.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,50 +4,176 @@
require "sorbet-runtime"

module Dependabot
class VersionInformation
extend T::Sig

# Initialize version information with optional requirement
# @param name [String] the name of the package manager or language (e.g., "bundler", "ruby").
# @param raw_current_version [String] the raw current version of the package manager or language.
# @param current_version [Dependabot::Version] the parsed current version.
# @param requirement [T.nilable(Requirement)] the version requirements, optional.
# @example
# VersionInformation.new("bundler", "2.1.4", Dependabot::Version.new("2.1.4"), nil)
sig do
params(
name: String,
raw_current_version: String,
current_version: Dependabot::Version,
requirement: T.nilable(Requirement)
).void
end
def initialize(name, raw_current_version, current_version, requirement = nil)
@name = T.let(name, String)
@raw_current_version = T.let(raw_current_version, String)
@current_version = T.let(current_version, Dependabot::Version)
@requirement = T.let(requirement, T.nilable(Requirement))
end

# The name of the package manager or language (e.g., "bundler", "ruby").
# @example
# version_information.name #=> "bundler"
sig { returns(String) }
attr_reader :name

# The current version of the package manager or language.
# @example
# version_information.current_version #=> Dependabot::Version.new("2.1.4")
sig { returns(Dependabot::Version) }
attr_reader :current_version

# The raw current version of the package manager or language as a string.
# @example
# version_information.raw_current_version #=> "2.1.4"
sig { returns(String) }
attr_reader :raw_current_version

# The version requirements (optional).
# @example
# version_information.requirement #=> Requirement.new(">= 2.1")
sig { returns(T.nilable(Requirement)) }
attr_reader :requirement
end

class Requirement
extend T::Sig

# Initialize version requirements with optional raw strings and parsed versions.
# @param req_raw [T.nilable(String)] the raw version requirements.
# @param req_raw_min [T.nilable(String)] the raw minimum version requirement.
# @param req_min [T.nilable(Dependabot::Version)] the parsed minimum version requirement.
# @param req_raw_max [T.nilable(String)] the raw maximum version requirement.
# @param req_max [T.nilable(Dependabot::Version)] the parsed maximum version requirement.
# @example
# Requirement.new(">= 2.0", "2.0", Version.new("2.0"), "3.0", Version.new("3.0"))
sig do
params(
req_raw: T.nilable(String),
req_raw_min: T.nilable(String),
req_min: T.nilable(Dependabot::Version),
req_raw_max: T.nilable(String),
req_max: T.nilable(Dependabot::Version)
).void
end
def initialize(
req_raw,
req_raw_min,
req_min,
req_raw_max,
req_max
)
# Ensure the type is correctly assigned to nullable types
@req_raw = T.let(req_raw, T.nilable(String))
@req_raw_min = T.let(req_raw_min, T.nilable(String))
@req_min = T.let(req_min, T.nilable(Dependabot::Version)) # Correctly inferred as nilable version
@req_raw_max = T.let(req_raw_max, T.nilable(String))
@req_max = T.let(req_max, T.nilable(Dependabot::Version)) # Correctly inferred as nilable version
end

# The raw version requirement.
sig { returns(T.nilable(String)) }
attr_reader :req_raw

# The raw minimum version requirement.
sig { returns(T.nilable(String)) }
attr_reader :req_raw_min

# The parsed minimum version requirement.
sig { returns(T.nilable(Dependabot::Version)) }
attr_reader :req_min

# The raw maximum version requirement.
sig { returns(T.nilable(String)) }
attr_reader :req_raw_max

# The parsed maximum version requirement.
sig { returns(T.nilable(Dependabot::Version)) }
attr_reader :req_max
end

class PackageManagerBase
extend T::Sig
extend T::Helpers

abstract!

# The name of the package manager (e.g., "bundler").
# Initialize with mandatory ecosystem and optional language information.
# @param ecosystem [String] the name of the ecosystem (e.g., "bundler", "npm").
# @param package_manager [VersionInformation] the version information of the package manager.
# @param language [T.nilable(VersionInformation)] optional language version information.
# @param deprecated_versions [Array<Dependabot::Version>] an array of deprecated versions.
# @param supported_versions [Array<Dependabot::Version>] an array of supported versions.
# @example
# package_manager.name #=> "bundler"
sig { abstract.returns(String) }
def name; end
# PackageManagerBase.new("bundler", nil, version_info, [], [Version.new("2.0")])
sig do
params(
ecosystem: String,
package_manager: VersionInformation,
language: T.nilable(VersionInformation),
deprecated_versions: T::Array[Dependabot::Version],
supported_versions: T::Array[Dependabot::Version]
).void
end
def initialize(
ecosystem,
package_manager,
language,
deprecated_versions = [],
supported_versions = []
)
@ecosystem = T.let(ecosystem, String)
@package_manager = T.let(package_manager, VersionInformation)
@language = T.let(language, T.nilable(VersionInformation))
@deprecated_versions = T.let(deprecated_versions, T::Array[Dependabot::Version])
@supported_versions = T.let(supported_versions, T::Array[Dependabot::Version])
end

# The version of the package manager (e.g., Dependabot::Version.new("2.1.4")).
# The name of the ecosystem (e.g., "bundler", "npm").
# @example
# package_manager.version #=> Dependabot::Version.new("2.1.4")
sig { abstract.returns(Dependabot::Version) }
def version; end
# package_manager.ecosystem #=> "npm_and_yarn"
sig { returns(String) }
attr_reader :ecosystem

# Returns an array of deprecated versions of the package manager.
# By default, returns an empty array if not overridden in the subclass.
# The version information of the language (optional).
# @example
# package_manager.deprecated_versions #=> [Dependabot::Version.new("1.0.0"), Dependabot::Version.new("1.1.0")]
sig { returns(T::Array[Dependabot::Version]) }
def deprecated_versions
[]
end
# package_manager.language #=> VersionInformation.new("ruby", "3.0.0", Version.new("3.0.0"), nil)
sig { returns(T.nilable(VersionInformation)) }
attr_reader :language

# Returns an array of unsupported versions of the package manager.
# By default, returns an empty array if not overridden in the subclass.
# The version information of the package manager.
# @example
# package_manager.package_manager #=> VersionInformation.new("bundler", "2.1.4", Version.new("2.1.4"), nil)
sig { returns(VersionInformation) }
attr_reader :package_manager

# Returns an array of deprecated versions of the package manager.
# @example
# package_manager.unsupported_versions #=> [Dependabot::Version.new("0.9.0")]
# package_manager.deprecated_versions #=> [Version.new("1")]
sig { returns(T::Array[Dependabot::Version]) }
def unsupported_versions
[]
end
attr_reader :deprecated_versions

# Returns an array of supported versions of the package manager.
# By default, returns an empty array if not overridden in the subclass.
# @example
# package_manager.supported_versions #=> [Dependabot::Version.new("2.0.0"), Dependabot::Version.new("2.1.0")]
sig { returns(T::Array[Dependabot::Version]) }
def supported_versions
[]
end
attr_reader :supported_versions

# Checks if the current version is deprecated.
# Returns true if the version is in the deprecated_versions array; false otherwise.
Expand All @@ -58,16 +184,15 @@ def deprecated?
# If the version is unsupported, the unsupported error is getting raised separately.
return false if unsupported?

deprecated_versions.include?(version)
deprecated_versions.include?(package_manager.current_version)
end

# Checks if the current version is unsupported.
# Returns true if the version is in the unsupported_versions array; false otherwise.
# @example
# package_manager.unsupported? #=> false
sig { returns(T::Boolean) }
def unsupported?
false
supported_versions.empty? || supported_versions.all? { |v| v > package_manager.current_version }
end

# Raises an error if the current package manager version is unsupported.
Expand All @@ -80,8 +205,8 @@ def raise_if_unsupported!
supported_versions_message = supported_versions.map { |v| "v#{v}.*" }.join(", ")

raise ToolVersionNotSupported.new(
name,
version.to_s,
package_manager.name,
package_manager.current_version.to_s,
supported_versions_message
)
end
Expand Down
42 changes: 22 additions & 20 deletions composer/lib/dependabot/composer/package_manager.rb
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@

module Dependabot
module Composer
ECOSYSTEM = "composer"
PACKAGE_MANAGER = "composer"

# Keep versions in ascending order
Expand All @@ -19,42 +20,43 @@ module Composer
class PackageManager < PackageManagerBase
extend T::Sig

# Initialize the Composer package manager with a version.
# @param version [T.any(String, Dependabot::Version)] the current version of Composer in use.
sig { params(version: T.any(String, Dependabot::Version)).void }
def initialize(version)
@version = T.let(Version.new(version), Dependabot::Version)
@name = T.let(PACKAGE_MANAGER, String)
@deprecated_versions = T.let(DEPRECATED_COMPOSER_VERSIONS, T::Array[Dependabot::Version])
@supported_versions = T.let(SUPPORTED_COMPOSER_VERSIONS, T::Array[Dependabot::Version])
# Create a version information instance for Composer.
package_manager_info = VersionInformation.new(
PACKAGE_MANAGER,
version.to_s,
Version.new(version)
)

# Call the superclass initializer
super(
ECOSYSTEM,
package_manager_info,
nil, # TODO: language info is not yet implemented
DEPRECATED_COMPOSER_VERSIONS,
SUPPORTED_COMPOSER_VERSIONS
)
end

sig { override.returns(String) }
attr_reader :name

sig { override.returns(Dependabot::Version) }
attr_reader :version

sig { override.returns(T::Array[Dependabot::Version]) }
attr_reader :deprecated_versions

sig { override.returns(T::Array[Dependabot::Version]) }
attr_reader :supported_versions

# Override deprecated method to check if the version is deprecated.
sig { override.returns(T::Boolean) }
def deprecated?
return false if unsupported?

# Check if the feature flag for Composer v1 deprecation warning is enabled.
return false unless Dependabot::Experiments.enabled?(:composer_v1_deprecation_warning)

deprecated_versions.include?(version)
super
end

# Override unsupported method to check if the version is unsupported.
sig { override.returns(T::Boolean) }
def unsupported?
# Check if the feature flag for Composer v1 unsupported error is enabled.
return false unless Dependabot::Experiments.enabled?(:composer_v1_unsupported_error)

supported_versions.all? { |supported| supported > version }
super
end
end
end
Expand Down

0 comments on commit e4c54e1

Please sign in to comment.