dependabot-core 0.81.1 → 0.82.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,198 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require "dependabot/shared_helpers"
4
- require "dependabot/errors"
5
- require "dependabot/file_parsers/elm/elm_package"
6
- require "dependabot/update_checkers/elm/elm_package"
7
- require "dependabot/update_checkers/elm/elm_package/cli_parser"
8
- require "dependabot/update_checkers/elm/elm_package/requirements_updater"
9
- require "dependabot/utils/elm/requirement"
10
-
11
- module Dependabot
12
- module UpdateCheckers
13
- module Elm
14
- class ElmPackage
15
- class Elm19VersionResolver
16
- class UnrecoverableState < StandardError; end
17
-
18
- def initialize(dependency:, dependency_files:)
19
- @dependency = dependency
20
- @dependency_files = dependency_files
21
- end
22
-
23
- def latest_resolvable_version(unlock_requirement:)
24
- unless %i(none own all).include?(unlock_requirement)
25
- raise "Invalid unlock setting: #{unlock_requirement}"
26
- end
27
-
28
- # Elm has no lockfile, so we will never create an update PR if
29
- # unlock requirements are `none`. Just return the current version.
30
- return current_version if unlock_requirement == :none
31
-
32
- # Otherwise, we gotta check a few conditions to see if bumping
33
- # wouldn't also bump other deps in elm-package.json
34
- fetch_latest_resolvable_version(unlock_requirement)
35
- end
36
-
37
- def updated_dependencies_after_full_unlock
38
- changed_deps = install_metadata
39
-
40
- original_dependency_details.map do |original_dep|
41
- new_version = changed_deps.fetch(original_dep.name, nil)
42
- next unless new_version
43
-
44
- old_reqs = original_dep.requirements.map do |req|
45
- requirement_class.new(req[:requirement])
46
- end
47
-
48
- next if old_reqs.all? { |req| req.satisfied_by?(new_version) }
49
-
50
- new_requirements =
51
- RequirementsUpdater.new(
52
- requirements: original_dep.requirements,
53
- latest_resolvable_version: new_version.to_s
54
- ).updated_requirements
55
-
56
- Dependency.new(
57
- name: original_dep.name,
58
- version: new_version.to_s,
59
- requirements: new_requirements,
60
- previous_version: original_dep.version,
61
- previous_requirements: original_dep.requirements,
62
- package_manager: original_dep.package_manager
63
- )
64
- end.compact
65
- end
66
-
67
- private
68
-
69
- attr_reader :dependency, :dependency_files
70
-
71
- def fetch_latest_resolvable_version(unlock_requirement)
72
- changed_deps = install_metadata
73
-
74
- result = check_install_result(changed_deps)
75
- version_after_install = changed_deps.fetch(dependency.name)
76
-
77
- # If the install was clean then we can definitely update
78
- return version_after_install if result == :clean_bump
79
-
80
- # Otherwise, we can still update if the result was a forced full
81
- # unlock and we're allowed to unlock other requirements
82
- return version_after_install if unlock_requirement == :all
83
-
84
- current_version
85
- end
86
-
87
- def check_install_result(changed_deps)
88
- other_deps_bumped =
89
- changed_deps.
90
- keys.
91
- reject { |name| name == dependency.name }
92
-
93
- return :forced_full_unlock_bump if other_deps_bumped.any?
94
-
95
- :clean_bump
96
- end
97
-
98
- def install_metadata
99
- @install_metadata ||=
100
- SharedHelpers.in_a_temporary_directory do
101
- write_temporary_dependency_files
102
-
103
- # Elm package install outputs a preview of the actions to be
104
- # performed. We can use this preview to calculate whether it
105
- # would do anything funny
106
- command = "yes n | elm19 install #{dependency.name}"
107
- response = run_shell_command(command)
108
-
109
- CliParser.decode_install_preview(response)
110
- rescue SharedHelpers::HelperSubprocessFailed => error
111
- # 5) We bump our dep but elm blows up
112
- handle_elm_errors(error)
113
- end
114
- end
115
-
116
- def run_shell_command(command)
117
- raw_response = nil
118
- IO.popen(command, err: %i(child out)) do |process|
119
- raw_response = process.read
120
- end
121
-
122
- # Raise an error with the output from the shell session if Elm
123
- # returns a non-zero status
124
- return raw_response if $CHILD_STATUS.success?
125
-
126
- raise SharedHelpers::HelperSubprocessFailed.new(
127
- raw_response,
128
- command
129
- )
130
- end
131
-
132
- def handle_elm_errors(error)
133
- if error.message.include?("OLD DEPENDENCIES") ||
134
- error.message.include?("BAD JSON")
135
- raise Dependabot::DependencyFileNotResolvable, error.message
136
- end
137
-
138
- # Raise any unrecognised errors
139
- raise error
140
- end
141
-
142
- def write_temporary_dependency_files
143
- dependency_files.each do |file|
144
- path = file.name
145
- FileUtils.mkdir_p(Pathname.new(path).dirname)
146
-
147
- File.write(path, updated_elm_json_content(file.content))
148
- end
149
- end
150
-
151
- def updated_elm_json_content(content)
152
- json = JSON.parse(content)
153
-
154
- # Delete the dependency from the elm.json, so that we can use
155
- # `elm install <dependency_name>` to generate the install plan
156
- %w(dependencies test-dependencies).each do |type|
157
- if json.dig(type, dependency.name)
158
- json[type].delete(dependency.name)
159
- end
160
-
161
- %w(direct indirect).each do |category|
162
- if json.dig(type, category, dependency.name)
163
- json[type][category].delete(dependency.name)
164
- end
165
- end
166
- end
167
-
168
- json["source-directories"] = []
169
-
170
- JSON.dump(json)
171
- end
172
-
173
- def original_dependency_details
174
- @original_dependency_details ||=
175
- FileParsers::Elm::ElmPackage.new(
176
- dependency_files: dependency_files,
177
- source: nil
178
- ).parse
179
- end
180
-
181
- def current_version
182
- return unless dependency.version
183
-
184
- version_class.new(dependency.version)
185
- end
186
-
187
- def version_class
188
- Utils::Elm::Version
189
- end
190
-
191
- def requirement_class
192
- Utils::Elm::Requirement
193
- end
194
- end
195
- end
196
- end
197
- end
198
- end
@@ -1,75 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require "dependabot/utils/elm/version"
4
- require "dependabot/utils/elm/requirement"
5
- require "dependabot/update_checkers/elm/elm_package"
6
-
7
- module Dependabot
8
- module UpdateCheckers
9
- module Elm
10
- class ElmPackage
11
- class RequirementsUpdater
12
- RANGE_REQUIREMENT_REGEX =
13
- /(\d+\.\d+\.\d+) <= v < (\d+\.\d+\.\d+)/.freeze
14
- SINGLE_VERSION_REGEX = /\A(\d+\.\d+\.\d+)\z/.freeze
15
-
16
- def initialize(requirements:, latest_resolvable_version:)
17
- @requirements = requirements
18
-
19
- return unless latest_resolvable_version
20
- return unless version_class.correct?(latest_resolvable_version)
21
-
22
- @latest_resolvable_version =
23
- version_class.new(latest_resolvable_version)
24
- end
25
-
26
- def updated_requirements
27
- return requirements unless latest_resolvable_version
28
-
29
- requirements.map do |req|
30
- updated_req_string = update_requirement(
31
- req[:requirement],
32
- latest_resolvable_version
33
- )
34
-
35
- req.merge(requirement: updated_req_string)
36
- end
37
- end
38
-
39
- private
40
-
41
- attr_reader :requirements, :latest_resolvable_version
42
-
43
- def update_requirement(old_req, new_version)
44
- if requirement_class.new(old_req).satisfied_by?(new_version)
45
- old_req
46
- elsif (match = RANGE_REQUIREMENT_REGEX.match(old_req))
47
- require_range(match[1], new_version)
48
- elsif SINGLE_VERSION_REGEX.match?(old_req)
49
- new_version.to_s
50
- else
51
- require_exactly(new_version)
52
- end
53
- end
54
-
55
- def require_range(minimum, version)
56
- major, _minor, _patch = version.to_s.split(".").map(&:to_i)
57
- "#{minimum} <= v < #{major + 1}.0.0"
58
- end
59
-
60
- def require_exactly(version)
61
- "#{version} <= v <= #{version}"
62
- end
63
-
64
- def version_class
65
- Utils::Elm::Version
66
- end
67
-
68
- def requirement_class
69
- Utils::Elm::Requirement
70
- end
71
- end
72
- end
73
- end
74
- end
75
- end
@@ -1,92 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require "dependabot/utils/elm/version"
4
-
5
- module Dependabot
6
- module Utils
7
- module Elm
8
- class Requirement < Gem::Requirement
9
- # Override the version pattern to allow local versions
10
- PATTERN_RAW =
11
- "(#{Utils::Elm::Version::VERSION_PATTERN}) (<=?) v (<=?) " \
12
- "(#{Utils::Elm::Version::VERSION_PATTERN})"
13
- PATTERN = /\A#{PATTERN_RAW}\z/.freeze
14
- EXACT_PATTERN = /\A#{Utils::Elm::Version::VERSION_PATTERN}\z/.freeze
15
-
16
- # Returns an array of requirements. At least one requirement from the
17
- # returned array must be satisfied for a version to be valid.
18
- def self.requirements_array(requirement_string)
19
- [new(requirement_string)]
20
- end
21
-
22
- # Override the parser to create Utils::Elm::Versions and return an
23
- # array of parsed requirements
24
- def self.parse(obj)
25
- # If a version is given this is an equals requirement
26
- if EXACT_PATTERN.match?(obj.to_s)
27
- return [["=", Utils::Elm::Version.new(obj.to_s)]]
28
- end
29
-
30
- unless (matches = PATTERN.match(obj.to_s))
31
- msg = "Illformed requirement #{obj.inspect}"
32
- raise BadRequirementError, msg
33
- end
34
-
35
- # If the two versions specified are identical this is an equals
36
- # requirement
37
- if matches[1] == matches[4] && matches[3] == "<="
38
- return [["=", Utils::Elm::Version.new(matches[4])]]
39
- end
40
-
41
- [
42
- [matches[2].tr("<", ">"), Utils::Elm::Version.new(matches[1])],
43
- [matches[3], Utils::Elm::Version.new(matches[4])]
44
- ]
45
- end
46
-
47
- # Overwrite superclass method to use `flat_map`
48
- def initialize(*requirements)
49
- if requirements.any?(&:nil?)
50
- raise BadRequirementError, "Nil requirement not supported in Elm"
51
- end
52
-
53
- requirements = requirements.flatten
54
- requirements.compact!
55
- requirements.uniq!
56
-
57
- if requirements.empty?
58
- @requirements = [DefaultRequirement]
59
- else
60
- @requirements = requirements.flat_map { |r| self.class.parse(r) }
61
- sort_requirements!
62
- end
63
- end
64
-
65
- # Overwrite superclass method to use `flat_map`
66
- def concat(new)
67
- new = new.flatten
68
- new.compact!
69
- new.uniq!
70
- new = new.flat_map { |r| self.class.parse(r) }
71
-
72
- @requirements.concat new
73
- sort_requirements!
74
- end
75
-
76
- def sort_requirements!
77
- @requirements.sort! do |l, r|
78
- comp = l.last <=> r.last # first, sort by the requirement's version
79
- next comp unless comp.zero?
80
-
81
- l.first <=> r.first # then, sort by the operator (for stability)
82
- end
83
- end
84
-
85
- def satisfied_by?(version)
86
- version = Utils::Elm::Version.new(version.to_s)
87
- super
88
- end
89
- end
90
- end
91
- end
92
- end
@@ -1,19 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- # Elm versions require major, minor and patch to be present
4
- # They don't allow any letters
5
-
6
- module Dependabot
7
- module Utils
8
- module Elm
9
- class Version < Gem::Version
10
- VERSION_PATTERN = "[0-9]+\.[0-9]+\.[0-9]+"
11
- VERSION_PATTERN_REGEX = /\A#{VERSION_PATTERN}\Z/.freeze
12
-
13
- def self.correct?(version)
14
- version.to_s.match?(VERSION_PATTERN_REGEX)
15
- end
16
- end
17
- end
18
- end
19
- end