diff --git a/hex/lib/dependabot/hex/file_parser.rb b/hex/lib/dependabot/hex/file_parser.rb index f575b744d8..d39067d116 100644 --- a/hex/lib/dependabot/hex/file_parser.rb +++ b/hex/lib/dependabot/hex/file_parser.rb @@ -7,12 +7,16 @@ require "dependabot/file_parsers/base" require "dependabot/hex/file_updater/mixfile_sanitizer" require "dependabot/hex/native_helpers" +require "dependabot/hex/language" +require "dependabot/hex/package_manager" +require "dependabot/hex/requirement" require "dependabot/shared_helpers" require "dependabot/errors" # For docs, see https://hexdocs.pm/mix/Mix.Tasks.Deps.html module Dependabot module Hex + extend T::Sig class FileParser < Dependabot::FileParsers::Base extend T::Sig require "dependabot/file_parsers/base/dependency_set" @@ -44,6 +48,17 @@ def parse dependency_set.dependencies.sort_by(&:name) end + sig { returns(Ecosystem) } + def ecosystem + @ecosystem ||= T.let(begin + Ecosystem.new( + name: ECOSYSTEM, + package_manager: package_manager, + language: language + ) + end, T.nilable(Dependabot::Ecosystem)) + end + private sig { returns(T::Array[T.any(T::Hash[String, String], T::Hash[String, T.untyped])]) } @@ -137,6 +152,43 @@ def mixfiles def lockfile @lockfile ||= T.let(get_original_file("mix.lock"), T.nilable(Dependabot::DependencyFile)) end + + sig { returns(Ecosystem::VersionManager) } + def package_manager + @package_manager ||= T.let( + PackageManager.new(hex_version), + T.nilable(Dependabot::Hex::PackageManager) + ) + end + + sig { returns(T.nilable(Ecosystem::VersionManager)) } + def language + @language ||= T.let( + Language.new(elixir_version), + T.nilable(Dependabot::Hex::Language) + ) + end + + sig { returns(String) } + def hex_version + T.must(T.must(hex_info).fetch(:hex_version)) + end + + sig { returns(String) } + def elixir_version + T.must(T.must(hex_info).fetch(:elixir_version)) + end + + sig { returns(T.nilable(T::Hash[Symbol, T.nilable(String)])) } + def hex_info + @hex_info ||= T.let(begin + version = SharedHelpers.run_shell_command("mix hex.info") + { + hex_version: version.match(/Hex: \s*(\d+\.\d+(.\d+)*)/)&.captures&.first, + elixir_version: version.match(/Elixir: \s*(\d+\.\d+(.\d+)*)/)&.captures&.first + } + end, T.nilable(T::Hash[Symbol, T.nilable(String)])) + end end end end diff --git a/hex/lib/dependabot/hex/language.rb b/hex/lib/dependabot/hex/language.rb new file mode 100644 index 0000000000..b315e6ab61 --- /dev/null +++ b/hex/lib/dependabot/hex/language.rb @@ -0,0 +1,21 @@ +# typed: strong +# frozen_string_literal: true + +require "sorbet-runtime" +require "dependabot/ecosystem" +require "dependabot/hex/version" + +module Dependabot + module Hex + LANGUAGE = "elixir" + + class Language < Dependabot::Ecosystem::VersionManager + extend T::Sig + + sig { params(raw_version: String).void } + def initialize(raw_version) + super(LANGUAGE, Version.new(raw_version)) + end + end + end +end diff --git a/hex/lib/dependabot/hex/package_manager.rb b/hex/lib/dependabot/hex/package_manager.rb new file mode 100644 index 0000000000..f973be7d12 --- /dev/null +++ b/hex/lib/dependabot/hex/package_manager.rb @@ -0,0 +1,41 @@ +# typed: strong +# frozen_string_literal: true + +require "sorbet-runtime" +require "dependabot/ecosystem" +require "dependabot/hex/version" + +module Dependabot + module Hex + ECOSYSTEM = "hex" + PACKAGE_MANAGER = "hex" + SUPPORTED_HEX_VERSIONS = T.let([].freeze, T::Array[Dependabot::Version]) + + # When a version is going to be unsupported, it will be added here + DEPRECATED_HEX_VERSIONS = T.let([].freeze, T::Array[Dependabot::Version]) + + class PackageManager < Dependabot::Ecosystem::VersionManager + extend T::Sig + + sig { params(raw_version: String).void } + def initialize(raw_version) + super( + PACKAGE_MANAGER, + Version.new(raw_version), + DEPRECATED_HEX_VERSIONS, + SUPPORTED_HEX_VERSIONS + ) + end + + sig { returns(T::Boolean) } + def deprecated? + false + end + + sig { returns(T::Boolean) } + def unsupported? + false + end + end + end +end diff --git a/hex/spec/dependabot/hex/file_parser_spec.rb b/hex/spec/dependabot/hex/file_parser_spec.rb index efc026fbb4..bc5fca2d5e 100644 --- a/hex/spec/dependabot/hex/file_parser_spec.rb +++ b/hex/spec/dependabot/hex/file_parser_spec.rb @@ -452,4 +452,32 @@ end end end + + describe "#ecosystem" do + subject(:ecosystem) { parser.ecosystem } + + it "has the correct name" do + expect(ecosystem.name).to eq "hex" + end + + describe "#package_manager" do + subject(:package_manager) { ecosystem.package_manager } + + it "returns the correct package manager" do + expect(package_manager.name).to eq "hex" + expect(package_manager.requirement).to be_nil + expect(package_manager.version.to_s).to eq "2.0.6" + end + end + + describe "#language" do + subject(:language) { ecosystem.language } + + it "returns the correct language" do + expect(language.name).to eq "elixir" + expect(language.requirement).to be_nil + expect(language.version.to_s).to eq "1.14.4" + end + end + end end diff --git a/hex/spec/dependabot/hex/language_spec.rb b/hex/spec/dependabot/hex/language_spec.rb new file mode 100644 index 0000000000..f4b7602c59 --- /dev/null +++ b/hex/spec/dependabot/hex/language_spec.rb @@ -0,0 +1,36 @@ +# typed: false +# frozen_string_literal: true + +require "dependabot/hex/language" +require "dependabot/ecosystem" +require "spec_helper" + +RSpec.describe Dependabot::Hex::Language do + subject(:language) { described_class.new(version) } + + let(:version) { "1.17.3" } + + describe "#version" do + it "returns the version" do + expect(language.version).to eq(Dependabot::Hex::Version.new(version)) + end + end + + describe "#name" do + it "returns the name" do + expect(language.name).to eq(Dependabot::Hex::LANGUAGE) + end + end + + describe "#unsupported?" do + it "returns false by default" do + expect(language.unsupported?).to be false + end + end + + describe "#deprecated?" do + it "returns false by default" do + expect(language.deprecated?).to be false + end + end +end diff --git a/hex/spec/dependabot/hex/package_manager_spec.rb b/hex/spec/dependabot/hex/package_manager_spec.rb new file mode 100644 index 0000000000..da86d34185 --- /dev/null +++ b/hex/spec/dependabot/hex/package_manager_spec.rb @@ -0,0 +1,36 @@ +# typed: false +# frozen_string_literal: true + +require "dependabot/hex/package_manager" +require "dependabot/ecosystem" +require "spec_helper" + +RSpec.describe Dependabot::Hex::PackageManager do + subject(:package_manager) { described_class.new(version) } + + let(:version) { "2.1.1" } + + describe "#version" do + it "returns the version" do + expect(package_manager.version).to eq(Dependabot::Hex::Version.new(version)) + end + end + + describe "#name" do + it "returns the name" do + expect(package_manager.name).to eq(Dependabot::Hex::PACKAGE_MANAGER) + end + end + + describe "#deprecated_versions" do + it "returns deprecated versions" do + expect(package_manager.deprecated_versions).to eq(Dependabot::Hex::DEPRECATED_HEX_VERSIONS) + end + end + + describe "#supported_versions" do + it "returns supported versions" do + expect(package_manager.supported_versions).to eq(Dependabot::Hex::SUPPORTED_HEX_VERSIONS) + end + end +end