dependabot-npm_and_yarn 0.125.1 → 0.125.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -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 ||=
@@ -93,6 +94,16 @@ module Dependabot
93
94
  library? ? :widen_ranges : :bump_versions
94
95
  end
95
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
+
96
107
  private
97
108
 
98
109
  def latest_version_resolvable_with_full_unlock?
@@ -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
@@ -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
@@ -230,7 +230,7 @@ module Dependabot
230
230
  # here (since problematic repos will be resolved here before they're
231
231
  # seen by the FileUpdater)
232
232
  SharedHelpers.in_a_temporary_directory do
233
- write_temporary_dependency_files
233
+ dependency_files_builder.write_temporary_dependency_files
234
234
 
235
235
  filtered_package_files.flat_map do |file|
236
236
  path = Pathname.new(file.name).dirname
@@ -385,8 +385,8 @@ module Dependabot
385
385
  def run_checker(path:, version:)
386
386
  # If there are both yarn lockfiles and npm lockfiles only run the
387
387
  # yarn updater, yarn is also used when only a package.json exists
388
- if lockfiles_for_path(lockfiles: yarn_locks, path: path).any? ||
389
- lockfiles_for_path(lockfiles: lockfiles, path: path).none?
388
+ if lockfiles_for_path(lockfiles: dependency_files_builder.yarn_locks, path: path).any? ||
389
+ lockfiles_for_path(lockfiles: dependency_files_builder.lockfiles, path: path).none?
390
390
  return run_yarn_checker(path: path, version: version)
391
391
  end
392
392
 
@@ -438,48 +438,6 @@ module Dependabot
438
438
  end.compact
439
439
  end
440
440
 
441
- def write_temporary_dependency_files
442
- write_lock_files
443
-
444
- File.write(".npmrc", npmrc_content)
445
-
446
- package_files.each do |file|
447
- path = file.name
448
- FileUtils.mkdir_p(Pathname.new(path).dirname)
449
- File.write(file.name, prepared_package_json_content(file))
450
- end
451
- end
452
-
453
- def write_lock_files
454
- yarn_locks.each do |f|
455
- FileUtils.mkdir_p(Pathname.new(f.name).dirname)
456
- File.write(f.name, f.content)
457
- end
458
-
459
- package_locks.each do |f|
460
- FileUtils.mkdir_p(Pathname.new(f.name).dirname)
461
- File.write(f.name, f.content)
462
- end
463
-
464
- shrinkwraps.each do |f|
465
- FileUtils.mkdir_p(Pathname.new(f.name).dirname)
466
- File.write(f.name, f.content)
467
- end
468
- end
469
-
470
- def prepared_package_json_content(file)
471
- NpmAndYarn::FileUpdater::PackageJsonPreparer.new(
472
- package_json_content: file.content
473
- ).prepared_content
474
- end
475
-
476
- def npmrc_content
477
- NpmAndYarn::FileUpdater::NpmrcBuilder.new(
478
- credentials: credentials,
479
- dependency_files: dependency_files
480
- ).npmrc_content
481
- end
482
-
483
441
  # Top level dependencies are required in the peer dep checker
484
442
  # to fetch the manifests for all top level deps which may contain
485
443
  # "peerDependency" requirements
@@ -491,34 +449,6 @@ module Dependabot
491
449
  ).parse.select(&:top_level?)
492
450
  end
493
451
 
494
- def lockfiles
495
- [*yarn_locks, *package_locks, *shrinkwraps]
496
- end
497
-
498
- def package_locks
499
- @package_locks ||=
500
- dependency_files.
501
- select { |f| f.name.end_with?("package-lock.json") }
502
- end
503
-
504
- def yarn_locks
505
- @yarn_locks ||=
506
- dependency_files.
507
- select { |f| f.name.end_with?("yarn.lock") }
508
- end
509
-
510
- def shrinkwraps
511
- @shrinkwraps ||=
512
- dependency_files.
513
- select { |f| f.name.end_with?("npm-shrinkwrap.json") }
514
- end
515
-
516
- def package_files
517
- @package_files ||=
518
- dependency_files.
519
- select { |f| f.name.end_with?("package.json") }
520
- end
521
-
522
452
  def filtered_package_files
523
453
  @filtered_package_files ||=
524
454
  DependencyFilesFilterer.new(
@@ -527,6 +457,15 @@ module Dependabot
527
457
  ).package_files_requiring_update
528
458
  end
529
459
 
460
+ def dependency_files_builder
461
+ @dependency_files_builder ||=
462
+ DependencyFilesBuilder.new(
463
+ dependency: dependency,
464
+ dependency_files: dependency_files,
465
+ credentials: credentials
466
+ )
467
+ end
468
+
530
469
  def version_for_dependency(dep)
531
470
  return version_class.new(dep.version) if dep.version && version_class.correct?(dep.version)
532
471