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.
Files changed (41) hide show
  1. checksums.yaml +7 -0
  2. data/helpers/build +19 -0
  3. data/helpers/deps/jason/.fetch +0 -0
  4. data/helpers/deps/jason/.hex +2 -0
  5. data/helpers/deps/jason/CHANGELOG.md +60 -0
  6. data/helpers/deps/jason/LICENSE +13 -0
  7. data/helpers/deps/jason/README.md +179 -0
  8. data/helpers/deps/jason/hex_metadata.config +20 -0
  9. data/helpers/deps/jason/lib/codegen.ex +158 -0
  10. data/helpers/deps/jason/lib/decoder.ex +657 -0
  11. data/helpers/deps/jason/lib/encode.ex +630 -0
  12. data/helpers/deps/jason/lib/encoder.ex +216 -0
  13. data/helpers/deps/jason/lib/formatter.ex +253 -0
  14. data/helpers/deps/jason/lib/fragment.ex +11 -0
  15. data/helpers/deps/jason/lib/helpers.ex +90 -0
  16. data/helpers/deps/jason/lib/jason.ex +228 -0
  17. data/helpers/deps/jason/mix.exs +92 -0
  18. data/helpers/lib/check_update.exs +92 -0
  19. data/helpers/lib/do_update.exs +39 -0
  20. data/helpers/lib/parse_deps.exs +103 -0
  21. data/helpers/lib/run.exs +76 -0
  22. data/helpers/mix.exs +21 -0
  23. data/helpers/mix.lock +3 -0
  24. data/lib/dependabot/hex.rb +11 -0
  25. data/lib/dependabot/hex/file_fetcher.rb +79 -0
  26. data/lib/dependabot/hex/file_parser.rb +125 -0
  27. data/lib/dependabot/hex/file_updater.rb +71 -0
  28. data/lib/dependabot/hex/file_updater/lockfile_updater.rb +142 -0
  29. data/lib/dependabot/hex/file_updater/mixfile_git_pin_updater.rb +51 -0
  30. data/lib/dependabot/hex/file_updater/mixfile_requirement_updater.rb +72 -0
  31. data/lib/dependabot/hex/file_updater/mixfile_sanitizer.rb +26 -0
  32. data/lib/dependabot/hex/file_updater/mixfile_updater.rb +94 -0
  33. data/lib/dependabot/hex/metadata_finder.rb +70 -0
  34. data/lib/dependabot/hex/native_helpers.rb +20 -0
  35. data/lib/dependabot/hex/requirement.rb +53 -0
  36. data/lib/dependabot/hex/update_checker.rb +275 -0
  37. data/lib/dependabot/hex/update_checker/file_preparer.rb +191 -0
  38. data/lib/dependabot/hex/update_checker/requirements_updater.rb +173 -0
  39. data/lib/dependabot/hex/update_checker/version_resolver.rb +170 -0
  40. data/lib/dependabot/hex/version.rb +67 -0
  41. 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