dependabot-hex 0.88.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 +7 -0
- data/helpers/build +19 -0
- data/helpers/deps/jason/.fetch +0 -0
- data/helpers/deps/jason/.hex +2 -0
- data/helpers/deps/jason/CHANGELOG.md +60 -0
- data/helpers/deps/jason/LICENSE +13 -0
- data/helpers/deps/jason/README.md +179 -0
- data/helpers/deps/jason/hex_metadata.config +20 -0
- data/helpers/deps/jason/lib/codegen.ex +158 -0
- data/helpers/deps/jason/lib/decoder.ex +657 -0
- data/helpers/deps/jason/lib/encode.ex +630 -0
- data/helpers/deps/jason/lib/encoder.ex +216 -0
- data/helpers/deps/jason/lib/formatter.ex +253 -0
- data/helpers/deps/jason/lib/fragment.ex +11 -0
- data/helpers/deps/jason/lib/helpers.ex +90 -0
- data/helpers/deps/jason/lib/jason.ex +228 -0
- data/helpers/deps/jason/mix.exs +92 -0
- data/helpers/lib/check_update.exs +92 -0
- data/helpers/lib/do_update.exs +39 -0
- data/helpers/lib/parse_deps.exs +103 -0
- data/helpers/lib/run.exs +76 -0
- data/helpers/mix.exs +21 -0
- data/helpers/mix.lock +3 -0
- data/lib/dependabot/hex.rb +11 -0
- data/lib/dependabot/hex/file_fetcher.rb +79 -0
- data/lib/dependabot/hex/file_parser.rb +125 -0
- data/lib/dependabot/hex/file_updater.rb +71 -0
- data/lib/dependabot/hex/file_updater/lockfile_updater.rb +142 -0
- data/lib/dependabot/hex/file_updater/mixfile_git_pin_updater.rb +51 -0
- data/lib/dependabot/hex/file_updater/mixfile_requirement_updater.rb +72 -0
- data/lib/dependabot/hex/file_updater/mixfile_sanitizer.rb +26 -0
- data/lib/dependabot/hex/file_updater/mixfile_updater.rb +94 -0
- data/lib/dependabot/hex/metadata_finder.rb +70 -0
- data/lib/dependabot/hex/native_helpers.rb +20 -0
- data/lib/dependabot/hex/requirement.rb +53 -0
- data/lib/dependabot/hex/update_checker.rb +275 -0
- data/lib/dependabot/hex/update_checker/file_preparer.rb +191 -0
- data/lib/dependabot/hex/update_checker/requirements_updater.rb +173 -0
- data/lib/dependabot/hex/update_checker/version_resolver.rb +170 -0
- data/lib/dependabot/hex/version.rb +67 -0
- metadata +208 -0
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "dependabot/file_updaters"
|
|
4
|
+
require "dependabot/file_updaters/base"
|
|
5
|
+
require "dependabot/shared_helpers"
|
|
6
|
+
|
|
7
|
+
module Dependabot
|
|
8
|
+
module Hex
|
|
9
|
+
class FileUpdater < Dependabot::FileUpdaters::Base
|
|
10
|
+
require_relative "file_updater/mixfile_updater"
|
|
11
|
+
require_relative "file_updater/lockfile_updater"
|
|
12
|
+
|
|
13
|
+
def self.updated_files_regex
|
|
14
|
+
[
|
|
15
|
+
/^mix\.exs$/,
|
|
16
|
+
/^mix\.lock$/
|
|
17
|
+
]
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def updated_dependency_files
|
|
21
|
+
updated_files = []
|
|
22
|
+
|
|
23
|
+
mixfiles.each do |file|
|
|
24
|
+
if file_changed?(file)
|
|
25
|
+
updated_files <<
|
|
26
|
+
updated_file(file: file, content: updated_mixfile_content(file))
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
if lockfile
|
|
31
|
+
updated_files <<
|
|
32
|
+
updated_file(file: lockfile, content: updated_lockfile_content)
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
updated_files
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
private
|
|
39
|
+
|
|
40
|
+
def check_required_files
|
|
41
|
+
raise "No mix.exs!" unless get_original_file("mix.exs")
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def updated_mixfile_content(file)
|
|
45
|
+
MixfileUpdater.new(
|
|
46
|
+
dependencies: dependencies,
|
|
47
|
+
mixfile: file
|
|
48
|
+
).updated_mixfile_content
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
def updated_lockfile_content
|
|
52
|
+
@updated_lockfile_content ||=
|
|
53
|
+
LockfileUpdater.new(
|
|
54
|
+
dependencies: dependencies,
|
|
55
|
+
dependency_files: dependency_files,
|
|
56
|
+
credentials: credentials
|
|
57
|
+
).updated_lockfile_content
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
def mixfiles
|
|
61
|
+
dependency_files.select { |f| f.name.end_with?("mix.exs") }
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
def lockfile
|
|
65
|
+
@lockfile ||= get_original_file("mix.lock")
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
Dependabot::FileUpdaters.register("hex", Dependabot::Hex::FileUpdater)
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "dependabot/hex/file_updater"
|
|
4
|
+
require "dependabot/hex/file_updater/mixfile_updater"
|
|
5
|
+
require "dependabot/hex/file_updater/mixfile_sanitizer"
|
|
6
|
+
require "dependabot/hex/file_updater/mixfile_requirement_updater"
|
|
7
|
+
require "dependabot/hex/version"
|
|
8
|
+
require "dependabot/hex/native_helpers"
|
|
9
|
+
require "dependabot/shared_helpers"
|
|
10
|
+
|
|
11
|
+
module Dependabot
|
|
12
|
+
module Hex
|
|
13
|
+
class FileUpdater
|
|
14
|
+
class LockfileUpdater
|
|
15
|
+
def initialize(dependencies:, dependency_files:, credentials:)
|
|
16
|
+
@dependencies = dependencies
|
|
17
|
+
@dependency_files = dependency_files
|
|
18
|
+
@credentials = credentials
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def updated_lockfile_content
|
|
22
|
+
@updated_lockfile_content ||=
|
|
23
|
+
SharedHelpers.in_a_temporary_directory do
|
|
24
|
+
write_temporary_dependency_files
|
|
25
|
+
FileUtils.cp(elixir_helper_do_update_path, "do_update.exs")
|
|
26
|
+
|
|
27
|
+
SharedHelpers.with_git_configured(credentials: credentials) do
|
|
28
|
+
SharedHelpers.run_helper_subprocess(
|
|
29
|
+
env: mix_env,
|
|
30
|
+
command: "mix run #{elixir_helper_path}",
|
|
31
|
+
function: "get_updated_lockfile",
|
|
32
|
+
args: [Dir.pwd, dependency.name, organization_credentials]
|
|
33
|
+
)
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
post_process_lockfile(@updated_lockfile_content)
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
private
|
|
41
|
+
|
|
42
|
+
attr_reader :dependencies, :dependency_files, :credentials
|
|
43
|
+
|
|
44
|
+
def dependency
|
|
45
|
+
# For now, we'll only ever be updating a single dep for Elixir
|
|
46
|
+
dependencies.first
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
def post_process_lockfile(content)
|
|
50
|
+
return content unless lockfile.content.start_with?("%{\"")
|
|
51
|
+
return content if content.start_with?("%{\"")
|
|
52
|
+
|
|
53
|
+
# Substitute back old file beginning and ending
|
|
54
|
+
content.sub(/\A%\{\n "/, "%{\"").sub(/\},\n\}/, "}}")
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
def write_temporary_dependency_files
|
|
58
|
+
mixfiles.each do |file|
|
|
59
|
+
path = file.name
|
|
60
|
+
FileUtils.mkdir_p(Pathname.new(path).dirname)
|
|
61
|
+
File.write(path, mixfile_content_for_lockfile_generation(file))
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
File.write("mix.lock", lockfile.content)
|
|
65
|
+
|
|
66
|
+
dependency_files.select(&:support_file).each do |file|
|
|
67
|
+
path = file.name
|
|
68
|
+
FileUtils.mkdir_p(Pathname.new(path).dirname)
|
|
69
|
+
File.write(path, file.content)
|
|
70
|
+
end
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
def mixfile_content_for_lockfile_generation(file)
|
|
74
|
+
content = updated_mixfile_content(file)
|
|
75
|
+
content = lock_mixfile_dependency_versions(content, file.name)
|
|
76
|
+
sanitize_mixfile(content)
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
def updated_mixfile_content(file)
|
|
80
|
+
MixfileUpdater.new(
|
|
81
|
+
dependencies: dependencies,
|
|
82
|
+
mixfile: file
|
|
83
|
+
).updated_mixfile_content
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
def lock_mixfile_dependency_versions(mixfile_content, filename)
|
|
87
|
+
dependencies.
|
|
88
|
+
reduce(mixfile_content.dup) do |content, dep|
|
|
89
|
+
# Run on the updated mixfile content, so we're updating from the
|
|
90
|
+
# updated requirements
|
|
91
|
+
req_details = dep.requirements.find { |r| r[:file] == filename }
|
|
92
|
+
|
|
93
|
+
next content unless req_details
|
|
94
|
+
next content unless Hex::Version.correct?(dep.version)
|
|
95
|
+
|
|
96
|
+
MixfileRequirementUpdater.new(
|
|
97
|
+
dependency_name: dep.name,
|
|
98
|
+
mixfile_content: content,
|
|
99
|
+
previous_requirement: req_details.fetch(:requirement),
|
|
100
|
+
updated_requirement: dep.version,
|
|
101
|
+
insert_if_bare: true
|
|
102
|
+
).updated_content
|
|
103
|
+
end
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
def sanitize_mixfile(content)
|
|
107
|
+
MixfileSanitizer.new(mixfile_content: content).sanitized_content
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
def mix_env
|
|
111
|
+
{
|
|
112
|
+
"MIX_EXS" => File.join(NativeHelpers.hex_helpers_dir, "mix.exs"),
|
|
113
|
+
"MIX_LOCK" => File.join(NativeHelpers.hex_helpers_dir, "mix.lock"),
|
|
114
|
+
"MIX_DEPS" => File.join(NativeHelpers.hex_helpers_dir, "deps"),
|
|
115
|
+
"MIX_QUIET" => "1"
|
|
116
|
+
}
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
def elixir_helper_path
|
|
120
|
+
File.join(NativeHelpers.hex_helpers_dir, "lib/run.exs")
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
def elixir_helper_do_update_path
|
|
124
|
+
File.join(NativeHelpers.hex_helpers_dir, "lib/do_update.exs")
|
|
125
|
+
end
|
|
126
|
+
|
|
127
|
+
def mixfiles
|
|
128
|
+
dependency_files.select { |f| f.name.end_with?("mix.exs") }
|
|
129
|
+
end
|
|
130
|
+
|
|
131
|
+
def lockfile
|
|
132
|
+
@lockfile ||= dependency_files.find { |f| f.name == "mix.lock" }
|
|
133
|
+
end
|
|
134
|
+
|
|
135
|
+
def organization_credentials
|
|
136
|
+
credentials.select { |cred| cred["type"] == "hex_organization" }.
|
|
137
|
+
flat_map { |cred| [cred["organization"], cred["token"]] }
|
|
138
|
+
end
|
|
139
|
+
end
|
|
140
|
+
end
|
|
141
|
+
end
|
|
142
|
+
end
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "dependabot/hex/file_updater"
|
|
4
|
+
require "dependabot/shared_helpers"
|
|
5
|
+
|
|
6
|
+
module Dependabot
|
|
7
|
+
module Hex
|
|
8
|
+
class FileUpdater
|
|
9
|
+
class MixfileGitPinUpdater
|
|
10
|
+
def initialize(dependency_name:, mixfile_content:,
|
|
11
|
+
previous_pin:, updated_pin:)
|
|
12
|
+
@dependency_name = dependency_name
|
|
13
|
+
@mixfile_content = mixfile_content
|
|
14
|
+
@previous_pin = previous_pin
|
|
15
|
+
@updated_pin = updated_pin
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def updated_content
|
|
19
|
+
updated_content = update_pin(mixfile_content)
|
|
20
|
+
|
|
21
|
+
if content_should_change? && mixfile_content == updated_content
|
|
22
|
+
raise "Expected content to change!"
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
updated_content
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
private
|
|
29
|
+
|
|
30
|
+
attr_reader :dependency_name, :mixfile_content,
|
|
31
|
+
:previous_pin, :updated_pin
|
|
32
|
+
|
|
33
|
+
def update_pin(content)
|
|
34
|
+
requirement_line_regex =
|
|
35
|
+
/
|
|
36
|
+
\{\s*:#{Regexp.escape(dependency_name)},[^\}]*
|
|
37
|
+
(?:ref|tag):\s+["']#{Regexp.escape(previous_pin)}["']
|
|
38
|
+
/mx
|
|
39
|
+
|
|
40
|
+
content.gsub(requirement_line_regex) do |requirement_line|
|
|
41
|
+
requirement_line.gsub(previous_pin, updated_pin)
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
def content_should_change?
|
|
46
|
+
previous_pin == updated_pin
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
end
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "dependabot/hex/file_updater"
|
|
4
|
+
require "dependabot/shared_helpers"
|
|
5
|
+
|
|
6
|
+
module Dependabot
|
|
7
|
+
module Hex
|
|
8
|
+
class FileUpdater
|
|
9
|
+
class MixfileRequirementUpdater
|
|
10
|
+
def initialize(dependency_name:, mixfile_content:,
|
|
11
|
+
previous_requirement:, updated_requirement:,
|
|
12
|
+
insert_if_bare: false)
|
|
13
|
+
@dependency_name = dependency_name
|
|
14
|
+
@mixfile_content = mixfile_content
|
|
15
|
+
@previous_requirement = previous_requirement
|
|
16
|
+
@updated_requirement = updated_requirement
|
|
17
|
+
@insert_if_bare = insert_if_bare
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def updated_content
|
|
21
|
+
updated_content = update_requirement(mixfile_content)
|
|
22
|
+
|
|
23
|
+
if content_should_change? && mixfile_content == updated_content
|
|
24
|
+
raise "Expected content to change!"
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
updated_content
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
private
|
|
31
|
+
|
|
32
|
+
attr_reader :dependency_name, :mixfile_content,
|
|
33
|
+
:previous_requirement, :updated_requirement
|
|
34
|
+
|
|
35
|
+
def insert_if_bare?
|
|
36
|
+
!@insert_if_bare.nil?
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def update_requirement(content)
|
|
40
|
+
return content if previous_requirement.nil? && !insert_if_bare?
|
|
41
|
+
|
|
42
|
+
requirement_line_regex =
|
|
43
|
+
if previous_requirement
|
|
44
|
+
/
|
|
45
|
+
:#{Regexp.escape(dependency_name)}\s*,.*
|
|
46
|
+
#{Regexp.escape(previous_requirement)}
|
|
47
|
+
/x
|
|
48
|
+
else
|
|
49
|
+
/:#{Regexp.escape(dependency_name)}(,|\s|\})/
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
content.gsub(requirement_line_regex) do |requirement_line|
|
|
53
|
+
if previous_requirement
|
|
54
|
+
requirement_line.gsub(previous_requirement, updated_requirement)
|
|
55
|
+
else
|
|
56
|
+
requirement_line.gsub(
|
|
57
|
+
":#{dependency_name}",
|
|
58
|
+
":#{dependency_name}, \"#{updated_requirement}\""
|
|
59
|
+
)
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
def content_should_change?
|
|
65
|
+
return false if previous_requirement == updated_requirement
|
|
66
|
+
|
|
67
|
+
previous_requirement || insert_if_bare?
|
|
68
|
+
end
|
|
69
|
+
end
|
|
70
|
+
end
|
|
71
|
+
end
|
|
72
|
+
end
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "dependabot/hex/file_updater"
|
|
4
|
+
require "dependabot/shared_helpers"
|
|
5
|
+
|
|
6
|
+
module Dependabot
|
|
7
|
+
module Hex
|
|
8
|
+
class FileUpdater
|
|
9
|
+
class MixfileSanitizer
|
|
10
|
+
def initialize(mixfile_content:)
|
|
11
|
+
@mixfile_content = mixfile_content
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def sanitized_content
|
|
15
|
+
mixfile_content.
|
|
16
|
+
gsub(/File\.read!\(.*?\)/, '"0.0.1"').
|
|
17
|
+
gsub(/File\.read\(.*?\)/, '{:ok, "0.0.1"}')
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
private
|
|
21
|
+
|
|
22
|
+
attr_reader :mixfile_content
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "dependabot/hex/file_updater"
|
|
4
|
+
require "dependabot/hex/file_updater/mixfile_requirement_updater"
|
|
5
|
+
require "dependabot/hex/file_updater/mixfile_git_pin_updater"
|
|
6
|
+
|
|
7
|
+
module Dependabot
|
|
8
|
+
module Hex
|
|
9
|
+
class FileUpdater
|
|
10
|
+
class MixfileUpdater
|
|
11
|
+
def initialize(mixfile:, dependencies:)
|
|
12
|
+
@mixfile = mixfile
|
|
13
|
+
@dependencies = dependencies
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def updated_mixfile_content
|
|
17
|
+
dependencies.
|
|
18
|
+
select { |dep| requirement_changed?(mixfile, dep) }.
|
|
19
|
+
reduce(mixfile.content.dup) do |content, dep|
|
|
20
|
+
updated_content = content
|
|
21
|
+
|
|
22
|
+
updated_content = update_requirement(
|
|
23
|
+
content: updated_content,
|
|
24
|
+
filename: mixfile.name,
|
|
25
|
+
dependency: dep
|
|
26
|
+
)
|
|
27
|
+
|
|
28
|
+
updated_content = update_git_pin(
|
|
29
|
+
content: updated_content,
|
|
30
|
+
filename: mixfile.name,
|
|
31
|
+
dependency: dep
|
|
32
|
+
)
|
|
33
|
+
|
|
34
|
+
raise "Expected content to change!" if content == updated_content
|
|
35
|
+
|
|
36
|
+
updated_content
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
private
|
|
41
|
+
|
|
42
|
+
attr_reader :mixfile, :dependencies
|
|
43
|
+
|
|
44
|
+
def requirement_changed?(file, dependency)
|
|
45
|
+
changed_requirements =
|
|
46
|
+
dependency.requirements - dependency.previous_requirements
|
|
47
|
+
|
|
48
|
+
changed_requirements.any? { |f| f[:file] == file.name }
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
def update_requirement(content:, filename:, dependency:)
|
|
52
|
+
updated_req =
|
|
53
|
+
dependency.requirements.find { |r| r[:file] == filename }.
|
|
54
|
+
fetch(:requirement)
|
|
55
|
+
|
|
56
|
+
old_req =
|
|
57
|
+
dependency.previous_requirements.
|
|
58
|
+
find { |r| r[:file] == filename }.
|
|
59
|
+
fetch(:requirement)
|
|
60
|
+
|
|
61
|
+
return content unless old_req
|
|
62
|
+
|
|
63
|
+
MixfileRequirementUpdater.new(
|
|
64
|
+
dependency_name: dependency.name,
|
|
65
|
+
mixfile_content: content,
|
|
66
|
+
previous_requirement: old_req,
|
|
67
|
+
updated_requirement: updated_req
|
|
68
|
+
).updated_content
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
def update_git_pin(content:, filename:, dependency:)
|
|
72
|
+
updated_pin =
|
|
73
|
+
dependency.requirements.find { |r| r[:file] == filename }&.
|
|
74
|
+
dig(:source, :ref)
|
|
75
|
+
|
|
76
|
+
old_pin =
|
|
77
|
+
dependency.previous_requirements.
|
|
78
|
+
find { |r| r[:file] == filename }&.
|
|
79
|
+
dig(:source, :ref)
|
|
80
|
+
|
|
81
|
+
return content unless old_pin
|
|
82
|
+
return content if old_pin == updated_pin
|
|
83
|
+
|
|
84
|
+
MixfileGitPinUpdater.new(
|
|
85
|
+
dependency_name: dependency.name,
|
|
86
|
+
mixfile_content: content,
|
|
87
|
+
previous_pin: old_pin,
|
|
88
|
+
updated_pin: updated_pin
|
|
89
|
+
).updated_content
|
|
90
|
+
end
|
|
91
|
+
end
|
|
92
|
+
end
|
|
93
|
+
end
|
|
94
|
+
end
|