dependabot-nuget 0.287.0 → 0.289.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.
Files changed (88) hide show
  1. checksums.yaml +4 -4
  2. data/helpers/lib/NuGetUpdater/.gitignore +1 -0
  3. data/helpers/lib/NuGetUpdater/Directory.Build.targets +17 -0
  4. data/helpers/lib/NuGetUpdater/Directory.Packages.props +26 -17
  5. data/helpers/lib/NuGetUpdater/NuGetProjects/NuGet.Packaging/NuGet.Packaging.csproj +0 -1
  6. data/helpers/lib/NuGetUpdater/NuGetUpdater.Cli/Commands/DiscoverCommand.cs +7 -3
  7. data/helpers/lib/NuGetUpdater/NuGetUpdater.Cli/Commands/RunCommand.cs +1 -1
  8. data/helpers/lib/NuGetUpdater/NuGetUpdater.Cli.Test/EntryPointTests.Analyze.cs +3 -1
  9. data/helpers/lib/NuGetUpdater/NuGetUpdater.Cli.Test/EntryPointTests.Discover.cs +88 -47
  10. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Analyze/AnalyzeWorker.cs +31 -16
  11. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Analyze/CompatabilityChecker.cs +1 -1
  12. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Analyze/RequirementArrayConverter.cs +39 -0
  13. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Analyze/VersionFinder.cs +1 -1
  14. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Clone/ShellGitCommandHandler.cs +1 -1
  15. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/DependencyDiscovery.props +7 -0
  16. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/DependencyDiscovery.targets +10 -0
  17. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Discover/DiscoveryWorker.cs +64 -53
  18. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Discover/DotNetToolsJsonDiscovery.cs +2 -2
  19. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Discover/GlobalJsonDiscovery.cs +2 -2
  20. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Discover/PackagesConfigDiscovery.cs +17 -5
  21. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Discover/PackagesConfigDiscoveryResult.cs +3 -1
  22. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Discover/ProjectDiscoveryResult.cs +3 -0
  23. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Discover/SdkProjectDiscovery.cs +429 -12
  24. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Discover/WorkspaceDiscoveryResult.cs +0 -1
  25. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/ExperimentsManager.cs +12 -2
  26. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Files/JsonBuildFile.cs +1 -1
  27. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/FrameworkChecker/CompatabilityChecker.cs +2 -2
  28. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/NuGetUpdater.Core.csproj +7 -2
  29. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Run/ApiModel/Job.cs +23 -0
  30. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Run/RunWorker.cs +43 -58
  31. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/TargetFrameworkReporter.targets +13 -0
  32. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Updater/BindingRedirectManager.cs +13 -43
  33. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Updater/DotNetToolsJsonUpdater.cs +4 -4
  34. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Updater/GlobalJsonUpdater.cs +5 -5
  35. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Updater/LockFileUpdater.cs +3 -10
  36. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Updater/PackageReferenceUpdater.cs +40 -33
  37. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Updater/PackagesConfigUpdater.cs +12 -11
  38. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Updater/UpdaterWorker.cs +16 -12
  39. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Utilities/CollectionExtensions.cs +17 -0
  40. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Utilities/ConsoleLogger.cs +1 -1
  41. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Utilities/DependencyConflictResolver.cs +19 -19
  42. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Utilities/ILogger.cs +11 -1
  43. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Utilities/MSBuildHelper.cs +74 -20
  44. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Utilities/NuGetHelper.cs +1 -17
  45. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Utilities/PathComparer.cs +31 -0
  46. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Utilities/PathHelper.cs +46 -10
  47. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Utilities/ProjectHelper.cs +96 -0
  48. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Analyze/AnalyzeWorkerTests.cs +135 -3
  49. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Discover/DiscoveryWorkerTestBase.cs +71 -38
  50. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Discover/DiscoveryWorkerTests.PackagesConfig.cs +66 -4
  51. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Discover/DiscoveryWorkerTests.Proj.cs +11 -5
  52. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Discover/DiscoveryWorkerTests.Project.cs +808 -222
  53. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Discover/DiscoveryWorkerTests.cs +477 -97
  54. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Discover/ExpectedDiscoveryResults.cs +5 -9
  55. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Discover/SdkProjectDiscoveryTests.cs +494 -0
  56. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/MockNuGetPackage.cs +46 -1
  57. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/NuGetUpdater.Core.Test.csproj +0 -1
  58. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Run/RunWorkerTests.cs +401 -77
  59. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Run/SerializationTests.cs +35 -2
  60. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Run/UpdatedDependencyListTests.cs +60 -2
  61. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/TemporaryDirectory.cs +3 -2
  62. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/TestLogger.cs +1 -1
  63. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Update/BindingRedirectsTests.cs +1 -1
  64. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Update/UpdateWorkerTestBase.cs +8 -4
  65. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Update/UpdateWorkerTests.PackageReference.cs +40 -0
  66. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Update/UpdateWorkerTests.PackagesConfig.cs +1 -1
  67. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Utilities/AssertEx.cs +1 -1
  68. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Utilities/LinuxOnlyAttribute.cs +12 -0
  69. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Utilities/MSBuildHelperTests.cs +8 -5
  70. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Utilities/PathHelperTests.cs +49 -3
  71. data/lib/dependabot/nuget/analysis/analysis_json_reader.rb +3 -1
  72. data/lib/dependabot/nuget/file_fetcher.rb +12 -393
  73. data/lib/dependabot/nuget/file_parser.rb +23 -54
  74. data/lib/dependabot/nuget/file_updater.rb +21 -16
  75. data/lib/dependabot/nuget/native_discovery/native_dependency_file_discovery.rb +2 -9
  76. data/lib/dependabot/nuget/native_discovery/native_discovery_json_reader.rb +183 -80
  77. data/lib/dependabot/nuget/native_discovery/native_project_discovery.rb +25 -3
  78. data/lib/dependabot/nuget/native_discovery/native_workspace_discovery.rb +1 -11
  79. data/lib/dependabot/nuget/native_helpers.rb +13 -4
  80. data/lib/dependabot/nuget/native_update_checker/native_update_checker.rb +17 -4
  81. metadata +15 -12
  82. data/helpers/lib/NuGetUpdater/NuGetProjects/Directory.Packages.props +0 -29
  83. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Analyze/RequirementConverter.cs +0 -17
  84. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Discover/DirectoryPackagesPropsDiscovery.cs +0 -69
  85. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Discover/DirectoryPackagesPropsDiscoveryResult.cs +0 -11
  86. data/lib/dependabot/nuget/file_fetcher/import_paths_finder.rb +0 -73
  87. data/lib/dependabot/nuget/file_fetcher/sln_project_paths_finder.rb +0 -60
  88. data/lib/dependabot/nuget/native_discovery/native_directory_packages_props_discovery.rb +0 -44
@@ -1,9 +1,10 @@
1
- # typed: strict
1
+ # typed: strong
2
2
  # frozen_string_literal: true
3
3
 
4
4
  require "dependabot/file_fetchers"
5
5
  require "dependabot/file_fetchers/base"
6
- require "dependabot/nuget/cache_manager"
6
+ require "dependabot/nuget/native_discovery/native_discovery_json_reader"
7
+ require "dependabot/nuget/native_helpers"
7
8
  require "set"
8
9
  require "sorbet-runtime"
9
10
 
@@ -13,410 +14,28 @@ module Dependabot
13
14
  extend T::Sig
14
15
  extend T::Helpers
15
16
 
16
- require_relative "file_fetcher/import_paths_finder"
17
- require_relative "file_fetcher/sln_project_paths_finder"
18
-
19
- BUILD_FILE_NAMES = /^Directory\.Build\.(props|targets)$/i # Directory.Build.props, Directory.Build.targets
20
-
21
17
  sig { override.params(filenames: T::Array[String]).returns(T::Boolean) }
22
18
  def self.required_files_in?(filenames)
23
- return true if filenames.any? { |f| f.match?(/^packages\.config$/i) }
24
- return true if filenames.any? { |f| f.end_with?(".sln") }
25
- return true if filenames.any? { |f| f.match?("^src$") }
26
- return true if filenames.any? { |f| f.end_with?(".proj") }
27
-
28
19
  filenames.any? { |name| name.match?(/\.(cs|vb|fs)proj$/) }
29
20
  end
30
21
 
31
22
  sig { override.returns(String) }
32
23
  def self.required_files_message
33
- "Repo must contain a .proj file, .(cs|vb|fs)proj file, or a packages.config."
34
- end
35
-
36
- sig do
37
- override
38
- .params(
39
- source: Dependabot::Source,
40
- credentials: T::Array[Credential],
41
- repo_contents_path: T.nilable(String),
42
- options: T::Hash[String, String]
43
- ).void
44
- end
45
- def initialize(source:, credentials:, repo_contents_path: nil, options: {})
46
- super
47
-
48
- @sln_files = T.let(nil, T.nilable(T::Array[Dependabot::DependencyFile]))
49
- @sln_project_files = T.let(nil, T.nilable(T::Array[Dependabot::DependencyFile]))
50
- @project_files = T.let([], T::Array[Dependabot::DependencyFile])
51
- @fetched_files = T.let({}, T::Hash[String, T::Array[Dependabot::DependencyFile]])
52
- @nuget_config_files = T.let(nil, T.nilable(T::Array[Dependabot::DependencyFile]))
53
- @packages_config_files = T.let(nil, T.nilable(T::Array[Dependabot::DependencyFile]))
54
- @assembly_binding_redirect_config_files = T.let(nil, T.nilable(T::Array[Dependabot::DependencyFile]))
55
- @packages_lock_files = T.let(nil, T.nilable(T::Array[Dependabot::DependencyFile]))
24
+ "Repo must contain .(cs|vb|fs)proj file."
56
25
  end
57
26
 
58
27
  sig { override.returns(T::Array[DependencyFile]) }
59
28
  def fetch_files
60
- fetched_files = [
61
- *project_files,
62
- *directory_build_files,
63
- *imported_property_files,
64
- *packages_config_files,
65
- *assembly_binding_redirect_config_files,
66
- *nuget_config_files,
67
- *packages_lock_files,
68
- global_json,
69
- dotnet_tools_json,
70
- packages_props
71
- ].compact
72
-
73
- # dedup files based on their absolute path
74
- fetched_files = fetched_files.uniq do |fetched_file|
75
- Pathname.new(fetched_file.directory).join(fetched_file.name).cleanpath.to_path
76
- end
77
-
78
- if project_files.none? && packages_config_files.none?
79
- raise T.must(@missing_sln_project_file_errors.first) if @missing_sln_project_file_errors&.any?
80
-
81
- raise_dependency_file_not_found
82
- end
83
-
84
- fetched_files
85
- end
86
-
87
- private
88
-
89
- sig { returns(T::Array[Dependabot::DependencyFile]) }
90
- def project_files
91
- return @project_files if @project_files.any?
92
-
93
- @project_files =
94
- begin
95
- project_files = []
96
- project_files += csproj_file
97
- project_files += vbproj_file
98
- project_files += fsproj_file
99
- project_files += sln_project_files
100
- project_files += proj_files
101
- project_files += project_files.filter_map do |f|
102
- named_file_up_tree_from_project_file(f, "Directory.Packages.props")
103
- end
104
- project_files
105
- end
106
- rescue Octokit::NotFound, Gitlab::Error::NotFound
107
- raise_dependency_file_not_found
108
- end
109
-
110
- sig { returns(T.noreturn) }
111
- def raise_dependency_file_not_found
112
- raise(
113
- Dependabot::DependencyFileNotFound.new(
114
- File.join(directory, "*.(sln|csproj|vbproj|fsproj|proj)"),
115
- "Unable to find `*.sln`, `*.(cs|vb|fs)proj`, or `*.proj` in directory `#{directory}`"
116
- )
29
+ discovery_json_reader = NativeDiscoveryJsonReader.run_discovery_in_directory(
30
+ repo_contents_path: T.must(repo_contents_path),
31
+ directory: directory,
32
+ credentials: credentials
117
33
  )
118
- end
119
-
120
- sig { returns(T::Array[Dependabot::DependencyFile]) }
121
- def packages_config_files
122
- return @packages_config_files if @packages_config_files
123
-
124
- imported_project_files = imported_property_files.filter { |f| f.name.match?(/\.(cs|vb|fs)proj$/) }
125
-
126
- @packages_config_files = [*project_files, *imported_project_files].filter_map do |f|
127
- named_file_next_to_project_file(f, "packages.config")
128
- end
129
- end
130
-
131
- sig { returns(T::Array[Dependabot::DependencyFile]) }
132
- def assembly_binding_redirect_config_files
133
- return @assembly_binding_redirect_config_files if @assembly_binding_redirect_config_files
134
-
135
- candidate_paths =
136
- [*project_files.map { |f| File.dirname(f.name) }, "."].uniq
137
-
138
- # Assembly binding redirects can appear in any app/web.config file for a .NET Framework project
139
- # https://learn.microsoft.com/en-us/dotnet/framework/configure-apps/redirect-assembly-versions#specify-assembly-binding-in-configuration-files
140
- @assembly_binding_redirect_config_files =
141
- candidate_paths.filter_map do |dir|
142
- file = repo_contents(dir: dir)
143
- .find { |f| f.name.match?(/^(app|web)\.config$/i) }
144
- fetch_file_from_host(File.join(dir, file.name)) if file
145
- end
146
- end
147
-
148
- # rubocop:disable Metrics/PerceivedComplexity
149
- sig { returns(T.nilable(T::Array[T.untyped])) }
150
- def sln_file_names
151
- sln_files = repo_contents.select { |f| f.name.end_with?(".sln") }
152
- src_dir = repo_contents.any? { |f| f.name == "src" && f.type == "dir" }
153
-
154
- # If there are no sln files but there is a src directory, check that dir
155
- if sln_files.none? && src_dir
156
- sln_files = repo_contents(dir: "src")
157
- .select { |f| f.name.end_with?(".sln") }.map(&:dup)
158
- .map { |file| file.tap { |f| f.name = "src/" + f.name } }
159
- end
160
-
161
- # Return `nil` if no sln files were found
162
- return if sln_files.none?
163
-
164
- sln_files.map(&:name)
165
- end
166
- # rubocop:enable Metrics/PerceivedComplexity
167
-
168
- sig { returns(T::Array[Dependabot::DependencyFile]) }
169
- def directory_build_files
170
- @directory_build_files ||= T.let(fetch_directory_build_files, T.nilable(T::Array[Dependabot::DependencyFile]))
171
- end
172
-
173
- sig { returns(T::Array[Dependabot::DependencyFile]) }
174
- def fetch_directory_build_files
175
- attempted_dirs = T.let([], T::Array[Pathname])
176
- directory_build_files = T.let([], T::Array[Dependabot::DependencyFile])
177
- directory_path = Pathname.new(directory)
178
-
179
- # find all build files (Directory.Build.props/.targets) relative to the given project file
180
- project_files.map { |f| Pathname.new(f.directory).join(f.name).dirname }.uniq.each do |dir|
181
- # Simulate MSBuild walking up the directory structure looking for a file
182
- dir.descend.each do |possible_dir|
183
- break if attempted_dirs.include?(possible_dir)
184
-
185
- attempted_dirs << possible_dir
186
- relative_possible_dir = Pathname.new(possible_dir).relative_path_from(directory_path).to_s
187
- build_files = repo_contents(dir: relative_possible_dir).select { |f| f.name.match?(BUILD_FILE_NAMES) }
188
- directory_build_files += build_files.map do |file|
189
- possible_file = File.join(relative_possible_dir, file.name).delete_prefix("/")
190
- fetch_file_from_host(possible_file)
191
- end
192
- end
193
- end
194
-
195
- directory_build_files
196
- end
197
-
198
- sig { returns(T::Array[Dependabot::DependencyFile]) }
199
- def sln_project_files
200
- return [] unless sln_files
201
-
202
- @sln_project_files ||=
203
- begin
204
- paths = T.must(sln_files).flat_map do |sln_file|
205
- SlnProjectPathsFinder
206
- .new(sln_file: sln_file)
207
- .project_paths
208
- end
209
-
210
- paths.filter_map do |path|
211
- fetch_file_from_host(path)
212
- rescue Dependabot::DependencyFileNotFound => e
213
- @missing_sln_project_file_errors ||= T.let([], T.nilable(T::Array[Dependabot::DependencyFileNotFound]))
214
- @missing_sln_project_file_errors << e
215
- # Don't worry about missing files too much for now (at least
216
- # until we start resolving properties)
217
- nil
218
- end
219
- end
220
- end
221
-
222
- sig { returns(T.nilable(T::Array[Dependabot::DependencyFile])) }
223
- def sln_files
224
- return unless sln_file_names
225
-
226
- @sln_files ||=
227
- sln_file_names
228
- &.map { |sln_file_name| fetch_file_from_host(sln_file_name) }
229
- &.select { |file| file.content&.valid_encoding? }
230
- end
231
-
232
- sig { returns(T::Array[Dependabot::DependencyFile]) }
233
- def csproj_file
234
- @csproj_file ||= T.let(find_and_fetch_with_suffix(".csproj"), T.nilable(T::Array[Dependabot::DependencyFile]))
235
- end
236
-
237
- sig { returns(T::Array[Dependabot::DependencyFile]) }
238
- def vbproj_file
239
- @vbproj_file ||= T.let(find_and_fetch_with_suffix(".vbproj"), T.nilable(T::Array[Dependabot::DependencyFile]))
240
- end
241
-
242
- sig { returns(T::Array[Dependabot::DependencyFile]) }
243
- def fsproj_file
244
- @fsproj_file ||= T.let(find_and_fetch_with_suffix(".fsproj"), T.nilable(T::Array[Dependabot::DependencyFile]))
245
- end
246
-
247
- sig { returns(T::Array[Dependabot::DependencyFile]) }
248
- def proj_files
249
- @proj_files ||= T.let(find_and_fetch_with_suffix(".proj"), T.nilable(T::Array[Dependabot::DependencyFile]))
250
- end
251
-
252
- sig { params(suffix: String).returns(T::Array[Dependabot::DependencyFile]) }
253
- def find_and_fetch_with_suffix(suffix)
254
- repo_contents.select { |f| f.name.end_with?(suffix) }.map { |f| fetch_file_from_host(f.name) }
255
- end
256
-
257
- sig { returns(T::Array[Dependabot::DependencyFile]) }
258
- def nuget_config_files
259
- return @nuget_config_files if @nuget_config_files
260
-
261
- @nuget_config_files = [*project_files.map do |f|
262
- named_file_up_tree_from_project_file(f, "nuget.config")
263
- end].compact.uniq
264
- @nuget_config_files
265
- end
266
-
267
- sig { returns(T::Array[Dependabot::DependencyFile]) }
268
- def packages_lock_files
269
- return @packages_lock_files if @packages_lock_files
270
-
271
- candidate_paths =
272
- [*project_files.map { |f| File.dirname(f.name) }, "."].uniq
273
-
274
- @packages_lock_files =
275
- candidate_paths.filter_map do |dir|
276
- file = repo_contents(dir: dir)
277
- .find { |f| f.name.casecmp("packages.lock.json").zero? }
278
- fetch_file_from_host(File.join(dir, file.name)) if file
279
- end
280
- end
281
-
282
- sig do
283
- params(
284
- project_file: Dependabot::DependencyFile,
285
- expected_file_name: String
286
- )
287
- .returns(T.nilable(Dependabot::DependencyFile))
288
- end
289
- def named_file_up_tree_from_project_file(project_file, expected_file_name)
290
- found_expected_file = T.let(nil, T.nilable(Dependabot::DependencyFile))
291
- directory_path = Pathname.new(directory)
292
- full_project_dir = Pathname.new(project_file.directory).join(project_file.name).dirname
293
- full_project_dir.ascend.each do |base|
294
- break if found_expected_file
295
-
296
- candidate_file_path = Pathname.new(base).join(expected_file_name).cleanpath.to_path
297
- candidate_directory = Pathname.new(File.dirname(candidate_file_path))
298
- relative_candidate_directory = candidate_directory.relative_path_from(directory_path)
299
- candidate_file = repo_contents(dir: relative_candidate_directory).find do |f|
300
- f.name.casecmp?(expected_file_name)
301
- end
302
- if candidate_file
303
- found_expected_file = fetch_file_from_host(File.join(relative_candidate_directory,
304
- candidate_file.name))
305
- end
306
- end
307
-
308
- found_expected_file
309
- end
310
-
311
- sig do
312
- params(
313
- project_file: Dependabot::DependencyFile,
314
- expected_file_name: String
315
- )
316
- .returns(T.nilable(Dependabot::DependencyFile))
317
- end
318
- def named_file_next_to_project_file(project_file, expected_file_name)
319
- found_expected_file = T.let(nil, T.nilable(Dependabot::DependencyFile))
320
- directory_path = Pathname.new(directory)
321
- full_project_dir = Pathname.new(project_file.directory).join(project_file.name).dirname
322
-
323
- candidate_file_path = Pathname.new(full_project_dir).join(expected_file_name).cleanpath.to_path
324
- candidate_directory = Pathname.new(File.dirname(candidate_file_path))
325
- relative_candidate_directory = candidate_directory.relative_path_from(directory_path)
326
- candidate_file = repo_contents(dir: relative_candidate_directory).find do |f|
327
- f.name.casecmp?(expected_file_name)
328
- end
329
- if candidate_file
330
- found_expected_file = fetch_file_from_host(File.join(relative_candidate_directory,
331
- candidate_file.name))
332
- end
333
-
334
- found_expected_file
335
- end
336
-
337
- sig { returns(T.nilable(Dependabot::DependencyFile)) }
338
- def global_json
339
- @global_json ||= T.let(fetch_file_if_present("global.json"), T.nilable(Dependabot::DependencyFile))
340
- end
341
-
342
- sig { returns(T.nilable(Dependabot::DependencyFile)) }
343
- def dotnet_tools_json
344
- @dotnet_tools_json ||= T.let(fetch_file_if_present(".config/dotnet-tools.json"),
345
- T.nilable(Dependabot::DependencyFile))
346
- end
347
-
348
- sig { returns(T.nilable(Dependabot::DependencyFile)) }
349
- def packages_props
350
- @packages_props ||= T.let(fetch_file_if_present("Packages.props"), T.nilable(Dependabot::DependencyFile))
351
- end
352
-
353
- sig { returns(T::Array[Dependabot::DependencyFile]) }
354
- def imported_property_files
355
- imported_property_files = T.let([], T::Array[Dependabot::DependencyFile])
356
-
357
- files = [*project_files, *directory_build_files]
358
-
359
- files.each do |proj_file|
360
- previously_fetched_files = project_files + imported_property_files
361
- imported_property_files +=
362
- fetch_imported_property_files(
363
- file: proj_file,
364
- previously_fetched_files: previously_fetched_files
365
- )
366
- end
367
-
368
- imported_property_files
369
- end
370
-
371
- sig do
372
- params(
373
- file: Dependabot::DependencyFile,
374
- previously_fetched_files: T::Array[Dependabot::DependencyFile]
375
- )
376
- .returns(T::Array[Dependabot::DependencyFile])
377
- end
378
- def fetch_imported_property_files(file:, previously_fetched_files:)
379
- file_id = file.directory + "/" + file.name
380
-
381
- if @fetched_files[file_id]
382
- T.must(@fetched_files[file_id])
383
- else
384
- paths =
385
- ImportPathsFinder.new(project_file: file).import_paths +
386
- ImportPathsFinder.new(project_file: file).project_reference_paths +
387
- ImportPathsFinder.new(project_file: file).project_file_paths
388
-
389
- # Initialize a set to hold fetched files temporarily to avoid duplicates
390
- fetched_files_set = Set.new([file])
391
-
392
- paths.each do |path|
393
- next if previously_fetched_files.map(&:name).include?(path)
394
- next if file.name == path
395
- next if path.include?("$(")
396
-
397
- begin
398
- fetched_file = fetch_file_from_host(path)
399
- grandchild_property_files = fetch_imported_property_files(
400
- file: fetched_file,
401
- previously_fetched_files: previously_fetched_files + [file]
402
- )
403
-
404
- # Add fetched file and grandchild property files to the set
405
- fetched_files_set << fetched_file
406
- fetched_files_set.merge(grandchild_property_files)
407
- rescue Dependabot::DependencyFileNotFound
408
- # Don't worry about missing files, just skip them for now
409
- Dependabot.logger.info("unable to find expected file #{file.name}")
410
- nil
411
- end
412
- end
413
-
414
- # Convert the set to an array and cache the fetched files
415
- fetched_files = fetched_files_set.to_a
416
- @fetched_files[file_id] = fetched_files
417
34
 
418
- # Return the fetched files
419
- fetched_files
35
+ NativeDiscoveryJsonReader.debug_report_discovery_files(error_if_missing: false)
36
+ discovery_json_reader.dependency_file_paths.map do |p|
37
+ relative_path = Pathname.new(p).relative_path_from(directory).to_path
38
+ fetch_file_from_host(relative_path)
420
39
  end
421
40
  end
422
41
  end
@@ -16,73 +16,42 @@ module Dependabot
16
16
  extend T::Sig
17
17
 
18
18
  require "dependabot/file_parsers/base/dependency_set"
19
- require_relative "cache_manager"
20
-
21
- sig { returns(T::Hash[String, T::Array[Dependabot::Dependency]]) }
22
- def self.file_dependency_cache
23
- T.let(CacheManager.cache("file_parser.parse"), T::Hash[String, T::Array[Dependabot::Dependency]])
24
- end
25
19
 
26
20
  sig { override.returns(T::Array[Dependabot::Dependency]) }
27
21
  def parse
28
- return [] unless repo_contents_path
29
-
30
- key = NativeDiscoveryJsonReader.create_cache_key(dependency_files)
31
- workspace_path = source&.directory || "/"
32
- self.class.file_dependency_cache[key] ||= begin
33
- # run discovery for the repo
34
- discovery_json_path = NativeDiscoveryJsonReader.create_discovery_file_path_from_dependency_files(
35
- dependency_files
36
- )
37
- NativeHelpers.run_nuget_discover_tool(repo_root: T.must(repo_contents_path),
38
- workspace_path: workspace_path,
39
- output_path: discovery_json_path,
40
- credentials: credentials)
41
-
42
- discovery_json = NativeDiscoveryJsonReader.discovery_json_from_path(discovery_json_path)
43
- return [] unless discovery_json
44
-
45
- Dependabot.logger.info("Discovery JSON content: #{discovery_json.content}")
46
- discovery_json_reader = NativeDiscoveryJsonReader.new(
47
- discovery_json: discovery_json
48
- )
49
-
50
- # cache discovery results
51
- NativeDiscoveryJsonReader.set_discovery_from_dependency_files(dependency_files: dependency_files,
52
- discovery: discovery_json_reader)
53
- discovery_json_reader.dependency_set.dependencies
54
- end
55
-
56
- T.must(self.class.file_dependency_cache[key])
22
+ dependencies
57
23
  end
58
24
 
59
25
  private
60
26
 
61
- sig { returns(T::Array[Dependabot::DependencyFile]) }
62
- def proj_files
63
- projfile = /\.proj$/
64
-
65
- dependency_files.select do |df|
66
- df.name.match?(projfile)
67
- end
68
- end
69
-
70
- sig { returns(T::Array[Dependabot::DependencyFile]) }
71
- def project_files
72
- projectfile = /\.(cs|vb|fs)proj$/
73
-
74
- dependency_files.select do |df|
75
- df.name.match?(projectfile)
76
- end
27
+ sig { returns(T::Array[Dependabot::Dependency]) }
28
+ def dependencies
29
+ @dependencies ||= T.let(begin
30
+ NativeDiscoveryJsonReader.debug_report_discovery_files(error_if_missing: true)
31
+ directory = source&.directory || "/"
32
+ discovery_json_reader = NativeDiscoveryJsonReader.run_discovery_in_directory(
33
+ repo_contents_path: T.must(repo_contents_path),
34
+ directory: directory,
35
+ credentials: credentials
36
+ )
37
+ discovery_json_reader.dependency_set.dependencies
38
+ end, T.nilable(T::Array[Dependabot::Dependency]))
77
39
  end
78
40
 
79
41
  sig { override.void }
80
42
  def check_required_files
81
- return if project_files.any? || proj_files.any?
43
+ requirement_files = dependencies.flat_map do |dep|
44
+ dep.requirements.map { |r| T.let(r.fetch(:file), String) }
45
+ end.uniq
46
+
47
+ project_files = requirement_files.select { |f| File.basename(f).match?(/\.(cs|vb|fs)proj$/) }
48
+ global_json_file = requirement_files.select { |f| File.basename(f) == "global.json" }
49
+ dotnet_tools_json_file = requirement_files.select { |f| File.basename(f) == "dotnet-tools.json" }
50
+ return if project_files.any? || global_json_file.any? || dotnet_tools_json_file.any?
82
51
 
83
52
  raise Dependabot::DependencyFileNotFound.new(
84
- "*.(cs|vb|fs)proj, *.proj",
85
- "No project file or *.proj!"
53
+ "*.(cs|vb|fs)proj",
54
+ "No project file."
86
55
  )
87
56
  end
88
57
  end
@@ -57,7 +57,12 @@ module Dependabot
57
57
  try_update_projects(dependency) || try_update_json(dependency)
58
58
  end
59
59
  updated_files = dependency_files.filter_map do |f|
60
- updated_content = File.read(dependency_file_path(f))
60
+ dependency_file_path = NativeDiscoveryJsonReader.dependency_file_path(
61
+ repo_contents_path: T.must(repo_contents_path),
62
+ dependency_file: f
63
+ )
64
+ dependency_file_path = File.join(repo_contents_path, dependency_file_path)
65
+ updated_content = File.read(dependency_file_path)
61
66
  next if updated_content == f.content
62
67
 
63
68
  normalized_content = normalize_content(f, updated_content)
@@ -92,7 +97,11 @@ module Dependabot
92
97
  # run update for each project file
93
98
  project_files.each do |project_file|
94
99
  project_dependencies = project_dependencies(project_file)
95
- proj_path = dependency_file_path(project_file)
100
+ dependency_file_path = NativeDiscoveryJsonReader.dependency_file_path(
101
+ repo_contents_path: T.must(repo_contents_path),
102
+ dependency_file: project_file
103
+ )
104
+ proj_path = dependency_file_path
96
105
 
97
106
  next unless project_dependencies.any? { |dep| dep.name.casecmp?(dependency.name) }
98
107
 
@@ -119,7 +128,11 @@ module Dependabot
119
128
 
120
129
  # We just need to feed the updater a project file, grab the first
121
130
  project_file = T.must(project_files.first)
122
- proj_path = dependency_file_path(project_file)
131
+ dependency_file_path = NativeDiscoveryJsonReader.dependency_file_path(
132
+ repo_contents_path: T.must(repo_contents_path),
133
+ dependency_file: project_file
134
+ )
135
+ proj_path = dependency_file_path
123
136
 
124
137
  return false unless repo_contents_path
125
138
 
@@ -157,8 +170,11 @@ module Dependabot
157
170
 
158
171
  sig { returns(T.nilable(NativeWorkspaceDiscovery)) }
159
172
  def workspace
160
- discovery_json_reader = NativeDiscoveryJsonReader.get_discovery_from_dependency_files(dependency_files)
161
- discovery_json_reader.workspace_discovery
173
+ dependency_file_paths = dependency_files.map do |f|
174
+ NativeDiscoveryJsonReader.dependency_file_path(repo_contents_path: T.must(repo_contents_path),
175
+ dependency_file: f)
176
+ end
177
+ NativeDiscoveryJsonReader.load_discovery_for_dependency_file_paths(dependency_file_paths).workspace_discovery
162
178
  end
163
179
 
164
180
  sig { params(project_file: Dependabot::DependencyFile).returns(T::Array[String]) }
@@ -215,17 +231,6 @@ module Dependabot
215
231
  end
216
232
  # rubocop:enable Metrics/PerceivedComplexity
217
233
 
218
- sig { params(dependency_file: Dependabot::DependencyFile).returns(String) }
219
- def dependency_file_path(dependency_file)
220
- if dependency_file.directory.start_with?(T.must(repo_contents_path))
221
- File.join(dependency_file.directory, dependency_file.name)
222
- else
223
- file_directory = dependency_file.directory
224
- file_directory = file_directory[1..-1] if file_directory.start_with?("/")
225
- File.join(repo_contents_path || "", file_directory, dependency_file.name)
226
- end
227
- end
228
-
229
234
  sig { returns(T::Array[Dependabot::DependencyFile]) }
230
235
  def project_files
231
236
  dependency_files.select { |df| df.name.match?(/\.(cs|vb|fs)proj$/) }
@@ -41,7 +41,7 @@ module Dependabot
41
41
  attr_reader :dependencies
42
42
 
43
43
  sig { overridable.returns(Dependabot::FileParsers::Base::DependencySet) }
44
- def dependency_set # rubocop:disable Metrics/PerceivedComplexity,Metrics/CyclomaticComplexity,Metrics/AbcSize
44
+ def dependency_set # rubocop:disable Metrics/PerceivedComplexity
45
45
  dependency_set = Dependabot::FileParsers::Base::DependencySet.new
46
46
 
47
47
  file_name = Pathname.new(file_path).cleanpath.to_path
@@ -65,14 +65,7 @@ module Dependabot
65
65
  # Exclude any dependencies which reference an item type
66
66
  next if dependency.name.include?("@(")
67
67
 
68
- dependency_file_name = file_name
69
- if dependency.type == "PackagesConfig"
70
- dir_name = File.dirname(file_name)
71
- dependency_file_name = "packages.config"
72
- dependency_file_name = File.join(dir_name, "packages.config") unless dir_name == "."
73
- end
74
-
75
- dependency_set << build_dependency(dependency_file_name, dependency)
68
+ dependency_set << build_dependency(file_name, dependency)
76
69
  end
77
70
 
78
71
  dependency_set