Skip to content

Commit

Permalink
dotnet ecosystem metric collection
Browse files Browse the repository at this point in the history
  • Loading branch information
sachin-sandhu committed Dec 11, 2024
1 parent e1024fb commit 47fc3fb
Show file tree
Hide file tree
Showing 5 changed files with 305 additions and 0 deletions.
89 changes: 89 additions & 0 deletions nuget/lib/dependabot/nuget/file_parser.rb
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@
require "dependabot/nuget/discovery/discovery_json_reader"
require "dependabot/nuget/native_helpers"
require "sorbet-runtime"
require "dependabot/nuget/package_manager"
require "dependabot/nuget/language"

# For details on how dotnet handles version constraints, see:
# https://docs.microsoft.com/en-us/nuget/reference/package-versioning
Expand All @@ -22,8 +24,36 @@ def parse
dependencies
end

sig { returns(Ecosystem) }
def ecosystem
@ecosystem ||= T.let(
Ecosystem.new(
name: ECOSYSTEM,
package_manager: package_manager,
language: language
),
T.nilable(Ecosystem)
)
end

private

sig { returns(T.nilable(T::Array[T.nilable(String)])) }
def content_json
@content_json ||= T.let(begin
directory = source&.directory || "/"
discovery_json_reader = DiscoveryJsonReader.run_discovery_in_directory(
repo_contents_path: T.must(repo_contents_path),
directory: directory,
credentials: credentials
)

discovery_json_reader.workspace_discovery&.projects&.map do |framework|
T.let(framework.instance_variable_get(:@target_frameworks), T::Array[String]).first
end
end, T.nilable(T::Array[T.nilable(String)]))
end

sig { returns(T::Array[Dependabot::Dependency]) }
def dependencies
@dependencies ||= T.let(begin
Expand Down Expand Up @@ -53,6 +83,65 @@ def check_required_files
"No project file."
)
end

sig { returns(T.nilable(Ecosystem::VersionManager)) }
def language
# Historically new version of language is released with incremental update of
# .Net version, so we tie the language with framework version for metric collection

nomenclature = "#{language_type} #{framework_version&.first}".strip.tr(" ", "-")

Dependabot.logger.info("Detected language and framework #{nomenclature}")

case language_type

when CSharpLanguage::TYPE
CSharpLanguage.new(nomenclature)

when VBLanguage::TYPE
VBLanguage.new(nomenclature)

when FSharpLanguage::TYPE
FSharpLanguage.new(nomenclature)

when DotNet::TYPE
DotNet.new(nomenclature)

end
end

sig { returns(T.nilable(T::Array[T.nilable(String)])) }
def framework_version
content_json
rescue StandardError
nil
end

sig { returns(T.nilable(String)) }
def language_type
requirement_files = dependencies.flat_map do |dep|
dep.requirements.map { |r| T.let(r.fetch(:file), String) }
end.uniq

return "cs" if requirement_files.any? { |f| File.basename(f).match?(/\.csproj$/) }
return "vb" if requirement_files.any? { |f| File.basename(f).match?(/\.vbproj$/) }
return "fs" if requirement_files.any? { |f| File.basename(f).match?(/\.fsproj$/) }

# return a fallback to avoid falling to exception
"dotnet"
end

sig { returns(Ecosystem::VersionManager) }
def package_manager
NugetPackageManager.new(nuget_version)
end

sig { returns(T.nilable(String)) }
def nuget_version
SharedHelpers.run_shell_command("dotnet nuget --version").split("Command Line").last&.strip
rescue StandardError
nil
end
end
end
end
Expand Down
82 changes: 82 additions & 0 deletions nuget/lib/dependabot/nuget/language.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
# typed: strong
# frozen_string_literal: true

require "sorbet-runtime"
require "dependabot/nuget/version"
require "dependabot/ecosystem"

module Dependabot
module Nuget
class Language < Dependabot::Ecosystem::VersionManager
extend T::Sig

sig { params(language: String, raw_version: String, requirement: T.nilable(Requirement)).void }
def initialize(language, raw_version, requirement = nil)
super(language, Version.new(raw_version), [], [], requirement)
end
end

class CSharpLanguage < Dependabot::Ecosystem::VersionManager
extend T::Sig

LANGUAGE = "CSharp"
TYPE = "cs"

SUPPORTED_VERSIONS = T.let([].freeze, T::Array[Dependabot::Version])

DEPRECATED_VERSIONS = T.let([].freeze, T::Array[Dependabot::Version])

sig { params(language: String, requirement: T.nilable(Requirement)).void }
def initialize(language, requirement = nil)
super(language, Version.new(nil), [], [], requirement)
end
end

class VBLanguage < Dependabot::Ecosystem::VersionManager
extend T::Sig

LANGUAGE = "VB"
TYPE = "vb"

SUPPORTED_VERSIONS = T.let([].freeze, T::Array[Dependabot::Version])

DEPRECATED_VERSIONS = T.let([].freeze, T::Array[Dependabot::Version])

sig { params(language: String, requirement: T.nilable(Requirement)).void }
def initialize(language, requirement = nil)
super(language, Version.new(nil), [], [], requirement)
end
end

class FSharpLanguage < Dependabot::Ecosystem::VersionManager
extend T::Sig

LANGUAGE = "FSharp"
TYPE = "fs"

SUPPORTED_VERSIONS = T.let([].freeze, T::Array[Dependabot::Version])

DEPRECATED_VERSIONS = T.let([].freeze, T::Array[Dependabot::Version])

sig { params(language: String, requirement: T.nilable(Requirement)).void }
def initialize(language, requirement = nil)
super(language, Version.new(nil), [], [], requirement)
end
end

class DotNet < Dependabot::Ecosystem::VersionManager
extend T::Sig

TYPE = "dotnet"

SUPPORTED_VERSIONS = T.let([].freeze, T::Array[Dependabot::Version])

DEPRECATED_VERSIONS = T.let([].freeze, T::Array[Dependabot::Version])

sig { params(language: String, requirement: T.nilable(Requirement)).void }
def initialize(language, requirement = nil)
super(language, Version.new(nil), [], [], requirement)
end
end
end
end
51 changes: 51 additions & 0 deletions nuget/lib/dependabot/nuget/package_manager.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
# typed: strong
# frozen_string_literal: true

require "sorbet-runtime"
require "dependabot/nuget/version"
require "dependabot/ecosystem"
require "dependabot/nuget/requirement"

module Dependabot
module Nuget
ECOSYSTEM = "dotnet"

SUPPORTED_VERSIONS = T.let([].freeze, T::Array[Dependabot::Version])

DEPRECATED_VERSIONS = T.let([].freeze, T::Array[Dependabot::Version])

class NugetPackageManager < Dependabot::Ecosystem::VersionManager
extend T::Sig

NAME = "nuget"

SUPPORTED_VERSIONS = T.let([].freeze, T::Array[Dependabot::Version])

DEPRECATED_VERSIONS = T.let([].freeze, T::Array[Dependabot::Version])

sig do
params(
raw_version: T.nilable(String)
).void
end
def initialize(raw_version)
super(
NAME,
Version.new(raw_version),
SUPPORTED_VERSIONS,
DEPRECATED_VERSIONS
)
end

sig { override.returns(T::Boolean) }
def deprecated?
false
end

sig { override.returns(T::Boolean) }
def unsupported?
false
end
end
end
end
38 changes: 38 additions & 0 deletions nuget/spec/dependabot/nuget/language_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
# typed: false
# frozen_string_literal: true

require "dependabot/nuget/language"
require "dependabot/nuget/requirement"
require "dependabot/ecosystem"
require "spec_helper"

RSpec.describe Dependabot::Nuget::Language do
describe "#initialize" do
context "when version and requirement are both strings initially" do
let(:language) { Dependabot::Nuget::CSharpLanguage.new(name) }
let(:name) { "cs-dotnet472" }

it "sets the name correctly" do
expect(language.name).to eq("cs-dotnet472")
end
end

context "when version and requirement are both strings initially" do
let(:language) { Dependabot::Nuget::VBLanguage.new(name) }
let(:name) { "vb-net35" }

it "sets the name correctly" do
expect(language.name).to eq("vb-net35")
end
end

context "when version and requirement are both strings initially" do
let(:language) { Dependabot::Nuget::FSharpLanguage.new(name) }
let(:name) { "fs-netstandard1.5" }

it "sets the name correctly" do
expect(language.name).to eq("fs-netstandard1.5")
end
end
end
end
45 changes: 45 additions & 0 deletions nuget/spec/dependabot/nuget/nuget_package_manager_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
# typed: false
# frozen_string_literal: true

require "dependabot/nuget/package_manager"
require "dependabot/ecosystem"
require "spec_helper"

RSpec.describe Dependabot::Nuget::NugetPackageManager do
let(:package_manager) { described_class.new("6.5.0") }

describe "#initialize" do
context "when version is a String" do
it "sets the version correctly" do
expect(package_manager.version).to eq("6.5.0")
end

it "sets the name correctly" do
expect(package_manager.name).to eq("nuget")
end
end

describe "#deprecated_versions" do
it "returns deprecated versions" do
expect(package_manager.deprecated_versions).to eq(Dependabot::Nuget::NugetPackageManager::DEPRECATED_VERSIONS)
end
end

describe "#supported_versions" do
it "returns supported versions" do
expect(package_manager.supported_versions).to eq(Dependabot::Nuget::NugetPackageManager::SUPPORTED_VERSIONS)
end
end

context "when nuget version extracted is well formed" do
# If this test starts failing, you need to adjust the "nuget_version" function
# to return a valid version in format x.x, x.x.x etc. examples: 3.12.5, 3.12 along with
# following block
version = Dependabot::SharedHelpers.run_shell_command("dotnet nuget --version").split("Command Line").last&.strip

it "does not raise error" do
expect(version.match(/^\d+(?:\.\d+)*$/)).to be_truthy
end
end
end
end

0 comments on commit 47fc3fb

Please sign in to comment.