dependabot-npm_and_yarn 0.124.6 → 0.125.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -123,9 +123,7 @@ module Dependabot
123
123
  filename = path
124
124
  # NPM/Yarn support loading path dependencies from tarballs:
125
125
  # https://docs.npmjs.com/cli/pack.html
126
- unless filename.end_with?(".tgz")
127
- filename = File.join(filename, "package.json")
128
- end
126
+ filename = File.join(filename, "package.json") unless filename.end_with?(".tgz")
129
127
  cleaned_name = Pathname.new(filename).cleanpath.to_path
130
128
  next if fetched_files.map(&:name).include?(cleaned_name)
131
129
 
@@ -185,9 +183,7 @@ module Dependabot
185
183
  resolution_objects = parsed_manifest.values_at("resolutions").compact
186
184
  manifest_objects = dependency_objects + resolution_objects
187
185
 
188
- unless manifest_objects.all? { |o| o.is_a?(Hash) }
189
- raise Dependabot::DependencyFileNotParseable, file.path
190
- end
186
+ raise Dependabot::DependencyFileNotParseable, file.path unless manifest_objects.all? { |o| o.is_a?(Hash) }
191
187
 
192
188
  resolution_deps = resolution_objects.flat_map(&:to_a).
193
189
  map do |path, value|
@@ -328,9 +328,7 @@ module Dependabot
328
328
 
329
329
  def resolvable_before_update?(lockfile)
330
330
  @resolvable_before_update ||= {}
331
- if @resolvable_before_update.key?(lockfile.name)
332
- return @resolvable_before_update[lockfile.name]
333
- end
331
+ return @resolvable_before_update[lockfile.name] if @resolvable_before_update.key?(lockfile.name)
334
332
 
335
333
  @resolvable_before_update[lockfile.name] =
336
334
  begin
@@ -50,9 +50,7 @@ module Dependabot
50
50
  next false if CENTRAL_REGISTRIES.include?(cred["registry"])
51
51
 
52
52
  # If all the URLs include this registry, it's global
53
- if dependency_urls.all? { |url| url.include?(cred["registry"]) }
54
- next true
55
- end
53
+ next true if dependency_urls.all? { |url| url.include?(cred["registry"]) }
56
54
 
57
55
  # If any unscoped URLs include this registry, it's global
58
56
  dependency_urls.
@@ -120,9 +118,7 @@ module Dependabot
120
118
  match(/^\s*registry\s+"(?<registry>[^"]+)"/)&.
121
119
  named_captures&.fetch("registry")
122
120
 
123
- if yarnrc_global_registry
124
- return "registry = #{yarnrc_global_registry}\n"
125
- end
121
+ return "registry = #{yarnrc_global_registry}\n" if yarnrc_global_registry
126
122
 
127
123
  build_npmrc_content_from_lockfile
128
124
  end
@@ -23,9 +23,7 @@ module Dependabot
23
23
 
24
24
  def updated_yarn_lock_content(yarn_lock)
25
25
  @updated_yarn_lock_content ||= {}
26
- if @updated_yarn_lock_content[yarn_lock.name]
27
- return @updated_yarn_lock_content[yarn_lock.name]
28
- end
26
+ return @updated_yarn_lock_content[yarn_lock.name] if @updated_yarn_lock_content[yarn_lock.name]
29
27
 
30
28
  new_content = updated_yarn_lock(yarn_lock)
31
29
 
@@ -235,16 +233,12 @@ module Dependabot
235
233
  raise Dependabot::GitDependenciesNotReachable, dependency_url
236
234
  end
237
235
 
238
- if error_message.match?(TIMEOUT_FETCHING_PACKAGE)
239
- handle_timeout(error_message, yarn_lock)
240
- end
236
+ handle_timeout(error_message, yarn_lock) if error_message.match?(TIMEOUT_FETCHING_PACKAGE)
241
237
 
242
238
  if error_message.start_with?("Couldn't find any versions") ||
243
239
  error_message.include?(": Not found")
244
240
 
245
- unless resolvable_before_update?(yarn_lock)
246
- raise_resolvability_error(error_message, yarn_lock)
247
- end
241
+ raise_resolvability_error(error_message, yarn_lock) unless resolvable_before_update?(yarn_lock)
248
242
 
249
243
  # Dependabot has probably messed something up with the update and we
250
244
  # want to hear about it
@@ -259,9 +253,7 @@ module Dependabot
259
253
 
260
254
  def resolvable_before_update?(yarn_lock)
261
255
  @resolvable_before_update ||= {}
262
- if @resolvable_before_update.key?(yarn_lock.name)
263
- return @resolvable_before_update[yarn_lock.name]
264
- end
256
+ return @resolvable_before_update[yarn_lock.name] if @resolvable_before_update.key?(yarn_lock.name)
265
257
 
266
258
  @resolvable_before_update[yarn_lock.name] =
267
259
  begin
@@ -392,9 +384,7 @@ module Dependabot
392
384
  'https://\1/'
393
385
  )
394
386
 
395
- if remove_integrity_lines?
396
- updated_content = remove_integrity_lines(updated_content)
397
- end
387
+ updated_content = remove_integrity_lines(updated_content) if remove_integrity_lines?
398
388
 
399
389
  updated_content
400
390
  end
@@ -14,9 +14,7 @@ module Dependabot
14
14
  def homepage_url
15
15
  # Attempt to use version_listing first, as fetching the entire listing
16
16
  # array can be slow (if it's large)
17
- if latest_version_listing["homepage"]
18
- return latest_version_listing["homepage"]
19
- end
17
+ return latest_version_listing["homepage"] if latest_version_listing["homepage"]
20
18
 
21
19
  listing = all_version_listings.find { |_, l| l["homepage"] }
22
20
  listing&.last&.fetch("homepage", nil) || super
@@ -136,9 +134,7 @@ module Dependabot
136
134
  # Special case DefinitelyTyped, which has predictable URLs.
137
135
  # This can be removed once this PR is merged:
138
136
  # https://github.com/Microsoft/types-publisher/pull/578
139
- if source_from_url.repo == "DefinitelyTyped/DefinitelyTyped"
140
- return dependency.name.gsub(/^@/, "")
141
- end
137
+ return dependency.name.gsub(/^@/, "") if source_from_url.repo == "DefinitelyTyped/DefinitelyTyped"
142
138
 
143
139
  # Only return a directory if it is explicitly specified
144
140
  return unless details.is_a?(Hash)
@@ -160,9 +156,7 @@ module Dependabot
160
156
  **SharedHelpers.excon_defaults(headers: registry_auth_headers)
161
157
  )
162
158
 
163
- if response.status == 200
164
- return @latest_version_listing = JSON.parse(response.body)
165
- end
159
+ return @latest_version_listing = JSON.parse(response.body) if response.status == 200
166
160
 
167
161
  @latest_version_listing = {}
168
162
  rescue JSON::ParserError, Excon::Error::Timeout
@@ -17,9 +17,7 @@ module Dependabot
17
17
  PATTERN = /\A#{PATTERN_RAW}\z/.freeze
18
18
 
19
19
  def self.parse(obj)
20
- if obj.is_a?(Gem::Version)
21
- return ["=", NpmAndYarn::Version.new(obj.to_s)]
22
- end
20
+ return ["=", NpmAndYarn::Version.new(obj.to_s)] if obj.is_a?(Gem::Version)
23
21
 
24
22
  unless (matches = PATTERN.match(obj.to_s))
25
23
  msg = "Illformed requirement [#{obj.inspect}]"
@@ -88,9 +86,7 @@ module Dependabot
88
86
  upper_bound_range =
89
87
  if upper_bound_parts.length < 3
90
88
  # When upper bound is a partial version treat these as an X-range
91
- if upper_bound_parts[-1].to_i.positive?
92
- upper_bound_parts[-1] = upper_bound_parts[-1].to_i + 1
93
- end
89
+ upper_bound_parts[-1] = upper_bound_parts[-1].to_i + 1 if upper_bound_parts[-1].to_i.positive?
94
90
  upper_bound_parts.fill("0", upper_bound_parts.length...3)
95
91
  "< #{upper_bound_parts.join('.')}.a"
96
92
  else
@@ -13,6 +13,7 @@ module Dependabot
13
13
  require_relative "update_checker/latest_version_finder"
14
14
  require_relative "update_checker/version_resolver"
15
15
  require_relative "update_checker/subdependency_version_resolver"
16
+ require_relative "update_checker/conflicting_dependency_resolver"
16
17
 
17
18
  def latest_version
18
19
  @latest_version ||=
@@ -54,9 +55,7 @@ module Dependabot
54
55
  def latest_resolvable_version_with_no_unlock
55
56
  return latest_resolvable_version unless dependency.top_level?
56
57
 
57
- if git_dependency?
58
- return latest_resolvable_version_with_no_unlock_for_git_dependency
59
- end
58
+ return latest_resolvable_version_with_no_unlock_for_git_dependency if git_dependency?
60
59
 
61
60
  latest_version_finder.latest_version_with_no_unlock
62
61
  end
@@ -89,14 +88,22 @@ module Dependabot
89
88
 
90
89
  def requirements_update_strategy
91
90
  # If passed in as an option (in the base class) honour that option
92
- if @requirements_update_strategy
93
- return @requirements_update_strategy.to_sym
94
- end
91
+ return @requirements_update_strategy.to_sym if @requirements_update_strategy
95
92
 
96
93
  # Otherwise, widen ranges for libraries and bump versions for apps
97
94
  library? ? :widen_ranges : :bump_versions
98
95
  end
99
96
 
97
+ def conflicting_dependencies
98
+ ConflictingDependencyResolver.new(
99
+ dependency_files: dependency_files,
100
+ credentials: credentials
101
+ ).conflicting_dependencies(
102
+ dependency: dependency,
103
+ target_version: lowest_security_fix_version
104
+ )
105
+ end
106
+
100
107
  private
101
108
 
102
109
  def latest_version_resolvable_with_full_unlock?
@@ -188,9 +195,7 @@ module Dependabot
188
195
  def git_branch_or_ref_in_latest_release?
189
196
  return false unless latest_released_version
190
197
 
191
- if defined?(@git_branch_or_ref_in_latest_release)
192
- return @git_branch_or_ref_in_latest_release
193
- end
198
+ return @git_branch_or_ref_in_latest_release if defined?(@git_branch_or_ref_in_latest_release)
194
199
 
195
200
  @git_branch_or_ref_in_latest_release ||=
196
201
  git_commit_checker.branch_or_ref_in_release?(latest_released_version)
@@ -261,9 +266,7 @@ module Dependabot
261
266
 
262
267
  # Otherwise, if the gem isn't pinned, the latest version is just the
263
268
  # latest commit for the specified branch.
264
- unless git_commit_checker.pinned?
265
- return { sha: git_commit_checker.head_commit_for_current_branch }
266
- end
269
+ return { sha: git_commit_checker.head_commit_for_current_branch } unless git_commit_checker.pinned?
267
270
 
268
271
  # If the dependency is pinned to a tag that doesn't look like a
269
272
  # version then there's nothing we can do.
@@ -0,0 +1,63 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "dependabot/dependency"
4
+ require "dependabot/errors"
5
+ require "dependabot/npm_and_yarn/file_parser"
6
+ require "dependabot/npm_and_yarn/native_helpers"
7
+ require "dependabot/npm_and_yarn/update_checker"
8
+ require "dependabot/npm_and_yarn/update_checker/dependency_files_builder"
9
+ require "dependabot/shared_helpers"
10
+
11
+ module Dependabot
12
+ module NpmAndYarn
13
+ class UpdateChecker < Dependabot::UpdateCheckers::Base
14
+ class ConflictingDependencyResolver
15
+ def initialize(dependency_files:, credentials:)
16
+ @dependency_files = dependency_files
17
+ @credentials = credentials
18
+ end
19
+
20
+ # Finds any dependencies in the `yarn.lock` or `package-lock.json` that
21
+ # have a subdependency on the given dependency that does not satisfly
22
+ # the target_version.
23
+ #
24
+ # @param dependency [Dependabot::Dependency] the dependency to check
25
+ # @param target_version [String] the version to check
26
+ # @return [Array<Hash{String => String}]
27
+ # * name [String] the blocking dependencies name
28
+ # * version [String] the version of the blocking dependency
29
+ # * requirement [String] the requirement on the target_dependency
30
+ def conflicting_dependencies(dependency:, target_version:)
31
+ SharedHelpers.in_a_temporary_directory do
32
+ dependency_files_builder = DependencyFilesBuilder.new(
33
+ dependency: dependency,
34
+ dependency_files: dependency_files,
35
+ credentials: credentials
36
+ )
37
+ dependency_files_builder.write_temporary_dependency_files
38
+
39
+ if dependency_files_builder.yarn_locks.any?
40
+ SharedHelpers.run_helper_subprocess(
41
+ command: NativeHelpers.helper_path,
42
+ function: "yarn:findConflictingDependencies",
43
+ args: [Dir.pwd, dependency.name, target_version.to_s]
44
+ )
45
+ else
46
+ SharedHelpers.run_helper_subprocess(
47
+ command: NativeHelpers.helper_path,
48
+ function: "npm:findConflictingDependencies",
49
+ args: [Dir.pwd, dependency.name, target_version.to_s]
50
+ )
51
+ end
52
+ end
53
+ rescue SharedHelpers::HelperSubprocessFailed
54
+ []
55
+ end
56
+
57
+ private
58
+
59
+ attr_reader :dependency_files, :credentials
60
+ end
61
+ end
62
+ end
63
+ end
@@ -0,0 +1,94 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "dependabot/npm_and_yarn/file_updater/npmrc_builder"
4
+ require "dependabot/npm_and_yarn/file_updater/package_json_preparer"
5
+
6
+ module Dependabot
7
+ module NpmAndYarn
8
+ class UpdateChecker
9
+ class DependencyFilesBuilder
10
+ def initialize(dependency:, dependency_files:, credentials:)
11
+ @dependency = dependency
12
+ @dependency_files = dependency_files
13
+ @credentials = credentials
14
+ end
15
+
16
+ def write_temporary_dependency_files
17
+ write_lock_files
18
+
19
+ File.write(".npmrc", npmrc_content)
20
+
21
+ package_files.each do |file|
22
+ path = file.name
23
+ FileUtils.mkdir_p(Pathname.new(path).dirname)
24
+ File.write(file.name, prepared_package_json_content(file))
25
+ end
26
+ end
27
+
28
+ def package_locks
29
+ @package_locks ||=
30
+ dependency_files.
31
+ select { |f| f.name.end_with?("package-lock.json") }
32
+ end
33
+
34
+ def yarn_locks
35
+ @yarn_locks ||=
36
+ dependency_files.
37
+ select { |f| f.name.end_with?("yarn.lock") }
38
+ end
39
+
40
+ def shrinkwraps
41
+ @shrinkwraps ||=
42
+ dependency_files.
43
+ select { |f| f.name.end_with?("npm-shrinkwrap.json") }
44
+ end
45
+
46
+ def lockfiles
47
+ [*package_locks, *shrinkwraps, *yarn_locks]
48
+ end
49
+
50
+ def package_files
51
+ @package_files ||=
52
+ dependency_files.
53
+ select { |f| f.name.end_with?("package.json") }
54
+ end
55
+
56
+ private
57
+
58
+ attr_reader :dependency, :dependency_files, :credentials
59
+
60
+ def write_lock_files
61
+ yarn_locks.each do |f|
62
+ FileUtils.mkdir_p(Pathname.new(f.name).dirname)
63
+ File.write(f.name, prepared_yarn_lockfile_content(f.content))
64
+ end
65
+
66
+ [*package_locks, *shrinkwraps].each do |f|
67
+ FileUtils.mkdir_p(Pathname.new(f.name).dirname)
68
+ File.write(f.name, f.content)
69
+ end
70
+ end
71
+
72
+ # Duplicated in NpmLockfileUpdater
73
+ # Remove the dependency we want to update from the lockfile and let
74
+ # yarn find the latest resolvable version and fix the lockfile
75
+ def prepared_yarn_lockfile_content(content)
76
+ content.gsub(/^#{Regexp.quote(dependency.name)}\@.*?\n\n/m, "")
77
+ end
78
+
79
+ def prepared_package_json_content(file)
80
+ NpmAndYarn::FileUpdater::PackageJsonPreparer.new(
81
+ package_json_content: file.content
82
+ ).prepared_content
83
+ end
84
+
85
+ def npmrc_content
86
+ NpmAndYarn::FileUpdater::NpmrcBuilder.new(
87
+ credentials: credentials,
88
+ dependency_files: dependency_files
89
+ ).npmrc_content
90
+ end
91
+ end
92
+ end
93
+ end
94
+ end
@@ -111,9 +111,7 @@ module Dependabot
111
111
  ignore_reqs.any? { |r| r.satisfied_by?(v) }
112
112
  end
113
113
 
114
- if @raise_on_ignored && filtered.empty? && versions_array.any?
115
- raise AllVersionsIgnored
116
- end
114
+ raise AllVersionsIgnored if @raise_on_ignored && filtered.empty? && versions_array.any?
117
115
 
118
116
  filtered
119
117
  end
@@ -261,9 +259,7 @@ module Dependabot
261
259
  def version_endpoint_working?
262
260
  return true if dependency_registry == "registry.npmjs.org"
263
261
 
264
- if defined?(@version_endpoint_working)
265
- return @version_endpoint_working
266
- end
262
+ return @version_endpoint_working if defined?(@version_endpoint_working)
267
263
 
268
264
  @version_endpoint_working =
269
265
  begin
@@ -216,9 +216,7 @@ module Dependabot
216
216
 
217
217
  # If there are multiple source types, or multiple source URLs, then
218
218
  # it's unclear how we should proceed
219
- if sources.map { |s| [s[:type], s[:url]] }.uniq.count > 1
220
- raise "Multiple sources! #{sources.join(', ')}"
221
- end
219
+ raise "Multiple sources! #{sources.join(', ')}" if sources.map { |s| [s[:type], s[:url]] }.uniq.count > 1
222
220
 
223
221
  # Otherwise we just take the URL of the first private registry
224
222
  sources.find { |s| s[:type] == "private_registry" }&.fetch(:url)
@@ -1,15 +1,16 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require "dependabot/dependency"
4
- require "dependabot/shared_helpers"
5
4
  require "dependabot/errors"
6
- require "dependabot/npm_and_yarn/update_checker"
7
5
  require "dependabot/npm_and_yarn/file_parser"
8
- require "dependabot/npm_and_yarn/version"
9
- require "dependabot/npm_and_yarn/native_helpers"
10
6
  require "dependabot/npm_and_yarn/file_updater/npmrc_builder"
11
7
  require "dependabot/npm_and_yarn/file_updater/package_json_preparer"
8
+ require "dependabot/npm_and_yarn/native_helpers"
12
9
  require "dependabot/npm_and_yarn/sub_dependency_files_filterer"
10
+ require "dependabot/npm_and_yarn/update_checker"
11
+ require "dependabot/npm_and_yarn/update_checker/dependency_files_builder"
12
+ require "dependabot/npm_and_yarn/version"
13
+ require "dependabot/shared_helpers"
13
14
 
14
15
  module Dependabot
15
16
  module NpmAndYarn
@@ -29,7 +30,7 @@ module Dependabot
29
30
  return if bundled_dependency?
30
31
 
31
32
  SharedHelpers.in_a_temporary_directory do
32
- write_temporary_dependency_files
33
+ dependency_files_builder.write_temporary_dependency_files
33
34
 
34
35
  updated_lockfiles = filtered_lockfiles.map do |lockfile|
35
36
  updated_content = update_subdependency_in_lockfile(lockfile)
@@ -67,9 +68,9 @@ module Dependabot
67
68
 
68
69
  def version_from_updated_lockfiles(updated_lockfiles)
69
70
  updated_files = dependency_files -
70
- yarn_locks -
71
- package_locks -
72
- shrinkwraps +
71
+ dependency_files_builder.yarn_locks -
72
+ dependency_files_builder.package_locks -
73
+ dependency_files_builder.shrinkwraps +
73
74
  updated_lockfiles
74
75
 
75
76
  updated_version = NpmAndYarn::FileParser.new(
@@ -118,84 +119,10 @@ module Dependabot
118
119
  end
119
120
  end
120
121
 
121
- def write_temporary_dependency_files
122
- write_lock_files
123
-
124
- File.write(".npmrc", npmrc_content)
125
-
126
- package_files.each do |file|
127
- path = file.name
128
- FileUtils.mkdir_p(Pathname.new(path).dirname)
129
- File.write(file.name, prepared_package_json_content(file))
130
- end
131
- end
132
-
133
- def write_lock_files
134
- yarn_locks.each do |f|
135
- FileUtils.mkdir_p(Pathname.new(f.name).dirname)
136
- File.write(f.name, prepared_yarn_lockfile_content(f.content))
137
- end
138
-
139
- [*package_locks, *shrinkwraps].each do |f|
140
- FileUtils.mkdir_p(Pathname.new(f.name).dirname)
141
- File.write(f.name, f.content)
142
- end
143
- end
144
-
145
- # Duplicated in NpmLockfileUpdater
146
- # Remove the dependency we want to update from the lockfile and let
147
- # yarn find the latest resolvable version and fix the lockfile
148
- def prepared_yarn_lockfile_content(content)
149
- content.gsub(/^#{Regexp.quote(dependency.name)}\@.*?\n\n/m, "")
150
- end
151
-
152
- def prepared_package_json_content(file)
153
- NpmAndYarn::FileUpdater::PackageJsonPreparer.new(
154
- package_json_content: file.content
155
- ).prepared_content
156
- end
157
-
158
- def npmrc_content
159
- NpmAndYarn::FileUpdater::NpmrcBuilder.new(
160
- credentials: credentials,
161
- dependency_files: dependency_files
162
- ).npmrc_content
163
- end
164
-
165
122
  def version_class
166
123
  NpmAndYarn::Version
167
124
  end
168
125
 
169
- def package_locks
170
- @package_locks ||=
171
- dependency_files.
172
- select { |f| f.name.end_with?("package-lock.json") }
173
- end
174
-
175
- def yarn_locks
176
- @yarn_locks ||=
177
- dependency_files.
178
- select { |f| f.name.end_with?("yarn.lock") }
179
- end
180
-
181
- def shrinkwraps
182
- @shrinkwraps ||=
183
- dependency_files.
184
- select { |f| f.name.end_with?("npm-shrinkwrap.json") }
185
- end
186
-
187
- def lockfiles
188
- [*package_locks, *shrinkwraps, *yarn_locks]
189
- end
190
-
191
- def filtered_lockfiles
192
- @filtered_lockfiles ||=
193
- SubDependencyFilesFilterer.new(
194
- dependency_files: dependency_files,
195
- updated_dependencies: [updated_dependency]
196
- ).files_requiring_update
197
- end
198
-
199
126
  def updated_dependency
200
127
  Dependabot::Dependency.new(
201
128
  name: dependency.name,
@@ -206,10 +133,21 @@ module Dependabot
206
133
  )
207
134
  end
208
135
 
209
- def package_files
210
- @package_files ||=
211
- dependency_files.
212
- select { |f| f.name.end_with?("package.json") }
136
+ def filtered_lockfiles
137
+ @filtered_lockfiles ||=
138
+ SubDependencyFilesFilterer.new(
139
+ dependency_files: dependency_files,
140
+ updated_dependencies: [updated_dependency]
141
+ ).files_requiring_update
142
+ end
143
+
144
+ def dependency_files_builder
145
+ @dependency_files_builder ||=
146
+ DependencyFilesBuilder.new(
147
+ dependency: dependency,
148
+ dependency_files: dependency_files,
149
+ credentials: credentials
150
+ )
213
151
  end
214
152
 
215
153
  # TODO: We should try and fix this by updating the parent that's not