dependabot-nuget 0.237.0 → 0.238.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/lib/dependabot/nuget/cache_manager.rb +22 -0
- data/lib/dependabot/nuget/file_fetcher/import_paths_finder.rb +15 -0
- data/lib/dependabot/nuget/file_fetcher.rb +65 -61
- data/lib/dependabot/nuget/file_parser/dotnet_tools_json_parser.rb +2 -1
- data/lib/dependabot/nuget/file_parser/global_json_parser.rb +2 -1
- data/lib/dependabot/nuget/file_parser/packages_config_parser.rb +22 -4
- data/lib/dependabot/nuget/file_parser/project_file_parser.rb +287 -15
- data/lib/dependabot/nuget/file_parser/property_value_finder.rb +24 -52
- data/lib/dependabot/nuget/file_parser.rb +4 -1
- data/lib/dependabot/nuget/file_updater.rb +123 -117
- data/lib/dependabot/nuget/native_helpers.rb +94 -0
- data/lib/dependabot/nuget/update_checker/compatibility_checker.rb +85 -0
- data/lib/dependabot/nuget/update_checker/dependency_finder.rb +228 -0
- data/lib/dependabot/nuget/update_checker/nupkg_fetcher.rb +114 -0
- data/lib/dependabot/nuget/update_checker/nuspec_fetcher.rb +86 -0
- data/lib/dependabot/nuget/update_checker/property_updater.rb +30 -3
- data/lib/dependabot/nuget/update_checker/repository_finder.rb +32 -10
- data/lib/dependabot/nuget/update_checker/tfm_comparer.rb +31 -0
- data/lib/dependabot/nuget/update_checker/tfm_finder.rb +127 -0
- data/lib/dependabot/nuget/update_checker/version_finder.rb +47 -6
- data/lib/dependabot/nuget/update_checker.rb +42 -8
- data/lib/dependabot/nuget.rb +2 -0
- metadata +33 -7
- data/lib/dependabot/nuget/file_updater/packages_config_declaration_finder.rb +0 -70
- data/lib/dependabot/nuget/file_updater/project_file_declaration_finder.rb +0 -183
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 4d913e6e79cd35b4a00551789e2d9fbea3a71476b76a12f64adfc3427cf419b1
|
4
|
+
data.tar.gz: 103b3ed625f8a89133b2c53b6a49941826cf3663de6897e9baad943a78fa37c7
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: c820263ed7825b8f7270693513d8ebab3ee73169318ca5113c75cad689887b5b42c1731fd6496e12033ba7a3ff0d3a59752b7bc512e64ae93baf4a520d485a83
|
7
|
+
data.tar.gz: 7ce94d621ef880f809124364816e19aa8cb1fe1975967d8eb907cf40b1573ff2c3fe4c8fad91631f5f545433813252736c3c1db17228366dea8950f0ab50ac9a
|
@@ -0,0 +1,22 @@
|
|
1
|
+
# typed: true
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
require "dependabot/file_fetchers"
|
5
|
+
require "dependabot/file_fetchers/base"
|
6
|
+
require "set"
|
7
|
+
|
8
|
+
module Dependabot
|
9
|
+
module Nuget
|
10
|
+
class CacheManager
|
11
|
+
def self.caching_disabled?
|
12
|
+
ENV["DEPENDABOT_NUGET_CACHE_DISABLED"] == "true"
|
13
|
+
end
|
14
|
+
|
15
|
+
def self.cache(name)
|
16
|
+
@cache ||= {}
|
17
|
+
@cache[name] ||= {}
|
18
|
+
@cache[name]
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -39,6 +39,21 @@ module Dependabot
|
|
39
39
|
nodes.compact
|
40
40
|
end
|
41
41
|
|
42
|
+
def project_file_paths
|
43
|
+
doc = Nokogiri::XML(project_file.content)
|
44
|
+
doc.remove_namespaces!
|
45
|
+
nodes = doc.xpath("/Project/ItemGroup/ProjectFile").map do |node|
|
46
|
+
attribute = node.attribute("Include")
|
47
|
+
next unless attribute
|
48
|
+
|
49
|
+
path = attribute.value.strip.tr("\\", "/")
|
50
|
+
path = File.join(current_dir, path) unless current_dir.nil?
|
51
|
+
Pathname.new(path).cleanpath.to_path
|
52
|
+
end
|
53
|
+
|
54
|
+
nodes.compact
|
55
|
+
end
|
56
|
+
|
42
57
|
private
|
43
58
|
|
44
59
|
attr_reader :project_file
|
@@ -15,22 +15,27 @@ module Dependabot
|
|
15
15
|
require_relative "file_fetcher/import_paths_finder"
|
16
16
|
require_relative "file_fetcher/sln_project_paths_finder"
|
17
17
|
|
18
|
+
BUILD_FILE_NAMES = /^Directory\.Build\.(props|targets)$/i # Directory.Build.props, Directory.Build.targets
|
19
|
+
|
18
20
|
def self.required_files_in?(filenames)
|
19
21
|
return true if filenames.any? { |f| f.match?(/^packages\.config$/i) }
|
20
22
|
return true if filenames.any? { |f| f.end_with?(".sln") }
|
21
23
|
return true if filenames.any? { |f| f.match?("^src$") }
|
24
|
+
return true if filenames.any? { |f| f.end_with?(".proj") }
|
22
25
|
|
23
26
|
filenames.any? { |name| name.match?(%r{^[^/]*\.[a-z]{2}proj$}) }
|
24
27
|
end
|
25
28
|
|
26
29
|
def self.required_files_message
|
27
|
-
"Repo must contain a .(cs|vb|fs)proj file or a packages.config."
|
30
|
+
"Repo must contain a .proj file, .(cs|vb|fs)proj file, or a packages.config."
|
28
31
|
end
|
29
32
|
|
33
|
+
# rubocop:disable Metrics/AbcSize
|
30
34
|
sig { override.returns(T::Array[DependencyFile]) }
|
31
35
|
def fetch_files
|
32
36
|
fetched_files = []
|
33
37
|
fetched_files += project_files
|
38
|
+
fetched_files += project_files.filter_map { |f| directory_packages_props_file_from_project_file(f) }
|
34
39
|
fetched_files += directory_build_files
|
35
40
|
fetched_files += imported_property_files
|
36
41
|
|
@@ -40,7 +45,10 @@ module Dependabot
|
|
40
45
|
fetched_files << dotnet_tools_json if dotnet_tools_json
|
41
46
|
fetched_files << packages_props if packages_props
|
42
47
|
|
43
|
-
|
48
|
+
# dedup files based on their absolute path
|
49
|
+
fetched_files = fetched_files.uniq do |fetched_file|
|
50
|
+
Pathname.new(File.join(fetched_file.directory, fetched_file.name)).cleanpath.to_path
|
51
|
+
end
|
44
52
|
|
45
53
|
if project_files.none? && packages_config_files.none?
|
46
54
|
raise @missing_sln_project_file_errors.first if @missing_sln_project_file_errors&.any?
|
@@ -53,6 +61,7 @@ module Dependabot
|
|
53
61
|
|
54
62
|
fetched_files
|
55
63
|
end
|
64
|
+
# rubocop:enable Metrics/AbcSize
|
56
65
|
|
57
66
|
private
|
58
67
|
|
@@ -60,10 +69,9 @@ module Dependabot
|
|
60
69
|
@project_files ||=
|
61
70
|
begin
|
62
71
|
project_files = []
|
63
|
-
project_files
|
64
|
-
project_files
|
65
|
-
project_files
|
66
|
-
project_files << directory_packages_props_file if directory_packages_props_file
|
72
|
+
project_files += csproj_file
|
73
|
+
project_files += vbproj_file
|
74
|
+
project_files += fsproj_file
|
67
75
|
|
68
76
|
project_files += sln_project_files
|
69
77
|
project_files
|
@@ -112,49 +120,37 @@ module Dependabot
|
|
112
120
|
@directory_build_files ||= fetch_directory_build_files
|
113
121
|
end
|
114
122
|
|
123
|
+
# rubocop:disable Metrics/AbcSize
|
115
124
|
def fetch_directory_build_files
|
116
|
-
|
125
|
+
attempted_dirs = []
|
117
126
|
directory_build_files = []
|
118
|
-
|
119
|
-
|
120
|
-
#
|
121
|
-
project_files.map { |f| File.dirname(f.name) }.uniq.
|
122
|
-
|
123
|
-
|
124
|
-
|
127
|
+
directory_path = Pathname.new(directory)
|
128
|
+
|
129
|
+
# find all build files (Directory.Build.props/.targets) relative to the given project file
|
130
|
+
project_files.map { |f| File.dirname(File.join(f.directory, f.name)) }.uniq.each do |dir|
|
131
|
+
# Simulate MSBuild walking up the directory structure looking for a file
|
132
|
+
possible_dirs = dir.split("/").map.with_index do |_, i|
|
133
|
+
candidate_dir = dir.split("/").first(i + 1).join("/")
|
134
|
+
candidate_dir = "/#{candidate_dir}" unless candidate_dir.start_with?("/")
|
135
|
+
candidate_dir
|
125
136
|
end.reverse
|
126
137
|
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
break if attempted_paths.include?(path)
|
138
|
-
|
139
|
-
attempted_paths << path
|
140
|
-
file = fetch_file_if_present(path)
|
141
|
-
directory_build_files << file if file
|
138
|
+
possible_dirs.each do |possible_dir|
|
139
|
+
break if attempted_dirs.include?(possible_dir)
|
140
|
+
|
141
|
+
attempted_dirs << possible_dir
|
142
|
+
relative_possible_dir = Pathname.new(possible_dir).relative_path_from(directory_path).to_s
|
143
|
+
build_files = repo_contents(dir: relative_possible_dir).select { |f| f.name.match?(BUILD_FILE_NAMES) }
|
144
|
+
directory_build_files += build_files.map do |file|
|
145
|
+
possible_file = File.join(relative_possible_dir, file.name).delete_prefix("/")
|
146
|
+
fetch_file_from_host(possible_file)
|
147
|
+
end
|
142
148
|
end
|
143
149
|
end
|
144
150
|
|
145
151
|
directory_build_files
|
146
152
|
end
|
147
|
-
|
148
|
-
def possible_build_file_paths(base)
|
149
|
-
[
|
150
|
-
Pathname.new(base + "/Directory.Build.props").cleanpath.to_path,
|
151
|
-
Pathname.new(base + "/Directory.build.props").cleanpath.to_path,
|
152
|
-
Pathname.new(base + "/Directory.Packages.props").cleanpath.to_path,
|
153
|
-
Pathname.new(base + "/Directory.packages.props").cleanpath.to_path,
|
154
|
-
Pathname.new(base + "/Directory.Build.targets").cleanpath.to_path,
|
155
|
-
Pathname.new(base + "/Directory.build.targets").cleanpath.to_path
|
156
|
-
]
|
157
|
-
end
|
153
|
+
# rubocop:enable Metrics/AbcSize
|
158
154
|
|
159
155
|
def sln_project_files
|
160
156
|
return [] unless sln_files
|
@@ -189,35 +185,42 @@ module Dependabot
|
|
189
185
|
end
|
190
186
|
|
191
187
|
def csproj_file
|
192
|
-
@csproj_file ||=
|
193
|
-
begin
|
194
|
-
file = repo_contents.find { |f| f.name.end_with?(".csproj") }
|
195
|
-
fetch_file_from_host(file.name) if file
|
196
|
-
end
|
188
|
+
@csproj_file ||= find_and_fetch_with_suffix(".csproj")
|
197
189
|
end
|
198
190
|
|
199
191
|
def vbproj_file
|
200
|
-
@vbproj_file ||=
|
201
|
-
begin
|
202
|
-
file = repo_contents.find { |f| f.name.end_with?(".vbproj") }
|
203
|
-
fetch_file_from_host(file.name) if file
|
204
|
-
end
|
192
|
+
@vbproj_file ||= find_and_fetch_with_suffix(".vbproj")
|
205
193
|
end
|
206
194
|
|
207
195
|
def fsproj_file
|
208
|
-
@fsproj_file ||=
|
209
|
-
begin
|
210
|
-
file = repo_contents.find { |f| f.name.end_with?(".fsproj") }
|
211
|
-
fetch_file_from_host(file.name) if file
|
212
|
-
end
|
196
|
+
@fsproj_file ||= find_and_fetch_with_suffix(".fsproj")
|
213
197
|
end
|
214
198
|
|
215
|
-
def
|
216
|
-
|
217
|
-
|
218
|
-
|
219
|
-
|
199
|
+
def directory_packages_props_file_from_project_file(project_file)
|
200
|
+
# walk up the tree from each project file stopping at the first `Directory.Packages.props` file found
|
201
|
+
# https://learn.microsoft.com/en-us/nuget/consume-packages/central-package-management#central-package-management-rules
|
202
|
+
|
203
|
+
found_directory_packages_props_file = nil
|
204
|
+
directory_path = Pathname.new(directory)
|
205
|
+
full_project_dir = File.dirname(File.join(project_file.directory, project_file.name))
|
206
|
+
full_project_dir.split("/").each.with_index do |_, i|
|
207
|
+
break if found_directory_packages_props_file
|
208
|
+
|
209
|
+
base = full_project_dir.split("/").first(i + 1).join("/")
|
210
|
+
candidate_file_path = Pathname.new(base + "/Directory.Packages.props").cleanpath.to_path
|
211
|
+
candidate_directory = Pathname.new(File.dirname(candidate_file_path))
|
212
|
+
relative_candidate_directory = candidate_directory.relative_path_from(directory_path)
|
213
|
+
candidate_file = repo_contents(dir: relative_candidate_directory).find do |f|
|
214
|
+
f.name.casecmp?("Directory.Packages.props")
|
220
215
|
end
|
216
|
+
found_directory_packages_props_file = fetch_file_from_host(candidate_file.name) if candidate_file
|
217
|
+
end
|
218
|
+
|
219
|
+
found_directory_packages_props_file
|
220
|
+
end
|
221
|
+
|
222
|
+
def find_and_fetch_with_suffix(suffix)
|
223
|
+
repo_contents.select { |f| f.name.end_with?(suffix) }.map { |f| fetch_file_from_host(f.name) }
|
221
224
|
end
|
222
225
|
|
223
226
|
def nuget_config_files
|
@@ -286,7 +289,8 @@ module Dependabot
|
|
286
289
|
def fetch_imported_property_files(file:, previously_fetched_files:)
|
287
290
|
paths =
|
288
291
|
ImportPathsFinder.new(project_file: file).import_paths +
|
289
|
-
ImportPathsFinder.new(project_file: file).project_reference_paths
|
292
|
+
ImportPathsFinder.new(project_file: file).project_reference_paths +
|
293
|
+
ImportPathsFinder.new(project_file: file).project_file_paths
|
290
294
|
|
291
295
|
paths.flat_map do |path|
|
292
296
|
next if previously_fetched_files.map(&:name).include?(path)
|
@@ -51,7 +51,8 @@ module Dependabot
|
|
51
51
|
attr_reader :dotnet_tools_json
|
52
52
|
|
53
53
|
def parsed_dotnet_tools_json
|
54
|
-
|
54
|
+
# Remove BOM if present as JSON should be UTF-8
|
55
|
+
@parsed_dotnet_tools_json ||= JSON.parse(dotnet_tools_json.content.delete_prefix("\uFEFF"))
|
55
56
|
rescue JSON::ParserError
|
56
57
|
raise Dependabot::DependencyFileNotParseable, dotnet_tools_json.path
|
57
58
|
end
|
@@ -48,7 +48,8 @@ module Dependabot
|
|
48
48
|
attr_reader :global_json
|
49
49
|
|
50
50
|
def parsed_global_json
|
51
|
-
|
51
|
+
# Remove BOM if present as JSON should be UTF-8
|
52
|
+
@parsed_global_json ||= JSON.parse(global_json.content.delete_prefix("\uFEFF"))
|
52
53
|
rescue JSON::ParserError
|
53
54
|
raise Dependabot::DependencyFileNotParseable, global_json.path
|
54
55
|
end
|
@@ -5,6 +5,7 @@ require "nokogiri"
|
|
5
5
|
|
6
6
|
require "dependabot/dependency"
|
7
7
|
require "dependabot/nuget/file_parser"
|
8
|
+
require "dependabot/nuget/cache_manager"
|
8
9
|
|
9
10
|
# For details on packages.config files see:
|
10
11
|
# https://docs.microsoft.com/en-us/nuget/reference/packages-config
|
@@ -16,11 +17,32 @@ module Dependabot
|
|
16
17
|
|
17
18
|
DEPENDENCY_SELECTOR = "packages > package"
|
18
19
|
|
20
|
+
def self.dependency_set_cache
|
21
|
+
CacheManager.cache("packages_config_dependency_set")
|
22
|
+
end
|
23
|
+
|
19
24
|
def initialize(packages_config:)
|
20
25
|
@packages_config = packages_config
|
21
26
|
end
|
22
27
|
|
23
28
|
def dependency_set
|
29
|
+
return parse_dependencies if CacheManager.caching_disabled?
|
30
|
+
|
31
|
+
key = "#{packages_config.name.downcase}::#{packages_config.content.hash}"
|
32
|
+
cache = PackagesConfigParser.dependency_set_cache
|
33
|
+
|
34
|
+
cache[key] ||= parse_dependencies
|
35
|
+
|
36
|
+
dependency_set = Dependabot::FileParsers::Base::DependencySet.new
|
37
|
+
dependency_set += cache[key]
|
38
|
+
dependency_set
|
39
|
+
end
|
40
|
+
|
41
|
+
private
|
42
|
+
|
43
|
+
attr_reader :packages_config
|
44
|
+
|
45
|
+
def parse_dependencies
|
24
46
|
dependency_set = Dependabot::FileParsers::Base::DependencySet.new
|
25
47
|
|
26
48
|
doc = Nokogiri::XML(packages_config.content)
|
@@ -43,10 +65,6 @@ module Dependabot
|
|
43
65
|
dependency_set
|
44
66
|
end
|
45
67
|
|
46
|
-
private
|
47
|
-
|
48
|
-
attr_reader :packages_config
|
49
|
-
|
50
68
|
def dependency_name(dependency_node)
|
51
69
|
dependency_node.attribute("id")&.value&.strip ||
|
52
70
|
dependency_node.at_xpath("./id")&.content&.strip
|