From e34337cb09f2f1dd96bc3e30721054c92429c8fb Mon Sep 17 00:00:00 2001 From: kbukum1 Date: Thu, 31 Oct 2024 14:07:04 -0700 Subject: [PATCH] Centralizing Eco-System, and Package Manager Version Information (#10826) * move package manager into ecosystem wrapper for storing ecosystem related information alongside with package manager information. * update package manager to use version manager in ecosystem --- bundler/lib/dependabot/bundler/file_parser.rb | 19 ++- .../lib/dependabot/bundler/package_manager.rb | 37 ++-- .../dependabot/bundler/file_parser_spec.rb | 2 +- .../bundler/package_manager_spec.rb | 4 +- common/lib/dependabot/ecosystem.rb | 161 ++++++++++++++++++ common/lib/dependabot/file_parsers/base.rb | 6 +- common/lib/dependabot/notices.rb | 6 +- common/lib/dependabot/package_manager.rb | 98 ----------- common/spec/dependabot/ecosystem_spec.rb | 95 +++++++++++ .../spec/dependabot/file_parsers/base_spec.rb | 33 ++-- common/spec/dependabot/notices_spec.rb | 34 ++-- ...anager_spec.rb => version_manager_spec.rb} | 70 ++------ .../lib/dependabot/composer/file_parser.rb | 17 +- .../dependabot/composer/package_manager.rb | 35 ++-- .../dependabot/composer/file_parser_spec.rb | 2 +- .../composer/package_manager_spec.rb | 4 +- silent/lib/dependabot/silent/file_parser.rb | 14 +- .../lib/dependabot/silent/package_manager.rb | 33 +--- updater/lib/dependabot/dependency_snapshot.rb | 18 +- updater/lib/dependabot/notices_helpers.rb | 8 +- .../spec/dependabot/notices_helpers_spec.rb | 54 +++--- ...reate_security_update_pull_request_spec.rb | 9 +- .../refresh_group_update_pull_request_spec.rb | 9 +- ...efresh_version_update_pull_request_spec.rb | 11 +- .../operations/update_all_versions_spec.rb | 11 +- .../updater/pull_request_helpers_spec.rb | 25 +-- updater/spec/support/dummy_pkg_helpers.rb | 25 ++- 27 files changed, 472 insertions(+), 368 deletions(-) create mode 100644 common/lib/dependabot/ecosystem.rb delete mode 100644 common/lib/dependabot/package_manager.rb create mode 100644 common/spec/dependabot/ecosystem_spec.rb rename common/spec/dependabot/{package_manager_spec.rb => version_manager_spec.rb} (71%) diff --git a/bundler/lib/dependabot/bundler/file_parser.rb b/bundler/lib/dependabot/bundler/file_parser.rb index aafa43b3de2..a0e9461bcfa 100644 --- a/bundler/lib/dependabot/bundler/file_parser.rb +++ b/bundler/lib/dependabot/bundler/file_parser.rb @@ -32,13 +32,24 @@ def parse dependency_set.dependencies end - sig { returns(PackageManagerBase) } - def package_manager - PackageManager.new(bundler_version) + sig { returns(Ecosystem) } + def ecosystem + @ecosystem ||= T.let( + Ecosystem.new( + name: ECOSYSTEM, + package_manager: package_manager + ), + T.nilable(Ecosystem) + ) end private + sig { returns(Ecosystem::VersionManager) } + def package_manager + PackageManager.new(bundler_version) + end + def check_external_code(dependencies) return unless @reject_external_code return unless git_source?(dependencies) @@ -309,12 +320,14 @@ def gemspecs .select { |file| file.name.end_with?(".gemspec") } end + sig { returns(T::Array[Dependabot::DependencyFile]) } def imported_ruby_files dependency_files .select { |f| f.name.end_with?(".rb") } .reject { |f| f.name == "gems.rb" } end + sig { returns(String) } def bundler_version @bundler_version ||= Helpers.bundler_version(lockfile) end diff --git a/bundler/lib/dependabot/bundler/package_manager.rb b/bundler/lib/dependabot/bundler/package_manager.rb index b5c2816ab0b..f048c3141d5 100644 --- a/bundler/lib/dependabot/bundler/package_manager.rb +++ b/bundler/lib/dependabot/bundler/package_manager.rb @@ -3,10 +3,11 @@ require "sorbet-runtime" require "dependabot/bundler/version" -require "dependabot/package_manager" +require "dependabot/ecosystem" module Dependabot module Bundler + ECOSYSTEM = "bundler" PACKAGE_MANAGER = "bundler" # Keep versions in ascending order @@ -18,33 +19,17 @@ module Bundler # DEPRECATED_BUNDLER_VERSIONS = T.let([Version.new("1")].freeze, T::Array[Dependabot::Version]) DEPRECATED_BUNDLER_VERSIONS = T.let([].freeze, T::Array[Dependabot::Version]) - class PackageManager < PackageManagerBase + class PackageManager < Dependabot::Ecosystem::VersionManager extend T::Sig - 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 } + sig { params(raw_version: String).void } + def initialize(raw_version) + super( + PACKAGE_MANAGER, + Version.new(raw_version), + DEPRECATED_BUNDLER_VERSIONS, + SUPPORTED_BUNDLER_VERSIONS, + ) end end end diff --git a/bundler/spec/dependabot/bundler/file_parser_spec.rb b/bundler/spec/dependabot/bundler/file_parser_spec.rb index 4d2281a30a3..e4b73159e19 100644 --- a/bundler/spec/dependabot/bundler/file_parser_spec.rb +++ b/bundler/spec/dependabot/bundler/file_parser_spec.rb @@ -734,7 +734,7 @@ describe "#package_manager" do it "returns the correct package manager" do - expect(parser.package_manager).to be_a(Dependabot::Bundler::PackageManager) + expect(parser.ecosystem.package_manager).to be_a(Dependabot::Bundler::PackageManager) end end end diff --git a/bundler/spec/dependabot/bundler/package_manager_spec.rb b/bundler/spec/dependabot/bundler/package_manager_spec.rb index 35b69eaba92..6a6a619aeec 100644 --- a/bundler/spec/dependabot/bundler/package_manager_spec.rb +++ b/bundler/spec/dependabot/bundler/package_manager_spec.rb @@ -2,7 +2,7 @@ # frozen_string_literal: true require "dependabot/bundler/package_manager" -require "dependabot/package_manager" +require "dependabot/ecosystem" require "spec_helper" RSpec.describe Dependabot::Bundler::PackageManager do @@ -30,7 +30,7 @@ end context "when version is a Dependabot::Bundler::Version" do - let(:version) { Dependabot::Bundler::Version.new("2") } + let(:version) { "2" } it "sets the version correctly" do expect(package_manager.version).to eq(version) diff --git a/common/lib/dependabot/ecosystem.rb b/common/lib/dependabot/ecosystem.rb new file mode 100644 index 00000000000..13f53c549d6 --- /dev/null +++ b/common/lib/dependabot/ecosystem.rb @@ -0,0 +1,161 @@ +# typed: strong +# frozen_string_literal: true + +require "sorbet-runtime" + +module Dependabot + class Ecosystem + extend T::Sig + + class VersionManager + extend T::Sig + extend T::Helpers + + abstract! + # Initialize version information with optional requirement + # @param name [String] the name for the package manager (e.g., "bundler", "npm"). + # @param version [Dependabot::Version] the parsed current version. + # @param deprecated_versions [Array] an array of deprecated versions. + # @param supported_versions [Array] an array of supported versions. + # @example + # VersionManager.new("bundler", "2.1.4", Dependabot::Version.new("2.1.4"), nil) + sig do + params( + name: String, + version: Dependabot::Version, + deprecated_versions: T::Array[Dependabot::Version], + supported_versions: T::Array[Dependabot::Version] + ).void + end + def initialize( + name, + version, + deprecated_versions = [], + supported_versions = [] + ) + @name = T.let(name, String) + @version = T.let(version, Dependabot::Version) + + @deprecated_versions = T.let(deprecated_versions, T::Array[Dependabot::Version]) + @supported_versions = T.let(supported_versions, T::Array[Dependabot::Version]) + end + + # The name of the package manager (e.g., "bundler", "npm"). + # @example + # name #=> "bundler" + sig { returns(String) } + attr_reader :name + + # The current version of the package manager. + # @example + # version #=> Dependabot::Version.new("2.1.4") + sig { returns(Dependabot::Version) } + attr_reader :version + + # Returns an array of deprecated versions of the package manager. + # @example + # deprecated_versions #=> [Version.new("1")] + sig { returns(T::Array[Dependabot::Version]) } + attr_reader :deprecated_versions + + # Returns an array of supported versions of the package manager. + sig { returns(T::Array[Dependabot::Version]) } + attr_reader :supported_versions + + # Checks if the current version is deprecated. + # Returns true if the version is in the deprecated_versions array; false otherwise. + # @example + # deprecated? #=> true + sig { returns(T::Boolean) } + def deprecated? + return false if unsupported? + + deprecated_versions.include?(version) + end + + # Checks if the current version is unsupported. + # @example + # unsupported? #=> false + sig { returns(T::Boolean) } + def unsupported? + return false if supported_versions.empty? + + # Check if the version is not supported + supported_versions.all? { |supported| supported > version } + end + + # Raises an error if the current package manager or language version is unsupported. + # If the version is unsupported, it raises a ToolVersionNotSupported error. + sig { void } + def raise_if_unsupported! + return unless unsupported? + + # Example: v2.*, v3.* + supported_versions_message = supported_versions.map { |v| "v#{v}.*" }.join(", ") + + raise ToolVersionNotSupported.new( + name, + version.to_s, + supported_versions_message + ) + end + + # Indicates if the package manager supports later versions beyond those listed in supported_versions. + # By default, returns false if not overridden in the subclass. + # @example + # support_later_versions? #=> true + sig { returns(T::Boolean) } + def support_later_versions? + false + end + end + + # Initialize with mandatory name and optional language information. + # @param name [String] the name of the ecosystem (e.g., "bundler", "npm_and_yarn"). + # @param package_manager [VersionManager] the package manager. + sig do + params( + name: String, + package_manager: VersionManager + ).void + end + def initialize( + name:, + package_manager: + ) + @name = T.let(name, String) + @package_manager = T.let(package_manager, VersionManager) + end + + # The name of the ecosystem (mandatory). + # @example + # name #=> "npm_and_yarn" + sig { returns(String) } + attr_reader :name + + # The information related to the package manager (mandatory). + # @example + # package_manager #=> VersionManager.new("bundler", "2.1.4", Version.new("2.1.4"), nil) + sig { returns(VersionManager) } + attr_reader :package_manager + + # Checks if the current version is deprecated. + # Returns true if the version is in the deprecated_versions array; false otherwise. + sig { returns(T::Boolean) } + def deprecated? + package_manager.deprecated? + end + + # Checks if the current version is unsupported. + sig { returns(T::Boolean) } + def unsupported? + package_manager.unsupported? + end + + # Delegate to the package manager to raise ToolVersionNotSupported if the version is unsupported. + sig { void } + def raise_if_unsupported! + package_manager.raise_if_unsupported! + end + end +end diff --git a/common/lib/dependabot/file_parsers/base.rb b/common/lib/dependabot/file_parsers/base.rb index 450e82bf06c..068b40f2143 100644 --- a/common/lib/dependabot/file_parsers/base.rb +++ b/common/lib/dependabot/file_parsers/base.rb @@ -3,7 +3,7 @@ require "sorbet-runtime" require "dependabot/credential" -require "dependabot/package_manager" +require "dependabot/ecosystem" module Dependabot module FileParsers @@ -54,8 +54,8 @@ def initialize(dependency_files:, source:, repo_contents_path: nil, sig { abstract.returns(T::Array[Dependabot::Dependency]) } def parse; end - sig { returns(T.nilable(PackageManagerBase)) } - def package_manager + sig { returns(T.nilable(Ecosystem)) } + def ecosystem nil end diff --git a/common/lib/dependabot/notices.rb b/common/lib/dependabot/notices.rb index face593224b..89447a5a254 100644 --- a/common/lib/dependabot/notices.rb +++ b/common/lib/dependabot/notices.rb @@ -2,7 +2,7 @@ # frozen_string_literal: true require "sorbet-runtime" -require "dependabot/package_manager" +require "dependabot/ecosystem" module Dependabot class Notice @@ -95,11 +95,11 @@ def self.generate_supported_versions_description(supported_versions, support_lat end # Generates a deprecation notice for the given package manager. - # @param package_manager [PackageManagerBase] The package manager object. + # @param package_manager [VersionManager] The package manager object. # @return [Notice, nil] The generated deprecation notice or nil if the package manager is not deprecated. sig do params( - package_manager: PackageManagerBase + package_manager: Ecosystem::VersionManager ).returns(T.nilable(Notice)) end def self.generate_pm_deprecation_notice(package_manager) diff --git a/common/lib/dependabot/package_manager.rb b/common/lib/dependabot/package_manager.rb deleted file mode 100644 index 48b85dc67be..00000000000 --- a/common/lib/dependabot/package_manager.rb +++ /dev/null @@ -1,98 +0,0 @@ -# typed: strong -# frozen_string_literal: true - -require "sorbet-runtime" - -module Dependabot - class PackageManagerBase - extend T::Sig - extend T::Helpers - - abstract! - - # The name of the package manager (e.g., "bundler"). - # @example - # package_manager.name #=> "bundler" - sig { abstract.returns(String) } - def name; end - - # The version of the package manager (e.g., Dependabot::Version.new("2.1.4")). - # @example - # package_manager.version #=> Dependabot::Version.new("2.1.4") - sig { abstract.returns(Dependabot::Version) } - def version; end - - # Returns an array of deprecated versions of the package manager. - # By default, returns an empty array if not overridden in the subclass. - # @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 - - # Returns an array of unsupported versions of the package manager. - # By default, returns an empty array if not overridden in the subclass. - # @example - # package_manager.unsupported_versions #=> [Dependabot::Version.new("0.9.0")] - sig { returns(T::Array[Dependabot::Version]) } - def unsupported_versions - [] - end - - # 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 - - # Checks if the current version is deprecated. - # Returns true if the version is in the deprecated_versions array; false otherwise. - # @example - # package_manager.deprecated? #=> true - sig { returns(T::Boolean) } - def deprecated? - # If the version is unsupported, the unsupported error is getting raised separately. - return false if unsupported? - - deprecated_versions.include?(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 - end - - # Raises an error if the current package manager version is unsupported. - # If the version is unsupported, it raises a ToolVersionNotSupported error. - sig { void } - def raise_if_unsupported! - return unless unsupported? - - # Example: v2.*, v3.* - supported_versions_message = supported_versions.map { |v| "v#{v}.*" }.join(", ") - - raise ToolVersionNotSupported.new( - name, - version.to_s, - supported_versions_message - ) - end - - # Indicates if the package manager supports later versions beyond those listed in supported_versions. - # By default, returns false if not overridden in the subclass. - # @example - # package_manager.support_later_versions? #=> true - sig { returns(T::Boolean) } - def support_later_versions? - false - end - end -end diff --git a/common/spec/dependabot/ecosystem_spec.rb b/common/spec/dependabot/ecosystem_spec.rb new file mode 100644 index 00000000000..82448c077e1 --- /dev/null +++ b/common/spec/dependabot/ecosystem_spec.rb @@ -0,0 +1,95 @@ +# typed: false +# frozen_string_literal: true + +require "spec_helper" +require "dependabot/ecosystem" + +RSpec.describe Dependabot::Ecosystem do + let(:supported_versions) { [Dependabot::Version.new("1"), Dependabot::Version.new("2")] } + let(:deprecated_versions) { [Dependabot::Version.new("1")] } + + let(:package_manager_raw_version) { "1.0.0" } + let(:language_raw_version) { "3.0.0" } + + let(:package_manager) do + Class.new(Dependabot::Ecosystem::VersionManager) do + def initialize(raw_version, deprecated_versions, supported_versions) + super( + "bundler", # name + Dependabot::Version.new(raw_version), # version + deprecated_versions, # deprecated_versions + supported_versions # supported_versions + ) + end + end.new(package_manager_raw_version, deprecated_versions, supported_versions) + end + + describe "#initialize" do + it "sets the correct attributes" do + ecosystem = described_class.new(name: "bundler", package_manager: package_manager) + + expect(ecosystem.name).to eq("bundler") + expect(ecosystem.package_manager.name).to eq("bundler") + end + end + + describe "#deprecated?" do + context "when the package manager version is deprecated" do + let(:package_manager_raw_version) { "1" } + + it "returns true" do + ecosystem = described_class.new(name: "bundler", package_manager: package_manager) + expect(ecosystem.deprecated?).to be true + end + end + + context "when the package manager version is not deprecated" do + let(:package_manager_raw_version) { "2.0.0" } + + it "returns false" do + ecosystem = described_class.new(name: "bundler", package_manager: package_manager) + expect(ecosystem.deprecated?).to be false + end + end + end + + describe "#unsupported?" do + context "when the package manager version is unsupported" do + let(:package_manager_raw_version) { "0.8.0" } + + it "returns true" do + ecosystem = described_class.new(name: "bundler", package_manager: package_manager) + expect(ecosystem.unsupported?).to be true + end + end + + context "when the package manager version is supported" do + let(:package_manager_raw_version) { "2.0.0" } + + it "returns false" do + ecosystem = described_class.new(name: "bundler", package_manager: package_manager) + expect(ecosystem.unsupported?).to be false + end + end + end + + describe "#raise_if_unsupported!" do + context "when the package manager version is unsupported" do + let(:package_manager_raw_version) { "0.8.0" } + + it "raises a ToolVersionNotSupported error" do + ecosystem = described_class.new(name: "bundler", package_manager: package_manager) + expect { ecosystem.raise_if_unsupported! }.to raise_error(Dependabot::ToolVersionNotSupported) + end + end + + context "when the package manager version is supported" do + let(:package_manager_raw_version) { "2.0.0" } + + it "does not raise an error" do + ecosystem = described_class.new(name: "bundler", package_manager: package_manager) + expect { ecosystem.raise_if_unsupported! }.not_to raise_error + end + end + end +end diff --git a/common/spec/dependabot/file_parsers/base_spec.rb b/common/spec/dependabot/file_parsers/base_spec.rb index dc6e99be775..76105e54279 100644 --- a/common/spec/dependabot/file_parsers/base_spec.rb +++ b/common/spec/dependabot/file_parsers/base_spec.rb @@ -46,25 +46,15 @@ let(:files) { [gemfile] } let(:concrete_package_manager_class) do - Class.new(Dependabot::PackageManagerBase) do - def name - "bundler" - end - - def version - Dependabot::Version.new("1.0.0") - end - - def deprecated_versions - [Dependabot::Version.new("1.0.0")] - end - - def unsupported_versions - [Dependabot::Version.new("0.9.0")] - end - - def supported_versions - [Dependabot::Version.new("1.1.0"), Dependabot::Version.new("2.0.0")] + Class.new(Dependabot::Ecosystem::VersionManager) do + def initialize + raw_version = "1.0.0" + super( + "bundler", # name + Dependabot::Version.new(raw_version), # version + [Dependabot::Version.new("1.0.0")], # deprecated_versions + [Dependabot::Version.new("1.1.0"), Dependabot::Version.new("2.0.0")] # supported_versions + ) end def support_later_versions? @@ -117,8 +107,8 @@ def support_later_versions? context "when called on a concrete class" do let(:package_manager_instance) { concrete_package_manager_class.new } - it "returns an instance of PackageManagerBase" do - expect(parser_instance.package_manager).to be_a(Dependabot::PackageManagerBase) + it "returns an instance of Ecosystem::VersionManager" do + expect(parser_instance.package_manager).to be_a(Dependabot::Ecosystem::VersionManager) end it "returns the correct package manager details" do @@ -126,7 +116,6 @@ def support_later_versions? expect(pm.name).to eq("bundler") expect(pm.version).to eq(Dependabot::Version.new("1.0.0")) expect(pm.deprecated_versions).to eq([Dependabot::Version.new("1.0.0")]) - expect(pm.unsupported_versions).to eq([Dependabot::Version.new("0.9.0")]) expect(pm.supported_versions).to eq([Dependabot::Version.new("1.1.0"), Dependabot::Version.new("2.0.0")]) expect(pm.support_later_versions?).to be true end diff --git a/common/spec/dependabot/notices_spec.rb b/common/spec/dependabot/notices_spec.rb index cde5924755d..f148d20b5b8 100644 --- a/common/spec/dependabot/notices_spec.rb +++ b/common/spec/dependabot/notices_spec.rb @@ -3,40 +3,34 @@ require "dependabot/version" require "dependabot/experiments" -require "dependabot/package_manager" +require "dependabot/ecosystem" require "dependabot/notices" # A stub package manager for testing purposes. -class StubPackageManager < Dependabot::PackageManagerBase - def initialize(name:, version:, deprecated_versions: [], unsupported_versions: [], supported_versions: [], +class StubPackageManager < Dependabot::Ecosystem::VersionManager + def initialize(name:, version:, deprecated_versions: [], supported_versions: [], support_later_versions: false) - @name = name - @version = version - @deprecated_versions = deprecated_versions - @unsupported_versions = unsupported_versions - @supported_versions = supported_versions @support_later_versions = support_later_versions + super( + name, + Dependabot::Version.new(version), + deprecated_versions, + supported_versions + ) end - attr_reader :name - attr_reader :version - attr_reader :deprecated_versions - attr_reader :unsupported_versions - attr_reader :supported_versions attr_reader :support_later_versions sig { override.returns(T::Boolean) } - def deprecated? - # If the version is unsupported, the unsupported error is getting raised separately. - return false if unsupported? - - deprecated_versions.include?(version) + def unsupported? + # Determine if the Bundler version is unsupported. + version < supported_versions.first end sig { override.returns(T::Boolean) } - def unsupported? + def support_later_versions? # Determine if the Bundler version is unsupported. - version < supported_versions.first + support_later_versions end end diff --git a/common/spec/dependabot/package_manager_spec.rb b/common/spec/dependabot/version_manager_spec.rb similarity index 71% rename from common/spec/dependabot/package_manager_spec.rb rename to common/spec/dependabot/version_manager_spec.rb index 8e265514320..d8f8d53375f 100644 --- a/common/spec/dependabot/package_manager_spec.rb +++ b/common/spec/dependabot/version_manager_spec.rb @@ -2,43 +2,19 @@ # frozen_string_literal: true require "spec_helper" -require "dependabot/package_manager" +require "dependabot/ecosystem" -RSpec.describe Dependabot::PackageManagerBase do # rubocop:disable RSpec/FilePath,RSpec/SpecFilePathFormat +RSpec.describe Dependabot::Ecosystem::VersionManager do # rubocop:disable RSpec/FilePath,RSpec/SpecFilePathFormat let(:concrete_class) do - Class.new(Dependabot::PackageManagerBase) do - def name - "bundler" - end - - def version - @version ||= Dependabot::Version.new("1.0.0") - end - - def deprecated_versions - [Dependabot::Version.new("1")] - end - - def unsupported_versions - [Dependabot::Version.new("0")] - end - - def supported_versions - @supported_versions ||= [Dependabot::Version.new("1"), Dependabot::Version.new("2")] - end - - sig { override.returns(T::Boolean) } - def deprecated? - # If the version is unsupported, treat it as unsupported, not deprecated. - return false if unsupported? - - deprecated_versions.include?(version) - end - - sig { override.returns(T::Boolean) } - def unsupported? - # Determine if the version is unsupported based on supported_versions. - version < supported_versions.first + Class.new(Dependabot::Ecosystem::VersionManager) do + def initialize + raw_version = "1.0.0" + super( + "bundler", # name + Dependabot::Version.new(raw_version), # version + [Dependabot::Version.new("1")], # deprecated_versions + [Dependabot::Version.new("1"), Dependabot::Version.new("2")] # supported_versions + ) end def support_later_versions? @@ -48,13 +24,13 @@ def support_later_versions? end let(:default_concrete_class) do - Class.new(Dependabot::PackageManagerBase) do - def name - "bundler" - end - - def version - Dependabot::Version.new("1.0.0") + Class.new(Dependabot::Ecosystem::VersionManager) do + def initialize + raw_version = "1.0.0" + super( + "bundler", # name + Dependabot::Version.new(raw_version) + ) end end end @@ -84,16 +60,6 @@ def version end end - describe "#unsupported_versions" do - it "returns an array of unsupported versions" do - expect(package_manager.unsupported_versions).to eq([Dependabot::Version.new("0")]) - end - - it "returns an empty array by default" do - expect(default_package_manager.unsupported_versions).to eq([]) - end - end - describe "#supported_versions" do it "returns an array of supported versions" do expect(package_manager.supported_versions).to eq([ diff --git a/composer/lib/dependabot/composer/file_parser.rb b/composer/lib/dependabot/composer/file_parser.rb index d2f888ba75d..92f1307c652 100644 --- a/composer/lib/dependabot/composer/file_parser.rb +++ b/composer/lib/dependabot/composer/file_parser.rb @@ -35,13 +35,24 @@ def parse dependency_set.dependencies end - sig { returns(PackageManagerBase) } - def package_manager - PackageManager.new(composer_version) + sig { returns(Ecosystem) } + def ecosystem + @ecosystem ||= T.let( + Ecosystem.new( + name: ECOSYSTEM, + package_manager: package_manager + ), + T.nilable(Ecosystem) + ) end private + sig { returns(Ecosystem::VersionManager) } + def package_manager + PackageManager.new(composer_version) + end + sig { returns(DependencySet) } def manifest_dependencies # rubocop:disable Metrics/PerceivedComplexity dependencies = T.let(DependencySet.new, DependencySet) diff --git a/composer/lib/dependabot/composer/package_manager.rb b/composer/lib/dependabot/composer/package_manager.rb index f4b106c869e..20cb732c411 100644 --- a/composer/lib/dependabot/composer/package_manager.rb +++ b/composer/lib/dependabot/composer/package_manager.rb @@ -2,11 +2,12 @@ # frozen_string_literal: true require "sorbet-runtime" -require "dependabot/package_manager" +require "dependabot/ecosystem" require "dependabot/composer/version" module Dependabot module Composer + ECOSYSTEM = "composer" PACKAGE_MANAGER = "composer" # Keep versions in ascending order @@ -16,29 +17,19 @@ module Composer Version.new("1") ].freeze, T::Array[Dependabot::Version]) - class PackageManager < PackageManagerBase + class PackageManager < Dependabot::Ecosystem::VersionManager extend T::Sig - 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]) + sig { params(raw_version: String).void } + def initialize(raw_version) + super( + PACKAGE_MANAGER, + Version.new(raw_version), + 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 - sig { override.returns(T::Boolean) } def deprecated? return false if unsupported? @@ -46,7 +37,7 @@ def deprecated? # 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 sig { override.returns(T::Boolean) } @@ -54,7 +45,7 @@ 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 diff --git a/composer/spec/dependabot/composer/file_parser_spec.rb b/composer/spec/dependabot/composer/file_parser_spec.rb index 19f902bcec7..c05162e1af7 100644 --- a/composer/spec/dependabot/composer/file_parser_spec.rb +++ b/composer/spec/dependabot/composer/file_parser_spec.rb @@ -412,7 +412,7 @@ describe "#package_manager" do it "returns the correct package manager" do - expect(parser.package_manager).to be_a(Dependabot::Composer::PackageManager) + expect(parser.ecosystem.package_manager).to be_a(Dependabot::Composer::PackageManager) end end end diff --git a/composer/spec/dependabot/composer/package_manager_spec.rb b/composer/spec/dependabot/composer/package_manager_spec.rb index 1475c0f5058..c4aa100563d 100644 --- a/composer/spec/dependabot/composer/package_manager_spec.rb +++ b/composer/spec/dependabot/composer/package_manager_spec.rb @@ -2,7 +2,7 @@ # frozen_string_literal: true require "dependabot/composer/package_manager" -require "dependabot/package_manager" +require "dependabot/ecosystem" require "spec_helper" RSpec.describe Dependabot::Composer::PackageManager do @@ -30,7 +30,7 @@ end context "when version is a Dependabot::Version" do - let(:version) { Dependabot::Version.new("2") } + let(:version) { "2" } it "sets the version correctly" do expect(package_manager.version).to eq(version) diff --git a/silent/lib/dependabot/silent/file_parser.rb b/silent/lib/dependabot/silent/file_parser.rb index a7c4f7203dc..01b9cd679fa 100644 --- a/silent/lib/dependabot/silent/file_parser.rb +++ b/silent/lib/dependabot/silent/file_parser.rb @@ -4,7 +4,7 @@ require "dependabot/dependency" require "dependabot/file_parsers" require "dependabot/file_parsers/base" -require "dependabot/package_manager" +require "dependabot/ecosystem" require "dependabot/silent/package_manager" require "sorbet-runtime" @@ -28,15 +28,21 @@ def parse raise Dependabot::DependencyFileNotParseable, T.must(dependency_files.first).path end - sig { returns(Dependabot::PackageManagerBase) } - def package_manager + sig { returns(Dependabot::Ecosystem) } + def ecosystem meta_data = JSON.parse(manifest_content)["silent"] silent_version = if meta_data.nil? "2" else meta_data["version"] end - Dependabot::Silent::PackageManager.new(silent_version) + @ecosystem ||= T.let( + Dependabot::Ecosystem.new( + name: Dependabot::Silent::ECOSYSYEM, + package_manager: Dependabot::Silent::PackageManager.new(silent_version) + ), + T.nilable(Dependabot::Ecosystem) + ) rescue JSON::ParserError raise Dependabot::DependencyFileNotParseable, T.must(dependency_files.first).path end diff --git a/silent/lib/dependabot/silent/package_manager.rb b/silent/lib/dependabot/silent/package_manager.rb index 7f8d54f10f3..c26e3646454 100644 --- a/silent/lib/dependabot/silent/package_manager.rb +++ b/silent/lib/dependabot/silent/package_manager.rb @@ -3,42 +3,27 @@ require "sorbet-runtime" require "dependabot/silent/version" -require "dependabot/package_manager" +require "dependabot/ecosystem" module Dependabot module Silent + ECOSYSYEM = "silent" PACKAGE_MANAGER = "silent" SUPPORTED_SILENT_VERSIONS = T.let([Version.new("2")].freeze, T::Array[Dependabot::Version]) DEPRECATED_SILENT_VERSIONS = T.let([Version.new("1")].freeze, T::Array[Dependabot::Version]) - class PackageManager < PackageManagerBase + class PackageManager < Ecosystem::VersionManager extend T::Sig 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_SILENT_VERSIONS, T::Array[Dependabot::Version]) - @supported_versions = T.let(SUPPORTED_SILENT_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 } + super( + PACKAGE_MANAGER, + Version.new(version), + DEPRECATED_SILENT_VERSIONS, + SUPPORTED_SILENT_VERSIONS, + ) end end end diff --git a/updater/lib/dependabot/dependency_snapshot.rb b/updater/lib/dependabot/dependency_snapshot.rb index 02b03c4ef46..8c92710705e 100644 --- a/updater/lib/dependabot/dependency_snapshot.rb +++ b/updater/lib/dependabot/dependency_snapshot.rb @@ -67,9 +67,9 @@ def dependencies T.must(@dependencies[@current_directory]) end - sig { returns(T.nilable(Dependabot::PackageManagerBase)) } - def package_manager - @package_manager[@current_directory] + sig { returns(T.nilable(Dependabot::Ecosystem)) } + def ecosystem + @ecosystem[@current_directory] end sig { returns(T::Array[Dependabot::Notice]) } @@ -181,7 +181,7 @@ def initialize(job:, base_commit_sha:, dependency_files:) # rubocop:disable Metr @current_directory = T.let("", String) @dependencies = T.let({}, T::Hash[String, T::Array[Dependabot::Dependency]]) - @package_manager = T.let({}, T::Hash[String, T.nilable(Dependabot::PackageManagerBase)]) + @ecosystem = T.let({}, T::Hash[String, T.nilable(Dependabot::Ecosystem)]) @notices = T.let({}, T::Hash[String, T::Array[Dependabot::Notice]]) directories.each do |dir| @@ -241,12 +241,12 @@ def dependency_file_parser reject_external_code: job.reject_external_code?, options: job.experiments ) - # Add 'package_manager' to the dependency_snapshot to use it in operations - package_manager = parser.package_manager + # Add 'ecosystem' to the dependency_snapshot to use it in operations + ecosystem = parser.ecosystem # Raise an error if the package manager version is unsupported - package_manager&.raise_if_unsupported! + ecosystem&.raise_if_unsupported! - @package_manager[@current_directory] = package_manager + @ecosystem[@current_directory] = ecosystem # Log deprecation notices if the package manager is deprecated # and add them to the notices array @@ -255,7 +255,7 @@ def dependency_file_parser # add deprecation notices for the package manager add_deprecation_notice( notices: notices_for_current_directory, - package_manager: package_manager + package_manager: ecosystem&.package_manager ) @notices[@current_directory] = notices_for_current_directory diff --git a/updater/lib/dependabot/notices_helpers.rb b/updater/lib/dependabot/notices_helpers.rb index c8f52474df8..8c89d0daa75 100644 --- a/updater/lib/dependabot/notices_helpers.rb +++ b/updater/lib/dependabot/notices_helpers.rb @@ -3,7 +3,7 @@ require "sorbet-runtime" require "dependabot/notices" -require "dependabot/package_manager" +require "dependabot/ecosystem" # This module extracts helpers for notice generations that can be used # for showing notices in logs, pr messages and alert ui page. @@ -20,7 +20,7 @@ module NoticesHelpers sig do params( notices: T::Array[Dependabot::Notice], - package_manager: T.nilable(PackageManagerBase) + package_manager: T.nilable(Ecosystem::VersionManager) ) .void end @@ -58,11 +58,11 @@ def log_notice(notice) private - sig { params(package_manager: T.nilable(PackageManagerBase)).returns(T.nilable(Dependabot::Notice)) } + sig { params(package_manager: T.nilable(Ecosystem::VersionManager)).returns(T.nilable(Dependabot::Notice)) } def create_deprecation_notice(package_manager) return unless package_manager - return unless package_manager.is_a?(PackageManagerBase) + return unless package_manager.is_a?(Ecosystem::VersionManager) Notice.generate_pm_deprecation_notice( package_manager diff --git a/updater/spec/dependabot/notices_helpers_spec.rb b/updater/spec/dependabot/notices_helpers_spec.rb index 45ac2b598b3..115573dd3f9 100644 --- a/updater/spec/dependabot/notices_helpers_spec.rb +++ b/updater/spec/dependabot/notices_helpers_spec.rb @@ -3,7 +3,7 @@ require "spec_helper" require "dependabot/updater" -require "dependabot/package_manager" +require "dependabot/ecosystem" require "dependabot/notices" require "dependabot/notices_helpers" @@ -23,25 +23,23 @@ def initialize let(:dummy_instance) { dummy_class.new } let(:package_manager) do - Class.new(Dependabot::PackageManagerBase) do - def name - "bundler" - end - - def version - Dependabot::Version.new("1") - end - - def deprecated_versions - [Dependabot::Version.new("1")] - end - - def supported_versions - [Dependabot::Version.new("2"), Dependabot::Version.new("3")] + Class.new(Dependabot::Ecosystem::VersionManager) do + def initialize + raw_version = "1" + super( + "bundler", # name + Dependabot::Version.new(raw_version), # version + [Dependabot::Version.new("1")], # deprecated_versions + [Dependabot::Version.new("2"), Dependabot::Version.new("3")] # supported_versions + ) end end.new end + before do + allow(package_manager).to receive(:unsupported?).and_return(false) + end + describe "#add_deprecation_notice" do context "when package manager is provided and is deprecated" do it "adds a deprecation notice to the notices array" do @@ -81,21 +79,15 @@ def supported_versions context "when package manager is not deprecated" do let(:package_manager) do - Class.new(Dependabot::PackageManagerBase) do - def name - "bundler" - end - - def version - Dependabot::Version.new("2") - end - - def deprecated_versions - [Dependabot::Version.new("1")] - end - - def supported_versions - [Dependabot::Version.new("2"), Dependabot::Version.new("3")] + Class.new(Dependabot::Ecosystem::VersionManager) do + def initialize + raw_version = "2" + super( + "bundler", # name + Dependabot::Version.new(raw_version), # version + [Dependabot::Version.new("1")], # deprecated_versions + [Dependabot::Version.new("2"), Dependabot::Version.new("3")] # supported_versions + ) end end.new end diff --git a/updater/spec/dependabot/updater/operations/create_security_update_pull_request_spec.rb b/updater/spec/dependabot/updater/operations/create_security_update_pull_request_spec.rb index 3fd645e8c9d..eea4493fe35 100644 --- a/updater/spec/dependabot/updater/operations/create_security_update_pull_request_spec.rb +++ b/updater/spec/dependabot/updater/operations/create_security_update_pull_request_spec.rb @@ -60,6 +60,13 @@ ) end + let(:ecosystem) do + Dependabot::Ecosystem.new( + name: "bundler", + package_manager: package_manager + ) + end + let(:package_manager) do DummyPkgHelpers::StubPackageManager.new( name: "bundler", @@ -218,7 +225,7 @@ allow(dependency_snapshot).to receive_messages( job_dependencies: [dependency], - package_manager: package_manager, + ecosystem: ecosystem, notices: [warning_deprecation_notice] ) allow(job).to receive(:security_fix?).and_return(true) diff --git a/updater/spec/dependabot/updater/operations/refresh_group_update_pull_request_spec.rb b/updater/spec/dependabot/updater/operations/refresh_group_update_pull_request_spec.rb index e877821b783..7ed869447ae 100644 --- a/updater/spec/dependabot/updater/operations/refresh_group_update_pull_request_spec.rb +++ b/updater/spec/dependabot/updater/operations/refresh_group_update_pull_request_spec.rb @@ -63,6 +63,13 @@ original_bundler_files end + let(:ecosystem) do + Dependabot::Ecosystem.new( + name: "bundler", + package_manager: package_manager + ) + end + let(:package_manager) do DummyPkgHelpers::StubPackageManager.new( name: "bundler", @@ -81,7 +88,7 @@ end before do - allow(dependency_snapshot).to receive(:package_manager).and_return(package_manager) + allow(dependency_snapshot).to receive(:ecosystem).and_return(ecosystem) allow(job).to receive(:package_manager).and_return("bundler") end diff --git a/updater/spec/dependabot/updater/operations/refresh_version_update_pull_request_spec.rb b/updater/spec/dependabot/updater/operations/refresh_version_update_pull_request_spec.rb index d8abdac525c..565ef59006e 100644 --- a/updater/spec/dependabot/updater/operations/refresh_version_update_pull_request_spec.rb +++ b/updater/spec/dependabot/updater/operations/refresh_version_update_pull_request_spec.rb @@ -11,7 +11,7 @@ require "dependabot/updater/error_handler" require "dependabot/updater/operations/refresh_version_update_pull_request" require "dependabot/dependency_change_builder" -require "dependabot/package_manager" +require "dependabot/ecosystem" require "dependabot/notices" require "dependabot/bundler" @@ -54,6 +54,13 @@ ) end + let(:ecosystem) do + Dependabot::Ecosystem.new( + name: "bundler", + package_manager: package_manager + ) + end + let(:package_manager) do DummyPkgHelpers::StubPackageManager.new( name: "bundler", @@ -132,7 +139,7 @@ allow(Dependabot::DependencyChangeBuilder) .to receive(:create_from) .and_return(stub_dependency_change) - allow(dependency_snapshot).to receive(:package_manager).and_return(package_manager) + allow(dependency_snapshot).to receive(:ecosystem).and_return(ecosystem) end after do diff --git a/updater/spec/dependabot/updater/operations/update_all_versions_spec.rb b/updater/spec/dependabot/updater/operations/update_all_versions_spec.rb index cc667cfe6b3..b98d18f5551 100644 --- a/updater/spec/dependabot/updater/operations/update_all_versions_spec.rb +++ b/updater/spec/dependabot/updater/operations/update_all_versions_spec.rb @@ -12,7 +12,7 @@ require "dependabot/updater/operations/update_all_versions" require "dependabot/dependency_change_builder" require "dependabot/environment" -require "dependabot/package_manager" +require "dependabot/ecosystem" require "dependabot/notices" require "dependabot/notices_helpers" @@ -63,6 +63,13 @@ ) end + let(:ecosystem) do + Dependabot::Ecosystem.new( + name: "bundler", + package_manager: package_manager + ) + end + let(:package_manager) do DummyPkgHelpers::StubPackageManager.new( name: "bundler", @@ -157,7 +164,7 @@ allow(Dependabot::DependencyChangeBuilder).to receive( :create_from ).and_return(stub_dependency_change) - allow(dependency_snapshot).to receive_messages(package_manager: package_manager, notices: [ + allow(dependency_snapshot).to receive_messages(ecosystem: ecosystem, notices: [ warning_deprecation_notice ]) end diff --git a/updater/spec/dependabot/updater/pull_request_helpers_spec.rb b/updater/spec/dependabot/updater/pull_request_helpers_spec.rb index f48f5cbf85c..48d5839817a 100644 --- a/updater/spec/dependabot/updater/pull_request_helpers_spec.rb +++ b/updater/spec/dependabot/updater/pull_request_helpers_spec.rb @@ -3,7 +3,7 @@ require "spec_helper" require "dependabot/updater" -require "dependabot/package_manager" +require "dependabot/ecosystem" require "dependabot/notices" require "dependabot/service" @@ -26,22 +26,13 @@ def initialize(service = nil) let(:service) { instance_double(Dependabot::Service) } let(:package_manager) do - Class.new(Dependabot::PackageManagerBase) do - def name - "bundler" - end - - def version - Dependabot::Version.new("1") - end - - def deprecated_versions - [Dependabot::Version.new("1")] - end - - def supported_versions - [Dependabot::Version.new("2"), Dependabot::Version.new("3")] - end + Class.new(Dependabot::Ecosystem::VersionManager) do + super( + "bundler", # name + Dependabot::Version.new("1"), # version + [Dependabot::Version.new("1")], # deprecated_versions + [Dependabot::Version.new("2"), Dependabot::Version.new("3")] # supported_versions + ) end.new end diff --git a/updater/spec/support/dummy_pkg_helpers.rb b/updater/spec/support/dummy_pkg_helpers.rb index 2750b821bdf..2ff6b3aeb89 100644 --- a/updater/spec/support/dummy_pkg_helpers.rb +++ b/updater/spec/support/dummy_pkg_helpers.rb @@ -1,7 +1,7 @@ # typed: false # frozen_string_literal: true -require "dependabot/package_manager" +require "dependabot/ecosystem" require "dependabot/dependency_file" # This module provides some shortcuts for working with our two mock RubyGems packages: @@ -63,22 +63,17 @@ def updated_bundler_files_hash(fixture: "bundler") updated_bundler_files(fixture: fixture).map(&:to_h) end - # Stub PackageManagerBase - class StubPackageManager < Dependabot::PackageManagerBase - def initialize(name:, version:, deprecated_versions: [], unsupported_versions: [], supported_versions: []) - @name = name - @version = version - @deprecated_versions = deprecated_versions - @unsupported_versions = unsupported_versions - @supported_versions = supported_versions + # Stub Ecosystem::VersionManager + class StubPackageManager < Dependabot::Ecosystem::VersionManager + def initialize(name:, version:, deprecated_versions: [], supported_versions: []) + super( + name, + Dependabot::Version.new(version), + deprecated_versions, + supported_versions + ) end - attr_reader :name - attr_reader :version - attr_reader :deprecated_versions - attr_reader :unsupported_versions - attr_reader :supported_versions - sig { override.returns(T::Boolean) } def deprecated? # If the version is unsupported, the unsupported error is getting raised separately.