From dd839ba3614d3b8f4266640adacf4b6ce417c611 Mon Sep 17 00:00:00 2001 From: Joey Robichaud Date: Thu, 18 Apr 2024 00:30:44 -0700 Subject: [PATCH] Progress on ruby tests --- .../Analyze/VersionFinderTests.cs | 35 +- .../Analyze/AnalyzeWorker.cs | 35 +- .../Analyze/VersionFinder.cs | 16 +- .../nuget/analysis/analysis_json_reader.rb | 29 +- .../nuget/analysis/dependency_analysis.rb | 61 ++ nuget/lib/dependabot/nuget/update_checker.rb | 67 +- .../compatibility_checker_spec.rb | 259 ----- .../update_checker/dependency_finder_spec.rb | 98 -- .../update_checker/nupkg_fetcher_spec.rb | 257 ----- .../update_checker/nuspec_fetcher_spec.rb | 55 - .../update_checker/repository_finder_spec.rb | 988 ------------------ .../nuget/update_checker/tfm_finder_spec.rb | 56 - .../update_checker/version_finder_spec.rb | 695 ------------ .../dependabot/nuget/update_checker_spec.rb | 15 + 14 files changed, 195 insertions(+), 2471 deletions(-) delete mode 100644 nuget/spec/dependabot/nuget/update_checker/compatibility_checker_spec.rb delete mode 100644 nuget/spec/dependabot/nuget/update_checker/dependency_finder_spec.rb delete mode 100644 nuget/spec/dependabot/nuget/update_checker/nupkg_fetcher_spec.rb delete mode 100644 nuget/spec/dependabot/nuget/update_checker/nuspec_fetcher_spec.rb delete mode 100644 nuget/spec/dependabot/nuget/update_checker/repository_finder_spec.rb delete mode 100644 nuget/spec/dependabot/nuget/update_checker/tfm_finder_spec.rb delete mode 100644 nuget/spec/dependabot/nuget/update_checker/version_finder_spec.rb diff --git a/nuget/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Analyze/VersionFinderTests.cs b/nuget/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Analyze/VersionFinderTests.cs index 5f1ec347ac3..a1617961929 100644 --- a/nuget/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Analyze/VersionFinderTests.cs +++ b/nuget/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Analyze/VersionFinderTests.cs @@ -19,7 +19,7 @@ public void VersionFilter_VersionInIgnoredVersions_ReturnsFalse() IgnoredVersions = [Requirement.Parse("< 1.0.0")], Vulnerabilities = [], }; - var filter = VersionFinder.CreateVersionFilter(dependencyInfo, NuGetVersion.Parse(dependencyInfo.Version)); + var filter = VersionFinder.CreateVersionFilter(dependencyInfo, VersionRange.Parse(dependencyInfo.Version)); var version = NuGetVersion.Parse("0.9.0"); var result = filter(version); @@ -38,7 +38,7 @@ public void VersionFilter_VersionNotInIgnoredVersions_ReturnsTrue() IgnoredVersions = [Requirement.Parse("< 1.0.0")], Vulnerabilities = [], }; - var filter = VersionFinder.CreateVersionFilter(dependencyInfo, NuGetVersion.Parse(dependencyInfo.Version)); + var filter = VersionFinder.CreateVersionFilter(dependencyInfo, VersionRange.Parse(dependencyInfo.Version)); var version = NuGetVersion.Parse("1.0.1"); var result = filter(version); @@ -63,7 +63,7 @@ public void VersionFilter_VersionInVulnerabilities_ReturnsFalse() VulnerableVersions = [Requirement.Parse("< 1.0.0")], }], }; - var filter = VersionFinder.CreateVersionFilter(dependencyInfo, NuGetVersion.Parse(dependencyInfo.Version)); + var filter = VersionFinder.CreateVersionFilter(dependencyInfo, VersionRange.Parse(dependencyInfo.Version)); var version = NuGetVersion.Parse("0.9.0"); var result = filter(version); @@ -88,7 +88,7 @@ public void VersionFilter_VersionNotInVulnerabilities_ReturnsTrue() VulnerableVersions = [Requirement.Parse("< 1.0.0")], }], }; - var filter = VersionFinder.CreateVersionFilter(dependencyInfo, NuGetVersion.Parse(dependencyInfo.Version)); + var filter = VersionFinder.CreateVersionFilter(dependencyInfo, VersionRange.Parse(dependencyInfo.Version)); var version = NuGetVersion.Parse("1.0.1"); var result = filter(version); @@ -107,7 +107,7 @@ public void VersionFilter_VersionLessThanCurrentVersion_ReturnsFalse() IgnoredVersions = [], Vulnerabilities = [], }; - var filter = VersionFinder.CreateVersionFilter(dependencyInfo, NuGetVersion.Parse(dependencyInfo.Version)); + var filter = VersionFinder.CreateVersionFilter(dependencyInfo, VersionRange.Parse(dependencyInfo.Version)); var version = NuGetVersion.Parse("0.9.0"); var result = filter(version); @@ -126,7 +126,7 @@ public void VersionFilter_VersionHigherThanCurrentVersion_ReturnsTrue() IgnoredVersions = [], Vulnerabilities = [], }; - var filter = VersionFinder.CreateVersionFilter(dependencyInfo, NuGetVersion.Parse(dependencyInfo.Version)); + var filter = VersionFinder.CreateVersionFilter(dependencyInfo, VersionRange.Parse(dependencyInfo.Version)); var version = NuGetVersion.Parse("1.0.1"); var result = filter(version); @@ -145,7 +145,7 @@ public void VersionFilter_PreviewVersionDifferentThanCurrentVersion_ReturnsFalse IgnoredVersions = [], Vulnerabilities = [], }; - var filter = VersionFinder.CreateVersionFilter(dependencyInfo, NuGetVersion.Parse(dependencyInfo.Version)); + var filter = VersionFinder.CreateVersionFilter(dependencyInfo, VersionRange.Parse(dependencyInfo.Version)); var version = NuGetVersion.Parse("1.0.1-beta"); var result = filter(version); @@ -164,7 +164,26 @@ public void VersionFilter_PreviewVersionSameAsCurrentVersion_ReturnsTrue() IgnoredVersions = [], Vulnerabilities = [], }; - var filter = VersionFinder.CreateVersionFilter(dependencyInfo, NuGetVersion.Parse(dependencyInfo.Version)); + var filter = VersionFinder.CreateVersionFilter(dependencyInfo, VersionRange.Parse(dependencyInfo.Version)); + var version = NuGetVersion.Parse("1.0.0-beta"); + + var result = filter(version); + + Assert.True(result); + } + + [Fact] + public void VersionFilter_WildcardPreviewVersion_ReturnsTrue() + { + var dependencyInfo = new DependencyInfo + { + Name = "Dependency", + Version = "*-*", + IsVulnerable = false, + IgnoredVersions = [], + Vulnerabilities = [], + }; + var filter = VersionFinder.CreateVersionFilter(dependencyInfo, VersionRange.Parse(dependencyInfo.Version)); var version = NuGetVersion.Parse("1.0.0-beta"); var result = filter(version); diff --git a/nuget/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Analyze/AnalyzeWorker.cs b/nuget/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Analyze/AnalyzeWorker.cs index 110bbfa34f3..ce1884e52a5 100644 --- a/nuget/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Analyze/AnalyzeWorker.cs +++ b/nuget/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Analyze/AnalyzeWorker.cs @@ -103,8 +103,6 @@ internal static async Task DeserializeJsonFileAsync(string path, string fi Directory.CreateDirectory(nugetContext.TempPackageDirectory); } - var currentVersion = NuGetVersion.Parse(dependencyInfo.Version); - var versionResult = await VersionFinder.GetVersionsAsync( dependencyInfo, nugetContext, @@ -116,7 +114,7 @@ internal static async Task DeserializeJsonFileAsync(string path, string fi return await FindFirstCompatibleVersion( dependencyInfo.Name, - currentVersion, + dependencyInfo.Version, versionResult, orderedVersions, projectFrameworks, @@ -127,7 +125,7 @@ internal static async Task DeserializeJsonFileAsync(string path, string fi internal static async Task FindFirstCompatibleVersion( string packageId, - NuGetVersion currentVersion, + string versionString, VersionResult versionResult, IEnumerable orderedVersions, ImmutableArray projectFrameworks, @@ -135,24 +133,27 @@ internal static async Task DeserializeJsonFileAsync(string path, string fi Logger logger, CancellationToken cancellationToken) { - var source = versionResult.GetPackageSources(currentVersion).First(); - var isCompatible = await CompatibilityChecker.CheckAsync( - source, - new(packageId, currentVersion), - projectFrameworks, - nugetContext, - logger, - cancellationToken); - if (!isCompatible) + if (NuGetVersion.TryParse(versionString, out var currentVersion)) { - // If the current package is incompatible, then don't check for compatibility. - return orderedVersions.First(); + var source = versionResult.GetPackageSources(currentVersion).First(); + var isCompatible = await CompatibilityChecker.CheckAsync( + source, + new(packageId, currentVersion), + projectFrameworks, + nugetContext, + logger, + cancellationToken); + if (!isCompatible) + { + // If the current package is incompatible, then don't check for compatibility. + return orderedVersions.First(); + } } foreach (var version in orderedVersions) { - source = versionResult.GetPackageSources(version).First(); - isCompatible = await CompatibilityChecker.CheckAsync( + var source = versionResult.GetPackageSources(version).First(); + var isCompatible = await CompatibilityChecker.CheckAsync( source, new(packageId, version), projectFrameworks, diff --git a/nuget/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Analyze/VersionFinder.cs b/nuget/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Analyze/VersionFinder.cs index 52250c8decc..80ee82d4ce5 100644 --- a/nuget/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Analyze/VersionFinder.cs +++ b/nuget/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Analyze/VersionFinder.cs @@ -16,10 +16,11 @@ internal static class VersionFinder CancellationToken cancellationToken) { var packageId = dependencyInfo.Name; - var currentVersion = NuGetVersion.Parse(dependencyInfo.Version); + var versionRange = VersionRange.Parse(dependencyInfo.Version); + var currentVersion = versionRange.MinVersion!; var includePrerelease = currentVersion.IsPrerelease; - var versionFilter = CreateVersionFilter(dependencyInfo, currentVersion); + var versionFilter = CreateVersionFilter(dependencyInfo, versionRange); VersionResult result = new(currentVersion); var sourceMapping = PackageSourceMapping.GetPackageSourceMapping(nugetContext.Settings); @@ -71,10 +72,15 @@ internal static class VersionFinder return result; } - internal static Func CreateVersionFilter(DependencyInfo dependencyInfo, NuGetVersion currentVersion) + internal static Func CreateVersionFilter(DependencyInfo dependencyInfo, VersionRange versionRange) { - return version => version > currentVersion - && (!currentVersion.IsPrerelease || !version.IsPrerelease || version.Version == currentVersion.Version) + // If we are floating to the aboslute latest version, we should not filter pre-release versions at all. + var currentVersion = versionRange.Float?.FloatBehavior != NuGetVersionFloatBehavior.AbsoluteLatest + ? versionRange.MinVersion + : null; + + return version => versionRange.Satisfies(version) + && (currentVersion is null || !currentVersion.IsPrerelease || !version.IsPrerelease || version.Version == currentVersion.Version) && !dependencyInfo.IgnoredVersions.Any(r => r.IsSatisfiedBy(version)) && !dependencyInfo.Vulnerabilities.Any(v => v.IsVulnerable(version)); } diff --git a/nuget/lib/dependabot/nuget/analysis/analysis_json_reader.rb b/nuget/lib/dependabot/nuget/analysis/analysis_json_reader.rb index 044b33a9dfb..77413c3cc7c 100644 --- a/nuget/lib/dependabot/nuget/analysis/analysis_json_reader.rb +++ b/nuget/lib/dependabot/nuget/analysis/analysis_json_reader.rb @@ -39,25 +39,24 @@ def initialize(analysis_json:) @analysis_json = analysis_json end - sig { returns(Dependabot::Nuget::Version) } - def updated_version - Version.new("1.0.0") - end + sig { returns(DependencyAnalysis) } + def dependency_analysis + @dependency_analysis ||= T.let(begin + raise Dependabot::DependencyFileNotParseable, analysis_json.path unless analysis_json.content - sig { returns(T::Boolean) } - def can_update? - true - end + Dependabot.logger.info("#{File.basename(analysis_json.path)} analysis content: #{analysis_json.content}") - sig { returns(T::Boolean) } - def version_comes_from_multi_dependency_property? - false + parsed_json = T.let(JSON.parse(T.must(analysis_json.content)), T::Hash[String, T.untyped]) + DependencyAnalysis.from_json(parsed_json) + end, T.nilable(DependencyAnalysis)) + rescue JSON::ParserError + raise Dependabot::DependencyFileNotParseable, analysis_json.path end - sig { returns(T::Array[Dependabot::Dependency]) } - def updated_dependencies - [] - end + private + + sig { returns(DependencyFile) } + attr_reader :analysis_json end end end diff --git a/nuget/lib/dependabot/nuget/analysis/dependency_analysis.rb b/nuget/lib/dependabot/nuget/analysis/dependency_analysis.rb index e69de29bb2d..759af5f270a 100644 --- a/nuget/lib/dependabot/nuget/analysis/dependency_analysis.rb +++ b/nuget/lib/dependabot/nuget/analysis/dependency_analysis.rb @@ -0,0 +1,61 @@ +# typed: strong +# frozen_string_literal: true + +require "dependabot/nuget/version" +require "sorbet-runtime" + +module Dependabot + module Nuget + class DependencyAnalysis + extend T::Sig + + sig { params(json: T::Hash[String, T.untyped]).returns(DependencyAnalysis) } + def self.from_json(json) + updated_version = T.let(json.fetch("UpdatedVersion"), String) + can_update = T.let(json.fetch("CanUpdate"), T::Boolean) + version_comes_from_multi_dependency_property = T.let(json.fetch("VersionComesFromMultiDependencyProperty"), + T::Boolean) + updated_dependencies = T.let(json.fetch("UpdatedDependencies"), + T::Array[T::Hash[String, T.untyped]]).map do |dep| + DependencyDetails.from_json(dep) + end + + DependencyAnalysis.new(updated_version: updated_version, + can_update: can_update, + version_comes_from_multi_dependency_property: version_comes_from_multi_dependency_property, + updated_dependencies: updated_dependencies) + end + + sig do + params(updated_version: String, + can_update: T::Boolean, + version_comes_from_multi_dependency_property: T::Boolean, + updated_dependencies: T::Array[DependencyDetails]).void + end + def initialize(updated_version:, can_update:, version_comes_from_multi_dependency_property:, + updated_dependencies:) + @updated_version = updated_version + @can_update = can_update + @version_comes_from_multi_dependency_property = version_comes_from_multi_dependency_property + @updated_dependencies = updated_dependencies + end + + sig { returns(String) } + attr_reader :updated_version + + sig { returns(T::Boolean) } + attr_reader :can_update + + sig { returns(T::Boolean) } + attr_reader :version_comes_from_multi_dependency_property + + sig { returns(T::Array[DependencyDetails]) } + attr_reader :updated_dependencies + + sig { returns(Dependabot::Nuget::Version) } + def numeric_updated_version + @numeric_updated_version ||= T.let(Version.new(updated_version), T.nilable(Dependabot::Nuget::Version)) + end + end + end +end diff --git a/nuget/lib/dependabot/nuget/update_checker.rb b/nuget/lib/dependabot/nuget/update_checker.rb index 847e9a066b6..5269aaaf839 100644 --- a/nuget/lib/dependabot/nuget/update_checker.rb +++ b/nuget/lib/dependabot/nuget/update_checker.rb @@ -21,7 +21,7 @@ def latest_version # if no update sources have the requisite package, then we can only assume that the current version is correct @latest_version = T.let( - update_analysis.updated_version.to_s, + update_analysis.dependency_analysis.updated_version, T.nilable(String) ) end @@ -35,14 +35,14 @@ def latest_resolvable_version sig { override.returns(Dependabot::Nuget::Version) } def lowest_security_fix_version - update_analysis.updated_version + update_analysis.dependency_analysis.numeric_updated_version end sig { override.returns(T.nilable(Dependabot::Version)) } def lowest_resolvable_security_fix_version return nil if version_comes_from_multi_dependency_property? - update_analysis.updated_version + update_analysis.dependency_analysis.numeric_updated_version end sig { override.returns(NilClass) } @@ -55,18 +55,18 @@ def latest_resolvable_version_with_no_unlock def updated_requirements RequirementsUpdater.new( requirements: dependency.requirements, - latest_version: update_analysis.updated_version.to_s + latest_version: update_analysis.dependency_analysis.updated_version ).updated_requirements end sig { returns(T::Boolean) } def up_to_date? - !update_analysis.can_update? + !update_analysis.dependency_analysis.can_update end sig { returns(T::Boolean) } def requirements_unlocked_or_can_be? - update_analysis.can_update? + update_analysis.dependency_analysis.can_update end private @@ -86,13 +86,25 @@ def request_analysis discovery_file_path = DiscoveryJsonReader.discovery_file_path analysis_folder_path = AnalysisJsonReader.temp_directory + write_dependency_info + + NativeHelpers.run_nuget_analyze_tool(discovery_file_path: discovery_file_path, + dependency_file_path: dependency_file_path, + analysis_folder_path: analysis_folder_path, + credentials: credentials) + + analysis_json = AnalysisJsonReader.analysis_json(dependency_name: dependency.name) + + AnalysisJsonReader.new(analysis_json: T.must(analysis_json)) + end + + sig { void } + def write_dependency_info dependency_info = { Name: dependency.name, Version: dependency.version.to_s, IsVulnerable: vulnerable?, - IgnoredVersions: ignored_versions.map do |i| - i == ">= 0" ? "*" : i - end, + IgnoredVersions: ignored_versions, Vulnerabilities: security_advisories.map do |vulnerability| { DependencyName: vulnerability.dependency_name, @@ -103,15 +115,16 @@ def request_analysis end }.to_json File.write(dependency_file_path, dependency_info) + end - NativeHelpers.run_nuget_analyze_tool(discovery_file_path: discovery_file_path, - dependency_file_path: dependency_file_path, - analysis_folder_path: analysis_folder_path, - credentials: credentials) - - analysis_json = AnalysisJsonReader.analysis_json(dependency_name: dependency.name) + sig { returns(Dependabot::FileParsers::Base::DependencySet) } + def discovered_dependencies + discovery_json = DiscoveryJsonReader.discovery_json + return Dependabot::FileParsers::Base::DependencySet.new unless discovery_json - AnalysisJsonReader.new(analysis_json: T.must(analysis_json)) + DiscoveryJsonReader.new( + discovery_json: discovery_json + ).dependency_set end sig { override.returns(T::Boolean) } @@ -122,12 +135,30 @@ def latest_version_resolvable_with_full_unlock? sig { override.returns(T::Array[Dependabot::Dependency]) } def updated_dependencies_after_full_unlock - update_analysis.updated_dependencies + dependencies = discovered_dependencies.dependencies + update_analysis.dependency_analysis.updated_dependencies.filter_map do |dependency_details| + dep = dependencies.find { |d| d.name.casecmp(dependency_details.name)&.zero? } + next unless dep + + metadata = {} + # For peer dependencies, instruct updater to not directly update this dependency + metadata = { information_only: true } unless dependency.name.casecmp(dependency_details.name)&.zero? + + Dependency.new( + name: dep.name, + version: dependency_details.version, + requirements: dep.requirements, + previous_version: dep.version, + previous_requirements: dep.requirements, + package_manager: dep.package_manager, + metadata: metadata + ) + end end sig { returns(T::Boolean) } def version_comes_from_multi_dependency_property? - update_analysis.version_comes_from_multi_dependency_property? + update_analysis.dependency_analysis.version_comes_from_multi_dependency_property end end end diff --git a/nuget/spec/dependabot/nuget/update_checker/compatibility_checker_spec.rb b/nuget/spec/dependabot/nuget/update_checker/compatibility_checker_spec.rb deleted file mode 100644 index 55d5ac05e42..00000000000 --- a/nuget/spec/dependabot/nuget/update_checker/compatibility_checker_spec.rb +++ /dev/null @@ -1,259 +0,0 @@ -# typed: false -# frozen_string_literal: true - -require "spec_helper" -require "dependabot/dependency" -require "dependabot/nuget/file_parser" -require "dependabot/nuget/update_checker/compatibility_checker" -require "dependabot/nuget/update_checker/repository_finder" -require "dependabot/nuget/update_checker/tfm_finder" - -RSpec.describe Dependabot::Nuget::CompatibilityChecker do - subject(:checker) do - Dependabot::Nuget::FileParser.new(dependency_files: dependency_files, - source: source, - repo_contents_path: repo_contents_path).parse - described_class.new( - dependency_urls: dependency_urls, - dependency: dependency - ) - end - let(:repo_contents_path) { write_tmp_repo(dependency_files) } - let(:source) do - Dependabot::Source.new( - provider: "github", - repo: "gocardless/bump", - directory: "/" - ) - end - let(:dependency_urls) do - Dependabot::Nuget::RepositoryFinder.new( - dependency: dependency, - credentials: credentials, - config_files: [] - ).dependency_urls - end - - let(:credentials) do - [{ - "type" => "nuget_feed", - "url" => "https://api.nuget.org/v3/index.json", - "token" => "my:passw0rd" - }] - end - - let(:dependency) do - Dependabot::Dependency.new( - name: dependency_name, - version: dependency_version, - requirements: dependency_requirements, - package_manager: "nuget" - ) - end - - let(:dependency_name) { "Microsoft.AppCenter.Crashes" } - let(:dependency_version) { "5.0.2" } - let(:dependency_requirements) do - [{ file: "my.csproj", requirement: "5.0.2", groups: ["dependencies"], source: nil }] - end - - let(:dependency_files) { [csproj] } - let(:csproj) do - Dependabot::DependencyFile.new(name: "my.csproj", content: csproj_body) - end - let(:csproj_body) do - <<~XML - - - uap10.0.16299 - - - - - - XML - end - - context "#compatible?" do - subject(:compatible) { checker.compatible?(version) } - - before do - stub_request(:get, "https://api.nuget.org/v3/registration5-gz-semver2/microsoft.appcenter.crashes/index.json") - .to_return( - status: 200, - body: { - items: [ - items: [ - { - catalogEntry: { - listed: true, - version: "5.0.2" - } - }, - { - catalogEntry: { - listed: true, - version: "5.0.3" - } - } - ] - ] - }.to_json - ) - end - - context "when the `.nuspec` reports itself as a development dependency, but still has regular dependencies" do - let(:csproj_body) do - <<~XML - - - net6.0 - - - - - - XML - end - - before do - nuspec502 = - <<~XML - - - Microsoft.AppCenter.Crashes - 5.0.2 - true - - - - - - - XML - nuspec503 = nuspec502.gsub("5.0.2", "5.0.3") - nuspec601 = nuspec502.gsub("5.0.2", "6.0.1").gsub("net6.0", "net8.0") - stub_request(:get, "https://api.nuget.org/v3-flatcontainer/microsoft.appcenter.crashes/5.0.2/microsoft.appcenter.crashes.nuspec") - .to_return( - status: 200, - body: nuspec502 - ) - stub_request(:get, "https://api.nuget.org/v3-flatcontainer/microsoft.appcenter.crashes/5.0.3/microsoft.appcenter.crashes.nuspec") - .to_return( - status: 200, - body: nuspec503 - ) - stub_request(:get, "https://api.nuget.org/v3-flatcontainer/microsoft.appcenter.crashes/6.0.1/microsoft.appcenter.crashes.nuspec") - .to_return( - status: 200, - body: nuspec601 - ) - end - - context "with a targetFramework compatible version" do - let(:version) { "5.0.3" } - - it "returns the correct data" do - expect(compatible).to be_truthy - end - end - - context "with a targetFramework non-compatible version" do - let(:version) { "6.0.1" } - - it "returns the correct data" do - expect(compatible).to be_falsey - end - end - end - - context "when the `.nuspec` has groups without a `targetFramework` attribute" do - let(:version) { "5.0.3" } - - before do - stub_request(:get, "https://api.nuget.org/v3-flatcontainer/microsoft.appcenter.crashes/5.0.2/microsoft.appcenter.crashes.nuspec") - .to_return( - status: 200, - body: fixture("nuspecs", "Microsoft.AppCenter.Crashes_faked.nuspec") - ) - stub_request(:get, "https://api.nuget.org/v3-flatcontainer/microsoft.appcenter.crashes/5.0.3/microsoft.appcenter.crashes.nuspec") - .to_return( - status: 200, - body: fixture("nuspecs", "Microsoft.AppCenter.Crashes_faked.nuspec") - ) - end - - it "returns the correct data" do - expect(compatible).to be_truthy - end - end - - context "when the `.nupkg` zip object contains an empty `lib/` entry" do - def create_nupkg_with_lib_contents(package_name, nuspec_contents, lib_subdirectories) - content = Zip::OutputStream.write_buffer do |zio| - zio.put_next_entry("#{package_name}.nuspec") - zio.write(nuspec_contents) - - zio.put_next_entry("lib/") # some zip files have an empty directory object entry - - lib_subdirectories.each do |lib| - zio.put_next_entry("lib/#{lib}/_._") - zio.write("fake contents") - end - end - content.rewind - content.sysread - end - - let(:csproj_body) do - <<~XML - - - net481 - - - - - - XML - end - - before do - nuspec_xml = - <<~XML - - - Microsoft.AppCenter.Crashes - 5.0.2 - - - - - - - XML - stub_request(:get, "https://api.nuget.org/v3-flatcontainer/microsoft.appcenter.crashes/5.0.2/microsoft.appcenter.crashes.nuspec") - .to_return( - status: 200, - body: nuspec_xml - ) - stub_request(:get, "https://api.nuget.org/v3-flatcontainer/microsoft.appcenter.crashes/5.0.2/microsoft.appcenter.crashes.5.0.2.nupkg") - .to_return( - status: 200, - body: create_nupkg_with_lib_contents(dependency_name, nuspec_xml, ["net45"]) - ) - end - - context "checks the `.nupkg` contents" do - let(:version) { "5.0.2" } - - it "returns the correct data" do - expect(compatible).to be_truthy - end - end - end - end -end diff --git a/nuget/spec/dependabot/nuget/update_checker/dependency_finder_spec.rb b/nuget/spec/dependabot/nuget/update_checker/dependency_finder_spec.rb deleted file mode 100644 index ba0431fcd5e..00000000000 --- a/nuget/spec/dependabot/nuget/update_checker/dependency_finder_spec.rb +++ /dev/null @@ -1,98 +0,0 @@ -# typed: false -# frozen_string_literal: true - -require "spec_helper" -require "dependabot/dependency" -require "dependabot/dependency_file" -require "dependabot/nuget/update_checker/dependency_finder" - -RSpec.describe Dependabot::Nuget::UpdateChecker::DependencyFinder do - subject(:finder) do - described_class.new( - dependency: dependency, - dependency_files: dependency_files, - credentials: credentials, - repo_contents_path: "test/repo" - ) - end - let(:dependency) do - Dependabot::Dependency.new( - name: dependency_name, - version: dependency_version, - requirements: dependency_requirements, - package_manager: "nuget" - ) - end - - let(:dependency_requirements) do - [{ file: "my.csproj", requirement: "1.1.1", groups: ["dependencies"], source: nil }] - end - let(:dependency_name) { "Microsoft.Extensions.DependencyModel" } - let(:dependency_version) { "1.1.1" } - - let(:dependency_files) { [csproj] } - let(:csproj) do - Dependabot::DependencyFile.new(name: "my.csproj", content: csproj_body) - end - let(:csproj_body) { fixture("csproj", "basic.csproj") } - - let(:credentials) do - [{ - "type" => "git_source", - "host" => "github.com", - "username" => "x-access-token", - "password" => "token" - }] - end - - # Can get transitive dependencies - describe "#transitive_dependencies", :vcr do - subject(:transitive_dependencies) { finder.transitive_dependencies } - - its(:length) { is_expected.to eq(34) } - end - - context "api.nuget.org is not hit if it's not in the NuGet.Config" do - let(:dependency_version) { "42.42.42" } - let(:nuget_config_body) { fixture("configs", "example.com_nuget.config") } - let(:nuget_config) { Dependabot::DependencyFile.new(name: "NuGet.Config", content: nuget_config_body) } - let(:dependency_files) { [csproj, nuget_config] } - subject(:transitive_dependencies) { finder.transitive_dependencies } - - def create_nupkg(nuspec_name, nuspec_fixture_path) - content = Zip::OutputStream.write_buffer do |zio| - zio.put_next_entry("#{nuspec_name}.nuspec") - zio.write(fixture("nuspecs", nuspec_fixture_path)) - end - content.rewind - content.sysread - end - - before(:context) do - disallowed_urls = %w( - https://api.nuget.org/v3/index.json - https://api.nuget.org/v3-flatcontainer/microsoft.extensions.dependencymodel/42.42.42/microsoft.extensions.dependencymodel.nuspec - https://api.nuget.org/v3-flatcontainer/microsoft.netcore.platforms/43.43.43/microsoft.netcore.platforms.nuspec - ) - - disallowed_urls.each do |url| - stub_request(:get, url) - .to_raise(StandardError.new("Not allowed to query `#{url}`")) - end - - stub_request(:get, "https://nuget.example.com/v3/index.json") - .to_return(status: 200, body: fixture("nuget_responses", "example_index.json")) - stub_request(:get, "https://api.example.com/v3-flatcontainer/microsoft.extensions.dependencymodel/42.42.42/microsoft.extensions.dependencymodel.42.42.42.nupkg") - .to_return(status: 200, body: create_nupkg("Microsoft.Extensions.DependencyModel", - "Microsoft.Extensions.DependencyModel_42.42.42_faked.nuspec")) - stub_request(:get, "https://api.example.com/v3-flatcontainer/microsoft.netcore.platforms/43.43.43/microsoft.netcore.platforms.43.43.43.nupkg") - .to_return(status: 200, body: create_nupkg("Microsoft.NETCore.Platforms", - "Microsoft.NETCore.Platforms_43.43.43_faked.nuspec")) - end - - # this test doesn't really care about the dependency count, we just need to ensure that `api.nuget.org` wasn't hit - its(:length) do - is_expected.to eq(1) - end - end -end diff --git a/nuget/spec/dependabot/nuget/update_checker/nupkg_fetcher_spec.rb b/nuget/spec/dependabot/nuget/update_checker/nupkg_fetcher_spec.rb deleted file mode 100644 index 52c86eba852..00000000000 --- a/nuget/spec/dependabot/nuget/update_checker/nupkg_fetcher_spec.rb +++ /dev/null @@ -1,257 +0,0 @@ -# typed: false -# frozen_string_literal: true - -require "spec_helper" -require "dependabot/dependency" -require "dependabot/dependency_file" -require "dependabot/nuget/update_checker/nupkg_fetcher" -require "dependabot/nuget/update_checker/repository_finder" - -RSpec.describe Dependabot::Nuget::NupkgFetcher do - describe "#fetch_nupkg_url_from_repository" do - let(:dependency) { Dependabot::Dependency.new(name: package_name, requirements: [], package_manager: "nuget") } - let(:package_name) { "Newtonsoft.Json" } - let(:package_version) { "13.0.1" } - let(:credentials) { [] } - let(:config_files) { [nuget_config] } - let(:nuget_config) do - Dependabot::DependencyFile.new( - name: "NuGet.config", - content: nuget_config_content - ) - end - let(:nuget_config_content) do - <<~XML - - - - - - - - XML - end - let(:repository_finder) do - Dependabot::Nuget::RepositoryFinder.new(dependency: dependency, credentials: credentials, - config_files: config_files) - end - let(:repository_details) { repository_finder.dependency_urls.first } - subject(:nupkg_url) do - described_class.fetch_nupkg_url_from_repository(repository_details, package_name, package_version) - end - - context "with a nuget feed url" do - let(:feed_url) { "https://api.nuget.org/v3/index.json" } - - before do - stub_request(:get, feed_url) - .to_return( - status: 200, - body: fixture("nuget_responses", "index.json", "nuget.index.json") - ) - end - - it { is_expected.to eq("https://api.nuget.org/v3-flatcontainer/newtonsoft.json/13.0.1/newtonsoft.json.13.0.1.nupkg") } - end - - context "with an azure feed url" do - let(:feed_url) { "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public/nuget/v3/index.json" } - - before do - stub_request(:get, feed_url) - .to_return( - status: 200, - body: fixture("nuget_responses", "index.json", "dotnet-public.index.json") - ) - end - - it { is_expected.to eq("https://pkgs.dev.azure.com/dnceng/9ee6d478-d288-47f7-aacc-f6e6d082ae6d/_packaging/45bacae2-5efb-47c8-91e5-8ec20c22b4f8/nuget/v3/flat2/newtonsoft.json/13.0.1/newtonsoft.json.13.0.1.nupkg") } - end - - context "with a github feed url" do - let(:feed_url) { "https://nuget.pkg.github.com/some-namespace/index.json" } - - before do - stub_request(:get, feed_url) - .to_return( - status: 200, - body: fixture("nuget_responses", "index.json", "github.index.json") - ) - end - - it { is_expected.to eq("https://nuget.pkg.github.com/some-namespace/download/newtonsoft.json/13.0.1/newtonsoft.json.13.0.1.nupkg") } - end - - context "with a v2 feed url" do - let(:feed_url) { "https://www.nuget.org/api/v2" } - - before do - stub_request(:get, feed_url) - .to_return( - status: 200, - body: - +<<~XML - - - - Packages - - - - XML - ) - stub_request(:get, "https://www.nuget.org/api/v2/Packages(Id='Newtonsoft.Json',Version='13.0.1')") - .to_return( - status: 200, - body: - <<~XML - - - - - XML - ) - end - - it { is_expected.to eq("https://www.nuget.org/api/v2/Download/Newtonsoft.Json/13.0.1") } - end - - context "from a v3 feed that doesn't specify `PackageBaseAddress`" do - let(:feed_url) { "https://nuget.example.com/v3-without-package-base/index.json" } - - before do - # initial `index.json` response; only provides `SearchQueryService` and not `PackageBaseAddress` - stub_request(:get, feed_url) - .to_return( - status: 200, - body: { - version: "3.0.0", - resources: [ - { - "@id" => "https://nuget.example.com/query", - "@type" => "SearchQueryService" - } - ] - }.to_json - ) - # SearchQueryService - stub_request(:get, "https://nuget.example.com/query?q=newtonsoft.json&prerelease=true&semVerLevel=2.0.0") - .to_return( - status: 200, - body: { - totalHits: 2, - data: [ - # this is a false match - { - registration: "not-used", - version: "42.42.42", - versions: [ - { - version: "1.0.0", - "@id" => "not-used" - }, - { - version: "42.42.42", - "@id" => "not-used" - } - ], - id: "Newtonsoft.Json.False.Match" - }, - # this is the real one - { - registration: "not-used", - version: "13.0.1", - versions: [ - { - version: "12.0.1", - "@id" => "https://nuget.example.com/registration/newtonsoft.json/12.0.1.json" - }, - { - version: "13.0.1", - "@id" => "https://nuget.example.com/registration/newtonsoft.json/13.0.1.json" - } - ], - id: "Newtonsoft.Json" - } - ] - }.to_json - ) - # registration content - stub_request(:get, "https://nuget.example.com/registration/newtonsoft.json/13.0.1.json") - .to_return( - status: 200, - body: { - listed: true, - packageContent: "https://nuget.example.com/nuget-local/Download/newtonsoft.json.13.0.1.nupkg", - registration: "not-used", - "@id" => "not-used" - }.to_json - ) - end - - it { is_expected.to eq("https://nuget.example.com/nuget-local/Download/newtonsoft.json.13.0.1.nupkg") } - end - end - - describe "#fetch_nupkg_buffer" do - let(:package_id) { "Newtonsoft.Json" } - let(:package_version) { "13.0.1" } - let(:repository_details) { Dependabot::Nuget::RepositoryFinder.get_default_repository_details(package_id) } - let(:dependency_urls) { [repository_details] } - subject(:nupkg_buffer) do - described_class.fetch_nupkg_buffer(dependency_urls, package_id, package_version) - end - - before do - stub_request(:get, "https://api.nuget.org/v3-flatcontainer/newtonsoft.json/13.0.1/newtonsoft.json.13.0.1.nupkg") - .to_return( - status: 301, - headers: { - "Location" => "https://api.nuget.org/redirect-on-301" - }, - body: "redirecting on 301" - ) - stub_request(:get, "https://api.nuget.org/redirect-on-301") - .to_return( - status: 302, - headers: { - "Location" => "https://api.nuget.org/redirect-on-302" - }, - body: "redirecting on 302" - ) - stub_request(:get, "https://api.nuget.org/redirect-on-302") - .to_return( - status: 303, - headers: { - "Location" => "https://api.nuget.org/redirect-on-303" - }, - body: "redirecting on 303" - ) - stub_request(:get, "https://api.nuget.org/redirect-on-303") - .to_return( - status: 307, - headers: { - "Location" => "https://api.nuget.org/redirect-on-307" - }, - body: "redirecting on 307" - ) - stub_request(:get, "https://api.nuget.org/redirect-on-307") - .to_return( - status: 308, - headers: { - "Location" => "https://api.nuget.org/redirect-on-308" - }, - body: "redirecting on 308" - ) - stub_request(:get, "https://api.nuget.org/redirect-on-308") - .to_return( - status: 200, - body: "the final contents" - ) - end - - it "fetches the nupkg after multiple redirects" do - expect(nupkg_buffer.to_s).to eq("the final contents") - end - end -end diff --git a/nuget/spec/dependabot/nuget/update_checker/nuspec_fetcher_spec.rb b/nuget/spec/dependabot/nuget/update_checker/nuspec_fetcher_spec.rb deleted file mode 100644 index d81a191eed4..00000000000 --- a/nuget/spec/dependabot/nuget/update_checker/nuspec_fetcher_spec.rb +++ /dev/null @@ -1,55 +0,0 @@ -# typed: false -# frozen_string_literal: true - -require "spec_helper" -require "dependabot/dependency" -require "dependabot/dependency_file" -require "dependabot/nuget/update_checker/nuspec_fetcher" - -RSpec.describe Dependabot::Nuget::NuspecFetcher do - describe "#feed_supports_nuspec_download?" do - context "when checking with a azure feed url" do - let(:url) { "https://pkgs.dev.azure.com/dependabot/dependabot-test/_packaging/dependabot-feed/nuget/v3/index.json" } - subject(:result) { described_class.feed_supports_nuspec_download?(url) } - - it { is_expected.to be_truthy } - end - - context "when checking with a azure feed url (no project)" do - let(:url) { "https://pkgs.dev.azure.com/dependabot/_packaging/dependabot-feed/nuget/v3/index.json" } - subject(:result) { described_class.feed_supports_nuspec_download?(url) } - - it { is_expected.to be_truthy } - end - - context "when checking with a visual studio feed url" do - let(:url) { "https://dynamicscrm.pkgs.visualstudio.com/_packaging/CRM.Engineering/nuget/v3/index.json" } - subject(:result) { described_class.feed_supports_nuspec_download?(url) } - - it { is_expected.to be_truthy } - end - - context "when checking with the nuget.org feed url" do - let(:url) { "https://api.nuget.org/v3/index.json" } - subject(:result) { described_class.feed_supports_nuspec_download?(url) } - - it { is_expected.to be_truthy } - end - - context "when checking with github feed url" do - let(:url) { "https://nuget.pkg.github.com/some_namespace/index.json" } - subject(:result) { described_class.feed_supports_nuspec_download?(url) } - - it { is_expected.to be_falsy } - end - end - - describe "remove_invalid_characters" do - context "when a utf-16 bom is present" do - let(:response_body) { "\xFE\xFF" } - subject(:result) { described_class.remove_invalid_characters(response_body) } - - it { is_expected.to eq("") } - end - end -end diff --git a/nuget/spec/dependabot/nuget/update_checker/repository_finder_spec.rb b/nuget/spec/dependabot/nuget/update_checker/repository_finder_spec.rb deleted file mode 100644 index cfa420097d3..00000000000 --- a/nuget/spec/dependabot/nuget/update_checker/repository_finder_spec.rb +++ /dev/null @@ -1,988 +0,0 @@ -# typed: false -# frozen_string_literal: true - -require "spec_helper" -require "dependabot/dependency" -require "dependabot/dependency_file" -require "dependabot/nuget/update_checker/repository_finder" -require_relative "../nuget_search_stubs" - -RSpec.describe Dependabot::Nuget::RepositoryFinder do - RSpec.configure do |config| - config.include(NuGetSearchStubs) - end - - subject(:finder) do - described_class.new( - dependency: dependency, - credentials: credentials, - config_files: [config_file].compact - ) - end - let(:config_file) { nil } - let(:credentials) do - [{ - "type" => "git_source", - "host" => "github.com", - "username" => "x-access-token", - "password" => "token" - }] - end - let(:dependency) do - Dependabot::Dependency.new( - name: "Microsoft.Extensions.DependencyModel", - version: "1.1.1", - requirements: [{ - requirement: "1.1.1", - file: "my.csproj", - groups: ["dependencies"], - source: nil - }], - package_manager: "nuget" - ) - end - - describe "local path in NuGet.Config" do - let(:config_file) do - nuget_config_content = <<~XML - - - - - - - - - - XML - Dependabot::DependencyFile.new( - name: "NuGet.Config", - content: nuget_config_content, - directory: "some/directory" - ) - end - - subject(:known_repositories) { finder.known_repositories } - - it "finds all local paths" do - urls = known_repositories.map { |r| r[:url] } - expected = [ - "/some/directory/SomePath", - "/some/directory/RelativePath", - "/AbsolutePath", - "https://nuget.example.com/index.json" - ] - expect(urls).to match_array(expected) - end - end - - describe "environment variables in NuGet.Config" do - let(:config_file) do - nuget_config_content = <<~XML - - - - - - - - - - - - - XML - Dependabot::DependencyFile.new( - name: "NuGet.Config", - content: nuget_config_content - ) - end - - subject(:known_repositories) { finder.known_repositories } - - context "are expanded" do - before do - allow(Dependabot.logger).to receive(:warn) - ENV["FEED_URL"] = "https://nuget.example.com/index.json" - ENV["THIS_VARIBLE_EXISTS"] = "replacement-text" - ENV.delete("THIS_VARIABLE_DOES_NOT") - end - - it "contains the expected values and warns on unavailable" do - repo = known_repositories[0] - expect(repo[:url]).to eq("https://nuget.example.com/index.json") - expect(repo[:token]).to eq("user:(head)replacement-text(mid)%THIS_VARIABLE_DOES_NOT%(tail)") - expect(Dependabot.logger).to have_received(:warn).with( - <<~WARN - The variable '%THIS_VARIABLE_DOES_NOT%' could not be expanded in NuGet.Config - WARN - ) - end - - after do - ENV.delete("THIS_VARIBLE_EXISTS") - ENV.delete("THIS_VARIABLE_DOES_NOT") - end - end - end - - describe "dependency_urls" do - subject(:dependency_urls) { finder.dependency_urls } - - it "gets the right URL without making any requests" do - expect(dependency_urls).to eq( - [{ - base_url: "https://api.nuget.org/v3-flatcontainer/", - registration_url: "https://api.nuget.org/v3/registration5-gz-semver2/" \ - "microsoft.extensions.dependencymodel/index.json", - repository_url: "https://api.nuget.org/v3/index.json", - versions_url: "https://api.nuget.org/v3-flatcontainer/" \ - "microsoft.extensions.dependencymodel/index.json", - search_url: "https://azuresearch-usnc.nuget.org/query" \ - "?q=microsoft.extensions.dependencymodel" \ - "&prerelease=true&semVerLevel=2.0.0", - auth_header: {}, - repository_type: "v3" - }] - ) - end - - context "with a URL passed as a credential" do - let(:custom_repo_url) do - "https://www.myget.org/F/exceptionless/api/v3/index.json" - end - let(:credentials) do - [{ - "type" => "git_source", - "host" => "github.com", - "username" => "x-access-token", - "password" => "token" - }, { - "type" => "nuget_feed", - "url" => custom_repo_url, - "token" => "my:passw0rd" - }] - end - - before do - stub_request(:get, custom_repo_url) - .with(basic_auth: %w(my passw0rd)) - .to_return( - status: 200, - body: fixture("nuget_responses", "myget_base.json") - ) - end - - it "gets the right URL" do - expect(dependency_urls).to eq( - [{ - base_url: "https://www.myget.org/F/exceptionless/api/v3/flatcontainer/", - registration_url: "https://www.myget.org/F/exceptionless/api/v3/registration1/" \ - "microsoft.extensions.dependencymodel/index.json", - repository_url: "https://www.myget.org/F/exceptionless/api/v3/" \ - "index.json", - versions_url: "https://www.myget.org/F/exceptionless/api/v3/" \ - "flatcontainer/microsoft.extensions." \ - "dependencymodel/index.json", - search_url: "https://www.myget.org/F/exceptionless/api/v3/" \ - "query?q=microsoft.extensions.dependencymodel" \ - "&prerelease=true&semVerLevel=2.0.0", - auth_header: { "Authorization" => "Basic bXk6cGFzc3cwcmQ=" }, - repository_type: "v3" - }] - ) - end - - context "that does not return PackageBaseAddress" do - let(:custom_repo_url) { "http://localhost:8082/artifactory/api/nuget/v3/nuget-local" } - before do - stub_request(:get, custom_repo_url) - .to_return( - status: 200, - body: fixture("nuget_responses", "artifactory_base.json") - ) - end - - it "gets the right URL" do - expect(dependency_urls).to eq( - [{ - base_url: nil, - registration_url: "http://localhost:8081/artifactory/api/nuget/v3/" \ - "dependabot-nuget-local/registration/microsoft.extensions.dependencymodel/index.json", - repository_url: custom_repo_url, - search_url: "http://localhost:8081/artifactory/api/nuget/v3/" \ - "dependabot-nuget-local/query?q=microsoft.extensions.dependencymodel" \ - "&prerelease=true&semVerLevel=2.0.0", - auth_header: { "Authorization" => "Basic bXk6cGFzc3cwcmQ=" }, - repository_type: "v3" - }] - ) - end - end - - context "that has URLs that need to be escaped" do - let(:custom_repo_url) { "https://www.myget.org/F/exceptionless/api with spaces/v3/index.json" } - before do - stub_request(:get, "https://www.myget.org/F/exceptionless/api%20with%20spaces/v3/index.json") - .to_return( - status: 200, - body: fixture("nuget_responses", "myget_base.json") - ) - end - - it "gets the right URL" do - expect(dependency_urls).to eq( - [{ - base_url: "https://www.myget.org/F/exceptionless/api/v3/flatcontainer/", - registration_url: "https://www.myget.org/F/exceptionless/api/v3/registration1/" \ - "microsoft.extensions.dependencymodel/index.json", - repository_url: "https://www.myget.org/F/exceptionless/api%20with%20spaces/v3/index.json", - versions_url: "https://www.myget.org/F/exceptionless/api/v3/" \ - "flatcontainer/microsoft.extensions." \ - "dependencymodel/index.json", - search_url: "https://www.myget.org/F/exceptionless/api/v3/" \ - "query?q=microsoft.extensions.dependencymodel" \ - "&prerelease=true&semVerLevel=2.0.0", - auth_header: { "Authorization" => "Basic bXk6cGFzc3cwcmQ=" }, - repository_type: "v3" - }] - ) - end - end - - context "that 404s" do - before { stub_request(:get, custom_repo_url).to_return(status: 404) } - - # TODO: Might want to raise here instead? - it { is_expected.to eq([]) } - end - - context "that 403s" do - before { stub_request(:get, custom_repo_url).to_return(status: 403) } - - it "raises a useful error" do - error_class = Dependabot::PrivateSourceAuthenticationFailure - expect { finder.dependency_urls } - .to raise_error do |error| - expect(error).to be_a(error_class) - expect(error.source).to eq(custom_repo_url) - end - end - end - - context "without a token" do - let(:credentials) do - [{ - "type" => "git_source", - "host" => "github.com", - "username" => "x-access-token", - "password" => "token" - }, { - "type" => "nuget_feed", - "url" => custom_repo_url - }] - end - - before do - stub_request(:get, custom_repo_url) - .with(basic_auth: nil) - .to_return( - status: 200, - body: fixture("nuget_responses", "myget_base.json") - ) - end - - it "gets the right URL" do - expect(dependency_urls).to eq( - [{ - base_url: "https://www.myget.org/F/exceptionless/api/v3/flatcontainer/", - registration_url: "https://www.myget.org/F/exceptionless/api/v3/registration1/" \ - "microsoft.extensions.dependencymodel/index.json", - repository_url: "https://www.myget.org/F/exceptionless/api/v3/" \ - "index.json", - versions_url: "https://www.myget.org/F/exceptionless/api/v3/" \ - "flatcontainer/microsoft.extensions." \ - "dependencymodel/index.json", - search_url: "https://www.myget.org/F/exceptionless/api/v3/" \ - "query?q=microsoft.extensions.dependencymodel" \ - "&prerelease=true&semVerLevel=2.0.0", - auth_header: {}, - repository_type: "v3" - }] - ) - end - end - end - - context "with a URL included in the nuget.config" do - let(:config_file) do - Dependabot::DependencyFile.new( - name: "NuGet.Config", - content: fixture("configs", config_file_fixture_name) - ) - end - let(:config_file_fixture_name) { "nuget.config" } - - before do - repo_url = "https://www.myget.org/F/exceptionless/api/v3/index.json" - stub_request(:get, repo_url).to_return(status: 404) - stub_request(:get, repo_url) - .with(basic_auth: %w(my passw0rd)) - .to_return( - status: 200, - body: fixture("nuget_responses", "myget_base.json") - ) - end - - # skipped - # it "gets the right URLs" do - # expect(dependency_urls).to match_array( - # [{ - # repository_url: "https://api.nuget.org/v3/index.json", - # versions_url: "https://api.nuget.org/v3-flatcontainer/" \ - # "microsoft.extensions.dependencymodel/index.json", - # search_url: "https://azuresearch-usnc.nuget.org/query" \ - # "?q=microsoft.extensions.dependencymodel" \ - # "&prerelease=true&semVerLevel=2.0.0", - # auth_header: {}, - # repository_type: "v3" - # }, { - # repository_url: "https://www.myget.org/F/exceptionless/api/v3/" \ - # "index.json", - # versions_url: "https://www.myget.org/F/exceptionless/api/v3/" \ - # "flatcontainer/microsoft.extensions." \ - # "dependencymodel/index.json", - # search_url: "https://www.myget.org/F/exceptionless/api/v3/" \ - # "query?q=microsoft.extensions.dependencymodel" \ - # "&prerelease=true&semVerLevel=2.0.0", - # auth_header: { "Authorization" => "Basic bXk6cGFzc3cwcmQ=" }, - # repository_type: "v3" - # }] - # ) - # end - - context "include the default repository" do - let(:config_file_fixture_name) { "include_default_disable_ext_sources.config" } - - it "with disable external source" do - expect(dependency_urls).to match_array( - [{ - base_url: "https://www.myget.org/F/exceptionless/api/v3/flatcontainer/", - repository_url: "https://www.myget.org/F/exceptionless/api/v3/" \ - "index.json", - registration_url: "https://www.myget.org/F/exceptionless/api/v3/" \ - "registration1/microsoft.extensions.dependencymodel/index.json", - versions_url: "https://www.myget.org/F/exceptionless/api/v3/" \ - "flatcontainer/microsoft.extensions." \ - "dependencymodel/index.json", - search_url: "https://www.myget.org/F/exceptionless/api/v3/" \ - "query?q=microsoft.extensions.dependencymodel" \ - "&prerelease=true&semVerLevel=2.0.0", - auth_header: { "Authorization" => "Basic bXk6cGFzc3cwcmQ=" }, - repository_type: "v3" - }, { - base_url: "https://api.nuget.org/v3-flatcontainer/", - registration_url: "https://api.nuget.org/v3/registration5-gz-semver2/" \ - "microsoft.extensions.dependencymodel/index.json", - repository_url: "https://api.nuget.org/v3/index.json", - versions_url: "https://api.nuget.org/v3-flatcontainer/" \ - "microsoft.extensions.dependencymodel/index.json", - search_url: "https://azuresearch-usnc.nuget.org/query" \ - "?q=microsoft.extensions.dependencymodel" \ - "&prerelease=true&semVerLevel=2.0.0", - auth_header: {}, - repository_type: "v3" - }] - ) - end - end - - context "that overrides the default package sources" do - let(:config_file_fixture_name) { "override_def_source_with_same_key.config" } - - before do - repo_url = "https://www.myget.org/F/exceptionless/api/v3/index.json" - stub_request(:get, repo_url) - .to_return( - status: 200, - body: fixture("nuget_responses", "myget_base.json") - ) - end - - it "when the default api key of default registry is provided without clear" do - expect(dependency_urls).to match_array( - [{ - base_url: "https://www.myget.org/F/exceptionless/api/v3/flatcontainer/", - registration_url: "https://www.myget.org/F/exceptionless/api/v3/registration1/" \ - "microsoft.extensions.dependencymodel/index.json", - repository_url: "https://www.myget.org/F/exceptionless/api/v3/" \ - "index.json", - versions_url: "https://www.myget.org/F/exceptionless/api/v3/" \ - "flatcontainer/microsoft.extensions." \ - "dependencymodel/index.json", - search_url: "https://www.myget.org/F/exceptionless/api/v3/" \ - "query?q=microsoft.extensions.dependencymodel" \ - "&prerelease=true&semVerLevel=2.0.0", - auth_header: {}, - repository_type: "v3" - }] - ) - end - - let(:config_file_fixture_name) { "override_def_source_with_same_key_default.config" } - it "when the default api key of default registry is provided with clear" do - expect(dependency_urls).to match_array( - [{ - base_url: "https://www.myget.org/F/exceptionless/api/v3/flatcontainer/", - registration_url: "https://www.myget.org/F/exceptionless/api/v3/registration1/" \ - "microsoft.extensions.dependencymodel/index.json", - repository_url: "https://www.myget.org/F/exceptionless/api/v3/" \ - "index.json", - versions_url: "https://www.myget.org/F/exceptionless/api/v3/" \ - "flatcontainer/microsoft.extensions." \ - "dependencymodel/index.json", - search_url: "https://www.myget.org/F/exceptionless/api/v3/" \ - "query?q=microsoft.extensions.dependencymodel" \ - "&prerelease=true&semVerLevel=2.0.0", - auth_header: {}, - repository_type: "v3" - }] - ) - end - end - - context "that doesn't include the default repository" do - let(:config_file_fixture_name) { "excludes_default.config" } - - it "still includes the default repository (as it wasn't cleared)" do - expect(dependency_urls).to match_array( - [{ - base_url: "https://api.nuget.org/v3-flatcontainer/", - registration_url: "https://api.nuget.org/v3/registration5-gz-semver2/" \ - "microsoft.extensions.dependencymodel/index.json", - repository_url: "https://api.nuget.org/v3/index.json", - versions_url: "https://api.nuget.org/v3-flatcontainer/" \ - "microsoft.extensions.dependencymodel/index.json", - search_url: "https://azuresearch-usnc.nuget.org/query" \ - "?q=microsoft.extensions.dependencymodel" \ - "&prerelease=true&semVerLevel=2.0.0", - auth_header: {}, - repository_type: "v3" - }, { - base_url: "https://www.myget.org/F/exceptionless/api/v3/flatcontainer/", - registration_url: "https://www.myget.org/F/exceptionless/api/v3/registration1/" \ - "microsoft.extensions.dependencymodel/index.json", - repository_url: "https://www.myget.org/F/exceptionless/api/v3/" \ - "index.json", - versions_url: "https://www.myget.org/F/exceptionless/api/v3/" \ - "flatcontainer/microsoft.extensions." \ - "dependencymodel/index.json", - search_url: "https://www.myget.org/F/exceptionless/api/v3/" \ - "query?q=microsoft.extensions.dependencymodel" \ - "&prerelease=true&semVerLevel=2.0.0", - auth_header: { "Authorization" => "Basic bXk6cGFzc3cwcmQ=" }, - repository_type: "v3" - }] - ) - end - - context "and clears it" do - let(:config_file_fixture_name) { "clears_default.config" } - - it "still excludes the default repository" do - expect(dependency_urls).to match_array( - [{ - base_url: "https://www.myget.org/F/exceptionless/api/v3/flatcontainer/", - registration_url: "https://www.myget.org/F/exceptionless/api/v3/registration1/" \ - "microsoft.extensions.dependencymodel/index.json", - repository_url: "https://www.myget.org/F/exceptionless/api/v3/" \ - "index.json", - versions_url: "https://www.myget.org/F/exceptionless/api/v3/" \ - "flatcontainer/microsoft.extensions." \ - "dependencymodel/index.json", - search_url: "https://www.myget.org/F/exceptionless/api/v3/" \ - "query?q=microsoft.extensions.dependencymodel" \ - "&prerelease=true&semVerLevel=2.0.0", - auth_header: { "Authorization" => "Basic bXk6cGFzc3cwcmQ=" }, - repository_type: "v3" - }] - ) - end - end - - context "that has disabled package sources" do - let(:config_file_fixture_name) { "disabled_sources.config" } - - it "only includes the enabled package sources" do - expect(dependency_urls).to match_array( - [{ - base_url: "https://www.myget.org/F/exceptionless/api/v3/flatcontainer/", - registration_url: "https://www.myget.org/F/exceptionless/api/v3/registration1/" \ - "microsoft.extensions.dependencymodel/index.json", - repository_url: "https://www.myget.org/F/exceptionless/api/v3/" \ - "index.json", - versions_url: "https://www.myget.org/F/exceptionless/api/v3/" \ - "flatcontainer/microsoft.extensions." \ - "dependencymodel/index.json", - search_url: "https://www.myget.org/F/exceptionless/api/v3/" \ - "query?q=microsoft.extensions.dependencymodel" \ - "&prerelease=true&semVerLevel=2.0.0", - auth_header: { "Authorization" => "Basic bXk6cGFzc3cwcmQ=" }, - repository_type: "v3" - }] - ) - end - end - - context "that has disabled default package sources" do - let(:config_file_fixture_name) { "disabled_default_sources.config" } - - it "only includes the enable package sources" do - expect(dependency_urls).to match_array( - [{ - base_url: "https://www.myget.org/F/exceptionless/api/v3/flatcontainer/", - registration_url: "https://www.myget.org/F/exceptionless/api/v3/registration1/" \ - "microsoft.extensions.dependencymodel/index.json", - repository_url: "https://www.myget.org/F/exceptionless/api/v3/" \ - "index.json", - versions_url: "https://www.myget.org/F/exceptionless/api/v3/" \ - "flatcontainer/microsoft.extensions." \ - "dependencymodel/index.json", - search_url: "https://www.myget.org/F/exceptionless/api/v3/" \ - "query?q=microsoft.extensions.dependencymodel" \ - "&prerelease=true&semVerLevel=2.0.0", - auth_header: { "Authorization" => "Basic bXk6cGFzc3cwcmQ=" }, - repository_type: "v3" - }] - ) - end - end - end - - context "that has a numeric key" do - let(:config_file_fixture_name) { "numeric_key.config" } - - before do - repo_url = "https://www.myget.org/F/exceptionless/api/v3/index.json" - stub_request(:get, repo_url) - .to_return( - status: 200, - body: fixture("nuget_responses", "myget_base.json") - ) - end - - it "gets the right URLs" do - expect(dependency_urls).to match_array( - [{ - base_url: "https://www.myget.org/F/exceptionless/api/v3/flatcontainer/", - registration_url: "https://www.myget.org/F/exceptionless/api/v3/registration1/" \ - "microsoft.extensions.dependencymodel/index.json", - repository_url: "https://www.myget.org/F/exceptionless/api/v3/" \ - "index.json", - versions_url: "https://www.myget.org/F/exceptionless/api/v3/" \ - "flatcontainer/microsoft.extensions." \ - "dependencymodel/index.json", - search_url: "https://www.myget.org/F/exceptionless/api/v3/" \ - "query?q=microsoft.extensions.dependencymodel" \ - "&prerelease=true&semVerLevel=2.0.0", - auth_header: {}, - repository_type: "v3" - }] - ) - end - end - - context "that only provides versioned `SearchQueryService`` entries" do - let(:config_file_fixture_name) { "versioned_search.config" } - - before do - repo_url = "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-libraries/nuget/v3/index.json" - stub_request(:get, repo_url) - .to_return( - status: 200, - body: fixture("nuget_responses", "index.json", "versioned_SearchQueryService.index.json") - ) - end - - it "gets the right URLs" do - expect(dependency_urls).to match_array( - [{ - base_url: "https://pkgs.dev.azure.com/dnceng/9ee6d478-d288-47f7-aacc-f6e6d082ae6d/_packaging/516521bf-6417-457e-9a9c-0a4bdfde03e7/nuget/v3/flat2/", - registration_url: "https://pkgs.dev.azure.com/dnceng/9ee6d478-d288-47f7-aacc-f6e6d082ae6d/_packaging/516521bf-6417-457e-9a9c-0a4bdfde03e7/nuget/v3/registrations2/microsoft.extensions.dependencymodel/index.json", - repository_url: "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-libraries/nuget/v3/index.json", - versions_url: "https://pkgs.dev.azure.com/dnceng/9ee6d478-d288-47f7-aacc-f6e6d082ae6d/_packaging/516521bf-6417-457e-9a9c-0a4bdfde03e7/nuget/v3/flat2/microsoft.extensions.dependencymodel/index.json", - search_url: "https://pkgs.dev.azure.com/dnceng/9ee6d478-d288-47f7-aacc-f6e6d082ae6d/_packaging/516521bf-6417-457e-9a9c-0a4bdfde03e7/nuget/v3/query2/?q=microsoft.extensions.dependencymodel&prerelease=true&semVerLevel=2.0.0", - auth_header: {}, - repository_type: "v3" - }] - ) - end - end - - context "includes repositories in the `trustedSigners` section" do - let(:config_file_fixture_name) { "with_trustedSigners.config" } - - before do - repo_url = "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-libraries/nuget/v3/index.json" - stub_request(:get, repo_url) - .to_return( - status: 200, - body: fixture("nuget_responses", "index.json", "versioned_SearchQueryService.index.json") - ) - end - - it "gets the right URLs" do - expect(dependency_urls).to eq( - [{ - base_url: "https://api.nuget.org/v3-flatcontainer/", - registration_url: "https://api.nuget.org/v3/registration5-gz-semver2/" \ - "microsoft.extensions.dependencymodel/index.json", - repository_url: "https://api.nuget.org/v3/index.json", - versions_url: "https://api.nuget.org/v3-flatcontainer/microsoft.extensions.dependencymodel/index.json", - search_url: "https://azuresearch-usnc.nuget.org/query?q=microsoft.extensions.dependencymodel&prerelease=true&semVerLevel=2.0.0", - auth_header: {}, - repository_type: "v3" - }, - { - base_url: "https://pkgs.dev.azure.com/dnceng/9ee6d478-d288-47f7-aacc-f6e6d082ae6d/_packaging/516521bf-6417-457e-9a9c-0a4bdfde03e7/nuget/v3/flat2/", - registration_url: "https://pkgs.dev.azure.com/dnceng/9ee6d478-d288-47f7-aacc-f6e6d082ae6d/_packaging/516521bf-6417-457e-9a9c-0a4bdfde03e7/nuget/v3/registrations2/microsoft.extensions.dependencymodel/index.json", - repository_url: "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-libraries/nuget/v3/index.json", - versions_url: "https://pkgs.dev.azure.com/dnceng/9ee6d478-d288-47f7-aacc-f6e6d082ae6d/_packaging/516521bf-6417-457e-9a9c-0a4bdfde03e7/nuget/v3/flat2/microsoft.extensions.dependencymodel/index.json", - search_url: "https://pkgs.dev.azure.com/dnceng/9ee6d478-d288-47f7-aacc-f6e6d082ae6d/_packaging/516521bf-6417-457e-9a9c-0a4bdfde03e7/nuget/v3/query2/?q=microsoft.extensions.dependencymodel&prerelease=true&semVerLevel=2.0.0", - auth_header: {}, - repository_type: "v3" - }] - ) - end - end - - context "with GitHub packages url" do - let(:config_file_fixture_name) { "github.nuget.config" } - - before do - repo_url = "https://nuget.pkg.github.com/some-namespace/index.json" - stub_request(:get, repo_url) - .to_return( - status: 200, - body: fixture("nuget_responses", "index.json", "github.index.json") - ) - end - - it "gets the right URLs" do - expect(dependency_urls).to eq( - [{ - base_url: "https://nuget.pkg.github.com/some-namespace/download", - registration_url: "https://nuget.pkg.github.com/some-namespace/microsoft.extensions.dependencymodel/index.json", - repository_url: "https://nuget.pkg.github.com/some-namespace/index.json", - versions_url: "https://nuget.pkg.github.com/some-namespace/download/microsoft.extensions.dependencymodel/index.json", - search_url: "https://nuget.pkg.github.com/some-namespace/query?q=microsoft.extensions.dependencymodel&prerelease=true&semVerLevel=2.0.0", - auth_header: {}, - repository_type: "v3" - }] - ) - end - end - - context "that has a non-ascii key" do - let(:config_file_fixture_name) { "non_ascii_key.config" } - - before do - repo_url = "https://www.myget.org/F/exceptionless/api/v3/index.json" - stub_request(:get, repo_url) - .to_return( - status: 200, - body: fixture("nuget_responses", "myget_base.json") - ) - end - - it "gets the right URLs" do - expect(dependency_urls).to match_array( - [{ - base_url: "https://www.myget.org/F/exceptionless/api/v3/flatcontainer/", - registration_url: "https://www.myget.org/F/exceptionless/api/v3/registration1/" \ - "microsoft.extensions.dependencymodel/index.json", - repository_url: "https://www.myget.org/F/exceptionless/api/v3/" \ - "index.json", - versions_url: "https://www.myget.org/F/exceptionless/api/v3/" \ - "flatcontainer/microsoft.extensions." \ - "dependencymodel/index.json", - search_url: "https://www.myget.org/F/exceptionless/api/v3/" \ - "query?q=microsoft.extensions.dependencymodel" \ - "&prerelease=true&semVerLevel=2.0.0", - auth_header: {}, - repository_type: "v3" - }] - ) - end - end - - context "that uses the v2 API alongside the v3 API" do - let(:config_file_fixture_name) { "with_v2_endpoints.config" } - - before do - v2_repo_urls = %w( - https://www.nuget.org/api/v2/ - https://www.myget.org/F/azure-appservice/api/v2 - https://www.myget.org/F/azure-appservice-staging/api/v2 - https://www.myget.org/F/fusemandistfeed/api/v2 - https://www.myget.org/F/30de4ee06dd54956a82013fa17a3accb/ - ) - - v2_repo_urls.each do |repo_url| - stub_request(:get, repo_url) - .to_return( - status: 200, - body: fixture("nuget_responses", "v2_base.xml") - ) - end - - url = "https://dotnet.myget.org/F/aspnetcore-dev/api/v3/index.json" - stub_request(:get, url) - .to_return( - status: 200, - body: fixture("nuget_responses", "myget_base.json") - ) - end - - it "gets the right URLs" do - expect(dependency_urls).to match_array( - [{ - base_url: "https://www.myget.org/F/exceptionless/api/v3/flatcontainer/", - registration_url: "https://www.myget.org/F/exceptionless/api/v3/registration1/" \ - "microsoft.extensions.dependencymodel/index.json", - repository_url: - "https://dotnet.myget.org/F/aspnetcore-dev/api/v3/index.json", - versions_url: - "https://www.myget.org/F/exceptionless/api/v3/" \ - "flatcontainer/microsoft.extensions.dependencymodel/index.json", - search_url: - "https://www.myget.org/F/exceptionless/api/v3/" \ - "query?q=microsoft.extensions.dependencymodel&prerelease=true&semVerLevel=2.0.0", - auth_header: {}, - repository_type: "v3" - }, { - base_url: "https://www.nuget.org/api/v2", - repository_url: "https://www.nuget.org/api/v2", - versions_url: - "https://www.nuget.org/api/v2/FindPackagesById()?id=" \ - "'Microsoft.Extensions.DependencyModel'", - auth_header: {}, - repository_type: "v2" - }] - ) - end - end - - context "that has no base url in v2 API response" do - let(:config_file_fixture_name) { "with_v2_endpoints.config" } - - before do - v2_repo_urls = %w( - https://www.nuget.org/api/v2/ - https://www.myget.org/F/azure-appservice/api/v2 - https://www.myget.org/F/azure-appservice-staging/api/v2 - https://www.myget.org/F/fusemandistfeed/api/v2 - https://www.myget.org/F/30de4ee06dd54956a82013fa17a3accb/ - ) - - v2_repo_urls.each do |repo_url| - stub_request(:get, repo_url) - .to_return( - status: 200, - body: fixture("nuget_responses", "v2_no_base.xml") - ) - end - - url = "https://dotnet.myget.org/F/aspnetcore-dev/api/v3/index.json" - stub_request(:get, url) - .to_return( - status: 200, - body: fixture("nuget_responses", "myget_base.json") - ) - end - - it "gets the right URLs" do - expect(dependency_urls).to match_array( - [{ - base_url: "https://www.myget.org/F/exceptionless/api/v3/flatcontainer/", - registration_url: "https://www.myget.org/F/exceptionless/api/v3/registration1/" \ - "microsoft.extensions.dependencymodel/index.json", - repository_url: - "https://dotnet.myget.org/F/aspnetcore-dev/api/v3/index.json", - versions_url: - "https://www.myget.org/F/exceptionless/api/v3/" \ - "flatcontainer/microsoft.extensions.dependencymodel/index.json", - search_url: - "https://www.myget.org/F/exceptionless/api/v3/" \ - "query?q=microsoft.extensions.dependencymodel&prerelease=true&semVerLevel=2.0.0", - auth_header: {}, - repository_type: "v3" - }, { - base_url: "https://www.nuget.org/api/v2/", - repository_url: "https://www.nuget.org/api/v2/", - versions_url: - "https://www.nuget.org/api/v2/FindPackagesById()?id=" \ - "'Microsoft.Extensions.DependencyModel'", - auth_header: {}, - repository_type: "v2" - }, { - base_url: "https://www.myget.org/F/azure-appservice/api/v2", - repository_url: "https://www.myget.org/F/azure-appservice/api/v2", - versions_url: - "https://www.myget.org/F/azure-appservice/api/v2/" \ - "FindPackagesById()?id=" \ - "'Microsoft.Extensions.DependencyModel'", - auth_header: {}, - repository_type: "v2" - }, { - base_url: "https://www.myget.org/F/azure-appservice-staging/api/v2", - repository_url: - "https://www.myget.org/F/azure-appservice-staging/api/v2", - versions_url: - "https://www.myget.org/F/azure-appservice-staging/api/v2/" \ - "FindPackagesById()?id=" \ - "'Microsoft.Extensions.DependencyModel'", - auth_header: {}, - repository_type: "v2" - }, { - base_url: "https://www.myget.org/F/fusemandistfeed/api/v2", - repository_url: "https://www.myget.org/F/fusemandistfeed/api/v2", - versions_url: - "https://www.myget.org/F/fusemandistfeed/api/v2/" \ - "FindPackagesById()?id=" \ - "'Microsoft.Extensions.DependencyModel'", - auth_header: {}, - repository_type: "v2" - }, { - base_url: "https://www.myget.org/F/30de4ee06dd54956a82013fa17a3accb/", - repository_url: - "https://www.myget.org/F/30de4ee06dd54956a82013fa17a3accb/", - versions_url: - "https://www.myget.org/F/30de4ee06dd54956a82013fa17a3accb/" \ - "FindPackagesById()?id=" \ - "'Microsoft.Extensions.DependencyModel'", - auth_header: {}, - repository_type: "v2" - }] - ) - end - end - - context "matching `packageSourceMapping` entries are honored" do - let(:config_file) do - nuget_config_content = <<~XML - - - - - - - - - - - - - - - - - - - - XML - Dependabot::DependencyFile.new( - name: "NuGet.Config", - content: nuget_config_content - ) - end - - before do - # `source1` and `source3` should never be queried - stub_index_json("https://nuget.example.com/source2/index.json") - end - - it "matches on the best pattern" do - expect(dependency_urls).to match_array( - [{ - base_url: "https://nuget.example.com/source2/PackageBaseAddress", - registration_url: "https://nuget.example.com/source2/RegistrationsBaseUrl/microsoft.extensions.dependencymodel/index.json", - repository_url: "https://nuget.example.com/source2/index.json", - versions_url: "https://nuget.example.com/source2/PackageBaseAddress/microsoft.extensions.dependencymodel/index.json", - search_url: "https://nuget.example.com/source2/SearchQueryService?q=microsoft.extensions.dependencymodel&prerelease=true&semVerLevel=2.0.0", - auth_header: {}, - repository_type: "v3" - }] - ) - end - end - - context "non-matching `packageSourceMapping` entries are ignored" do - let(:config_file) do - nuget_config_content = <<~XML - - - - - - - - - - - - - - - - - - - - XML - Dependabot::DependencyFile.new( - name: "NuGet.Config", - content: nuget_config_content - ) - end - - before do - # all sources will need to be queried - stub_index_json("https://nuget.example.com/source1/index.json") - stub_index_json("https://nuget.example.com/source2/index.json") - stub_index_json("https://nuget.example.com/source3/index.json") - end - - it "returns all sources" do - expect(dependency_urls).to match_array( - [{ - base_url: "https://nuget.example.com/source1/PackageBaseAddress", - registration_url: "https://nuget.example.com/source1/RegistrationsBaseUrl/microsoft.extensions.dependencymodel/index.json", - repository_url: "https://nuget.example.com/source1/index.json", - versions_url: "https://nuget.example.com/source1/PackageBaseAddress/microsoft.extensions.dependencymodel/index.json", - search_url: "https://nuget.example.com/source1/SearchQueryService?q=microsoft.extensions.dependencymodel&prerelease=true&semVerLevel=2.0.0", - auth_header: {}, - repository_type: "v3" - }, { - base_url: "https://nuget.example.com/source2/PackageBaseAddress", - registration_url: "https://nuget.example.com/source2/RegistrationsBaseUrl/microsoft.extensions.dependencymodel/index.json", - repository_url: "https://nuget.example.com/source2/index.json", - versions_url: "https://nuget.example.com/source2/PackageBaseAddress/microsoft.extensions.dependencymodel/index.json", - search_url: "https://nuget.example.com/source2/SearchQueryService?q=microsoft.extensions.dependencymodel&prerelease=true&semVerLevel=2.0.0", - auth_header: {}, - repository_type: "v3" - }, { - base_url: "https://nuget.example.com/source3/PackageBaseAddress", - registration_url: "https://nuget.example.com/source3/RegistrationsBaseUrl/microsoft.extensions.dependencymodel/index.json", - repository_url: "https://nuget.example.com/source3/index.json", - versions_url: "https://nuget.example.com/source3/PackageBaseAddress/microsoft.extensions.dependencymodel/index.json", - search_url: "https://nuget.example.com/source3/SearchQueryService?q=microsoft.extensions.dependencymodel&prerelease=true&semVerLevel=2.0.0", - auth_header: {}, - repository_type: "v3" - }] - ) - end - end - end - end -end diff --git a/nuget/spec/dependabot/nuget/update_checker/tfm_finder_spec.rb b/nuget/spec/dependabot/nuget/update_checker/tfm_finder_spec.rb deleted file mode 100644 index c3e0ba00665..00000000000 --- a/nuget/spec/dependabot/nuget/update_checker/tfm_finder_spec.rb +++ /dev/null @@ -1,56 +0,0 @@ -# typed: false -# frozen_string_literal: true - -require "spec_helper" -require "dependabot/dependency" -require "dependabot/dependency_file" -require "dependabot/nuget/file_parser" -require "dependabot/nuget/update_checker/tfm_finder" - -RSpec.describe Dependabot::Nuget::TfmFinder do - let(:project_name) { "tfm_finder" } - let(:dependency_files) { nuget_project_dependency_files(project_name, directory: "/").reverse } - let(:repo_contents_path) { nuget_build_tmp_repo(project_name) } - let(:source) do - Dependabot::Source.new( - provider: "github", - repo: "gocardless/bump", - directory: "/" - ) - end - let(:dependency) do - Dependabot::Dependency.new( - name: dependency_name, - version: dependency_version, - requirements: dependency_requirements, - package_manager: "nuget" - ) - end - - subject(:frameworks) do - Dependabot::Nuget::FileParser.new(dependency_files: dependency_files, - source: source, - repo_contents_path: repo_contents_path).parse - Dependabot::Nuget::TfmFinder.frameworks(dependency) - end - - describe "#frameworks" do - context "when checking for a transitive dependency" do - let(:dependency_requirements) { [] } - let(:dependency_name) { "Microsoft.Extensions.DependencyModel" } - let(:dependency_version) { "1.1.1" } - - its(:length) { is_expected.to eq(2) } - end - - context "when checking for a top-level dependency" do - let(:dependency_requirements) do - [{ file: "my.csproj", requirement: "2.3.0", groups: ["dependencies"], source: nil }] - end - let(:dependency_name) { "Serilog" } - let(:dependency_version) { "2.3.0" } - - its(:length) { is_expected.to eq(1) } - end - end -end diff --git a/nuget/spec/dependabot/nuget/update_checker/version_finder_spec.rb b/nuget/spec/dependabot/nuget/update_checker/version_finder_spec.rb deleted file mode 100644 index 2230a9fa3b1..00000000000 --- a/nuget/spec/dependabot/nuget/update_checker/version_finder_spec.rb +++ /dev/null @@ -1,695 +0,0 @@ -# typed: false -# frozen_string_literal: true - -require "spec_helper" -require "dependabot/dependency" -require "dependabot/dependency_file" -require "dependabot/nuget/file_parser" -require "dependabot/nuget/update_checker/version_finder" -require "dependabot/nuget/update_checker/tfm_comparer" -require_relative "../nuget_search_stubs" - -RSpec.describe Dependabot::Nuget::UpdateChecker::VersionFinder do - RSpec.configure do |config| - config.include(NuGetSearchStubs) - end - - let(:repo_contents_path) { write_tmp_repo(dependency_files) } - let(:source) do - Dependabot::Source.new( - provider: "github", - repo: "gocardless/bump", - directory: "/" - ) - end - - let(:finder) do - Dependabot::Nuget::FileParser.new(dependency_files: dependency_files, - source: source, - repo_contents_path: repo_contents_path).parse - described_class.new( - dependency: dependency, - dependency_files: dependency_files, - credentials: credentials, - ignored_versions: ignored_versions, - raise_on_ignored: raise_on_ignored, - security_advisories: security_advisories, - repo_contents_path: repo_contents_path - ) - end - - let(:dependency) do - Dependabot::Dependency.new( - name: dependency_name, - version: dependency_version, - requirements: dependency_requirements, - package_manager: "nuget" - ) - end - - let(:dependency_requirements) do - [{ file: "my.csproj", requirement: "1.1.1", groups: ["dependencies"], source: nil }] - end - let(:dependency_name) { "Microsoft.Extensions.DependencyModel" } - let(:dependency_version) { "1.1.1" } - - let(:dependency_files) { [csproj] } - let(:csproj) do - Dependabot::DependencyFile.new(name: "my.csproj", content: csproj_body) - end - let(:csproj_body) { fixture("csproj", "basic.csproj") } - - let(:credentials) do - [{ - "type" => "git_source", - "host" => "github.com", - "username" => "x-access-token", - "password" => "token" - }] - end - let(:ignored_versions) { [] } - let(:raise_on_ignored) { false } - let(:security_advisories) { [] } - - let(:nuget_versions_url) do - "https://api.nuget.org/v3-flatcontainer/" \ - "microsoft.extensions.dependencymodel/index.json" - end - let(:nuget_search_url) do - "https://api.nuget.org/v3/registration5-gz-semver2/" \ - "microsoft.extensions.dependencymodel/index.json" - end - let(:version_class) { Dependabot::Nuget::Version } - let(:nuget_versions) { fixture("nuget_responses", "versions.json") } - let(:nuget_search_results) do - fixture("nuget_responses", "search_results.json") - end - let(:nuspec) do - fixture("nuspecs", "#{dependency_name}.#{dependency_version}.nuspec") - end - - let(:nuspec_url) do - "https://api.nuget.org/v3-flatcontainer/#{dependency_name.downcase}/#{dependency_version}/#{dependency_name.downcase}.nuspec" - end - - let(:version_instance) do - version_class.new(dependency_version) - end - - let(:expected_version_instance) do - version_class.new(expected_version) - end - - before do - stub_request(:get, nuget_versions_url) - .to_return(status: 200, body: nuget_versions) - stub_request(:get, nuget_search_url) - .to_return(status: 200, body: nuget_search_results) - end - - describe "#latest_version_details" do - subject(:latest_version_details) { finder.latest_version_details } - - let(:expected_version) { "2.1.0" } - let(:current_compatible) { true } - let(:expected_compatible) { true } - - before do - allow(finder).to receive(:str_version_compatible?).with(dependency_version.to_s).and_return(current_compatible) - allow(finder).to receive(:str_version_compatible?).with(expected_version.to_s).and_return(expected_compatible) - end - - its([:version]) { is_expected.to eq(expected_version_instance) } - - context "when the returned versions is prefixed with a zero-width char" do - let(:nuget_search_results) do - fixture("nuget_responses", "search_results_zero_width.json") - end - - its([:version]) { is_expected.to eq(expected_version_instance) } - end - - context "when the user wants a pre-release" do - let(:dependency_version) { "2.2.0-preview1-26216-03" } - let(:expected_version) { "2.2.0-preview2-26406-04" } - - its([:version]) do - is_expected.to eq(expected_version_instance) - end - - context "for a previous version" do - let(:dependency_version) { "2.1.0-preview1-26216-03" } - let(:expected_version) { "2.1.0" } - - its([:version]) do - is_expected.to eq(expected_version_instance) - end - end - end - - context "when the user wants a pre-release with wildcard" do - let(:dependency_version) { "*-*" } - let(:current_compatible) { false } - let(:dependency_requirements) do - [{ file: "my.csproj", requirement: "*-*", groups: ["dependencies"], source: nil }] - end - its([:version]) do - is_expected.to eq(version_class.new("2.2.0-preview2-26406-04")) - end - end - - context "when the user is using an unfound property" do - let(:dependency_version) { "$PackageVersion_LibGit2SharpNativeBinaries" } - its([:version]) { is_expected.to eq(version_class.new("2.1.0")) } - end - - context "raise_on_ignored when later versions are allowed" do - let(:raise_on_ignored) { true } - it "doesn't raise an error" do - expect { subject }.to_not raise_error - end - end - - context "when the user is on the latest version" do - let(:dependency_version) { "2.1.0" } - its([:version]) { is_expected.to eq(version_class.new("2.1.0")) } - - context "raise_on_ignored" do - let(:raise_on_ignored) { true } - it "doesn't raise an error" do - expect { subject }.to_not raise_error - end - end - end - - context "when the current version isn't known" do - let(:dependency_version) { nil } - let(:current_compatible) { false } - let(:expected_version) { nil } - let(:expected_compatible) { false } - - context "raise_on_ignored" do - let(:raise_on_ignored) { true } - it "doesn't raise an error" do - expect { subject }.to_not raise_error - end - end - end - - context "when the dependency is a git dependency" do - let(:dependency_version) { "a1b78a929dac93a52f08db4f2847d76d6cfe39bd" } - - context "raise_on_ignored" do - let(:raise_on_ignored) { true } - it "doesn't raise an error" do - expect { subject }.to_not raise_error - end - end - end - - context "when the user is ignoring all later versions" do - let(:ignored_versions) { ["> 1.1.1"] } - its([:version]) { is_expected.to eq(version_class.new("1.1.1")) } - - context "raise_on_ignored" do - let(:raise_on_ignored) { true } - it "raises an error" do - expect { subject }.to raise_error(Dependabot::AllVersionsIgnored) - end - end - end - - context "when the user is ignoring the latest version" do - let(:ignored_versions) { ["[2.a,3.0.0)"] } - let(:expected_version) { "1.1.2" } - its([:version]) { is_expected.to eq(expected_version_instance) } - end - - context "when a version range is specified using Ruby syntax" do - let(:ignored_versions) { [">= 2.a, < 3.0.0"] } - let(:expected_version) { "1.1.2" } - its([:version]) { is_expected.to eq(version_class.new("1.1.2")) } - end - - context "when the user has ignored all versions" do - let(:ignored_versions) { ["[0,)"] } - it "returns nil" do - expect(subject).to be_nil - end - - context "raise_on_ignored" do - let(:raise_on_ignored) { true } - it "raises an error" do - expect { subject }.to raise_error(Dependabot::AllVersionsIgnored) - end - end - end - - context "when an open version range is specified using Ruby syntax" do - let(:ignored_versions) { ["> 0"] } - it "returns nil" do - expect(subject).to be_nil - end - - context "raise_on_ignored" do - let(:raise_on_ignored) { true } - it "raises an error" do - expect { subject }.to raise_error(Dependabot::AllVersionsIgnored) - end - end - end - - context "with a custom repo in a nuget.config file" do - let(:config_file) do - Dependabot::DependencyFile.new( - name: "NuGet.Config", - content: fixture("configs", "nuget.config") - ) - end - let(:dependency_files) { [csproj, config_file] } - let(:custom_repo_url) do - "https://www.myget.org/F/exceptionless/api/v3/index.json" - end - let(:custom_nuget_search_url) do - "https://www.myget.org/F/exceptionless/api/v3/" \ - "registration1/microsoft.extensions.dependencymodel/index.json" - end - before do - stub_request(:get, nuget_versions_url).to_return(status: 404) - stub_request(:get, nuget_search_url).to_return(status: 404) - - stub_request(:get, custom_repo_url).to_return(status: 404) - stub_request(:get, custom_repo_url) - .with(basic_auth: %w(my passw0rd)) - .to_return( - status: 200, - body: fixture("nuget_responses", "myget_base.json") - ) - stub_request(:get, custom_nuget_search_url).to_return(status: 404) - stub_request(:get, custom_nuget_search_url) - .with(basic_auth: %w(my passw0rd)) - .to_return(status: 200, body: nuget_search_results) - end - - # skipped - # its([:version]) { is_expected.to eq(version_class.new("2.1.0")) } - - context "that uses the v2 API" do - let(:config_file) do - Dependabot::DependencyFile.new( - name: "NuGet.Config", - content: fixture("configs", "with_v2_endpoints.config") - ) - end - - let(:custom_v3_nuget_versions_url) do - "https://www.myget.org/F/exceptionless/api/v3/flatcontainer/" \ - "#{dependency_name}/index.json" - end - - let(:expected_version) { "4.8.1" } - - before do - v2_repo_urls = %w( - https://www.nuget.org/api/v2/ - https://www.myget.org/F/azure-appservice/api/v2 - https://www.myget.org/F/azure-appservice-staging/api/v2 - https://www.myget.org/F/fusemandistfeed/api/v2 - https://www.myget.org/F/30de4ee06dd54956a82013fa17a3accb/ - ) - - v2_repo_urls.each do |repo_url| - stub_request(:get, repo_url) - .to_return( - status: 200, - body: fixture("nuget_responses", "v2_base.xml") - ) - end - - url = "https://dotnet.myget.org/F/aspnetcore-dev/api/v3/index.json" - stub_request(:get, url) - .to_return( - status: 200, - body: fixture("nuget_responses", "myget_base.json") - ) - - stub_request(:get, custom_v3_nuget_versions_url) - .to_return(status: 404) - - custom_v2_nuget_versions_url = - "https://www.nuget.org/api/v2/FindPackagesById()?id=" \ - "'#{dependency_name}'" - stub_request(:get, custom_v2_nuget_versions_url) - .to_return( - status: 200, - body: fixture("nuget_responses", "v2_versions.xml") - ) - end - - its([:version]) { is_expected.to eq(expected_version_instance) } - end - end - - context "with a package that returns paginated api results when using the v2 nuget api", :vcr do - let(:dependency_files) { project_dependency_files("paginated_package_v2_api") } - let(:dependency_requirements) do - [{ file: "my.csproj", requirement: "4.7.1", groups: ["dependencies"], source: nil }] - end - let(:dependency_name) { "FakeItEasy" } - let(:dependency_version) { "4.7.1" } - let(:expected_version) { "7.3.0" } - - it "returns the expected version" do - expect(subject[:version]).to eq(expected_version_instance) - end - end - - context "with a custom repo in the credentials", :vcr do - let(:credentials) do - [{ - "type" => "git_source", - "host" => "github.com", - "username" => "x-access-token", - "password" => "token" - }, { - "type" => "nuget_feed", - "url" => custom_repo_url, - "token" => "my:passw0rd" - }] - end - - let(:nuget_versions) { fixture("nuget_responses", "versions.json") } - - let(:nuget_search_results) do - fixture("nuget_responses", "search_results.json") - end - - let(:custom_repo_url) do - "https://www.myget.org/F/exceptionless/api/v3/index.json" - end - let(:custom_nuget_search_url) do - "https://www.myget.org/F/exceptionless/api/v3/" \ - "registration1/microsoft.extensions.dependencymodel/index.json" - end - - before do - stub_request(:get, nuget_versions_url).to_return(status: 404) - stub_request(:get, nuget_search_url).to_return(status: 404) - - stub_request(:get, custom_repo_url).to_return(status: 404) - stub_request(:get, custom_repo_url) - .with(basic_auth: %w(my passw0rd)) - .to_return( - status: 200, - body: fixture("nuget_responses", "myget_base.json") - ) - - stub_request(:get, custom_nuget_search_url).to_return(status: 404) - stub_request(:get, custom_nuget_search_url) - .with(basic_auth: %w(my passw0rd)) - .to_return(status: 200, body: nuget_search_results) - end - - its([:version]) { is_expected.to eq(version_class.new("2.1.0")) } - - context "that does not return PackageBaseAddress" do - let(:custom_repo_url) { "http://www.myget.org/artifactory/api/nuget/v3/dependabot-nuget-local" } - before do - stub_request(:get, custom_repo_url) - .with(basic_auth: %w(admin password)) - .to_return( - status: 200, - body: fixture("nuget_responses", "artifactory_base.json") - ) - end - - its([:version]) { is_expected.to eq(version_class.new("2.1.0")) } - end - end - - context "with a version range specified" do - let(:dependency_files) { project_dependency_files("version_range") } - let(:dependency_version) { "1.1.0" } - let(:dependency_requirements) do - [{ file: "my.csproj", requirement: "[1.1.0, 3.0.0)", groups: ["dependencies"], source: nil }] - end - - its([:version]) { is_expected.to eq(version_class.new("2.1.0")) } - end - - context "with an open upper version range specified" do - let(:dependency_files) { project_dependency_files("open_upper_version_range") } - let(:dependency_version) { "1.1.0" } - let(:dependency_requirements) do - [{ file: "my.csproj", requirement: "[1.1.0-alpha,", groups: ["dependencies"], source: nil }] - end - - its([:version]) { is_expected.to eq(version_class.new("2.1.0")) } - end - - context "with a package that is implicitly referenced", :vcr do - let(:dependency_files) { project_dependency_files("implicit_reference") } - let(:dependency_requirements) do - [{ file: "implicitReference.csproj", requirement: "1.1.2-beta1.22511.2", groups: ["dependencies"], - source: nil }] - end - let(:dependency_name) { "NuGet.Protocol" } - let(:dependency_version) { "6.3.0" } - - # skipped - # it "returns the expected version" do - # expect(subject[:version]).to eq(version_class.new("6.5.0")) - # end - end - - context "when the package can't be meaninfully sorted by just version" do - before do - allow(finder).to receive(:str_version_compatible?).and_call_original - reported_versions = [ - "2.6.1", - "2.7.1", - "3.4.0", - "3.14.0", - "4.0.1" - ] - stub_request(:get, "https://api.nuget.org/v3/registration5-gz-semver2/nunit/index.json") - .to_return( - status: 200, - body: { - items: [ - items: reported_versions.map { |v| { catalogEntry: { listed: true, version: v } } } - ] - }.to_json - ) - stub_request(:get, "https://api.nuget.org/v3-flatcontainer/nunit/3.14.0/nunit.nuspec") - .to_return(status: 200, body: fixture("nuspecs", "nunit.3.14.0_faked.nuspec")) - stub_request(:get, "https://api.nuget.org/v3-flatcontainer/nunit/4.0.1/nunit.nuspec") - .to_return(status: 200, body: fixture("nuspecs", "nunit.4.0.1_faked.nuspec")) - end - - let(:csproj_body) do - <<~XML - - - netcoreapp3.1 - - - - - - XML - end - let(:expected_version) { version_class.new("3.14.0") } - let(:dependency_version) { "3.14.0" } - let(:dependency) do - Dependabot::Dependency.new( - name: "nunit", - version: dependency_version, - requirements: [{ file: "my.csproj", requirement: "3.14.0", groups: ["dependencies"], source: nil }], - package_manager: "nuget" - ) - end - - it "returns the expected version" do - expect(subject[:version]).to eq(version_class.new("3.14.0")) - end - end - - context "when `packageSourceMapping`s are specified" do - let(:csproj_body) do - <<~XML - - - net8.0 - - - - - - XML - end - let(:config_file) do - Dependabot::DependencyFile.new( - name: "NuGet.Config", - content: - <<~XML - - - - - - - - - - - - - - - - - - XML - ) - end - let(:dependency_files) { [csproj, config_file] } - let(:dependency) do - Dependabot::Dependency.new( - name: "Some.Package", - version: "1.0.0", - requirements: [{ file: "my.csproj", requirement: "1.0.0", groups: ["dependencies"], source: nil }], - package_manager: "nuget" - ) - end - let(:expected_version) { version_class.new("1.1.0") } - - def create_nupkg(nuspec_name, nuspec_content) - content = Zip::OutputStream.write_buffer do |zio| - zio.put_next_entry("#{nuspec_name}.nuspec") - zio.write(nuspec_content) - end - content.rewind - content.sysread - end - - before do - allow(finder).to receive(:str_version_compatible?).and_call_original - - # stub source 1 - stub_index_json("https://nuget.example.com/source1/index.json") - stub_request(:get, "https://nuget.example.com/source1/RegistrationsBaseUrl/some.package/index.json") - .to_return( - status: 200, - body: { - count: 1, - items: [ - { - count: 2, - items: [ - { - catalogEntry: { - id: "Some.Package", - version: "1.0.0" # this is what's currently installed - } - }, - { - catalogEntry: { - id: "Some.Package", - version: "1.1.0" # this is what we'd like to upgrade to - } - } - ] - } - ] - }.to_json - ) - stub_request(:get, "https://nuget.example.com/source1/PackageBaseAddress/some.package/1.0.0/some.package.1.0.0.nupkg") - .to_return( - status: 200, - body: create_nupkg( - "Some.Package", - <<~XML - - - - - - - - XML - ) - ) - stub_request(:get, "https://nuget.example.com/source1/PackageBaseAddress/some.package/1.1.0/some.package.1.1.0.nupkg") - .to_return( - status: 200, - body: create_nupkg( - "Some.Package", - <<~XML - - - - - - - - XML - ) - ) - # none of the `source2` URLs should be called - end - - it "returns the expected version honoring the package source mapping" do - expect(subject[:version]).to eq(version_class.new("1.1.0")) - end - end - end - - describe "#lowest_security_fix_version_details" do - subject(:lowest_security_fix_version_details) do - finder.lowest_security_fix_version_details - end - - let(:dependency_version) { "1.1.1" } - let(:security_advisories) do - [ - Dependabot::SecurityAdvisory.new( - dependency_name: "rails", - package_manager: "nuget", - vulnerable_versions: ["< 2.0.0"] - ) - ] - end - - let(:expected_version) { "2.0.0" } - - before do - allow(finder).to receive(:str_version_compatible?).with(dependency_version.to_s).and_return(true) - allow(finder).to receive(:str_version_compatible?).with(expected_version.to_s).and_return(true) - end - - its([:version]) { is_expected.to eq(version_class.new("2.0.0")) } - - context "when the user is ignoring the lowest version" do - let(:ignored_versions) { [">= 2.a, <= 2.0.0"] } - let(:expected_version) { "2.0.3" } - its([:version]) { is_expected.to eq(version_class.new("2.0.3")) } - end - end - - describe "#versions" do - subject(:versions) { finder.versions } - - it "includes the correct versions" do - expect(versions.count).to eq(21) - expect(versions.first).to eq( - nuspec_url: "https://api.nuget.org/v3-flatcontainer/" \ - "microsoft.extensions.dependencymodel/1.0.0-rc2-002702/" \ - "microsoft.extensions.dependencymodel.nuspec", - repo_url: "https://api.nuget.org/v3/index.json", - source_url: nil, - version: Dependabot::Nuget::Version.new("1.0.0-rc2-002702") - ) - end - end -end diff --git a/nuget/spec/dependabot/nuget/update_checker_spec.rb b/nuget/spec/dependabot/nuget/update_checker_spec.rb index f04c5da99a3..a8877bddfda 100644 --- a/nuget/spec/dependabot/nuget/update_checker_spec.rb +++ b/nuget/spec/dependabot/nuget/update_checker_spec.rb @@ -4,13 +4,28 @@ require "spec_helper" require "dependabot/dependency" require "dependabot/dependency_file" +require "dependabot/nuget/file_parser" require "dependabot/nuget/update_checker" require "dependabot/nuget/version" require_common_spec "update_checkers/shared_examples_for_update_checkers" + RSpec.describe Dependabot::Nuget::UpdateChecker do it_behaves_like "an update checker" + let(:repo_contents_path) { write_tmp_repo(dependency_files) } + let(:source) do + Dependabot::Source.new( + provider: "github", + repo: "gocardless/bump", + directory: "/" + ) + end + let(:checker) do + # We have to run the FileParser first to ensure the dicovery.json is generated. + Dependabot::Nuget::FileParser.new(dependency_files: dependency_files, + source: source, + repo_contents_path: repo_contents_path).parse described_class.new( dependency: dependency, dependency_files: dependency_files,