dependabot-elm 0.82.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/lib/dependabot/elm/file_fetcher.rb +53 -0
- data/lib/dependabot/elm/file_parser.rb +137 -0
- data/lib/dependabot/elm/file_updater.rb +80 -0
- data/lib/dependabot/elm/file_updater/elm_json_updater.rb +67 -0
- data/lib/dependabot/elm/file_updater/elm_package_updater.rb +67 -0
- data/lib/dependabot/elm/metadata_finder.rb +24 -0
- data/lib/dependabot/elm/requirement.rb +94 -0
- data/lib/dependabot/elm/update_checker.rb +128 -0
- data/lib/dependabot/elm/update_checker/cli_parser.rb +31 -0
- data/lib/dependabot/elm/update_checker/elm_18_version_resolver.rb +232 -0
- data/lib/dependabot/elm/update_checker/elm_19_version_resolver.rb +196 -0
- data/lib/dependabot/elm/update_checker/requirements_updater.rb +73 -0
- data/lib/dependabot/elm/version.rb +22 -0
- metadata +183 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: e4631c5a095b12bcb7680efa489f38c3706a65f02b6aff6bb5ac77efc5252301
|
4
|
+
data.tar.gz: f501e81ff96e0262008737a04ef0c952ae1ca6b4a799ed686761af7b29c25dc8
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 1289f30665a25cd7b5e98ced8d71c1b794311ccb9cbbfec89f6be6dab6d5f9210e135181ea979a5b3031149d316f3602e5480616c42cc4ae313552e63e78c1a6
|
7
|
+
data.tar.gz: a7ceb51fa33fbc0e94f44a305fe513e1483777dbfeb09f53a0e3b06d5d4163beaec1bec7c6ebaee6b7f05eb6a2a72026a101cac10d2d47ec122b286b86e5239e
|
@@ -0,0 +1,53 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "dependabot/file_fetchers"
|
4
|
+
require "dependabot/file_fetchers/base"
|
5
|
+
|
6
|
+
module Dependabot
|
7
|
+
module Elm
|
8
|
+
class FileFetcher < Dependabot::FileFetchers::Base
|
9
|
+
def self.required_files_in?(filenames)
|
10
|
+
return true if filenames.include?("elm-package.json")
|
11
|
+
|
12
|
+
filenames.include?("elm.json")
|
13
|
+
end
|
14
|
+
|
15
|
+
def self.required_files_message
|
16
|
+
"Repo must contain an elm-package.json or an elm.json"
|
17
|
+
end
|
18
|
+
|
19
|
+
private
|
20
|
+
|
21
|
+
def fetch_files
|
22
|
+
fetched_files = []
|
23
|
+
|
24
|
+
fetched_files << elm_package if elm_package
|
25
|
+
fetched_files << elm_json if elm_json
|
26
|
+
|
27
|
+
# Note: We *do not* fetch the exact-dependencies.json file, as it is
|
28
|
+
# recommended that this is not committed
|
29
|
+
|
30
|
+
check_required_files_present
|
31
|
+
fetched_files
|
32
|
+
end
|
33
|
+
|
34
|
+
def check_required_files_present
|
35
|
+
return if elm_package || elm_json
|
36
|
+
|
37
|
+
path = Pathname.new(File.join(directory, "elm.json")).
|
38
|
+
cleanpath.to_path
|
39
|
+
raise Dependabot::DependencyFileNotFound, path
|
40
|
+
end
|
41
|
+
|
42
|
+
def elm_package
|
43
|
+
@elm_package ||= fetch_file_if_present("elm-package.json")
|
44
|
+
end
|
45
|
+
|
46
|
+
def elm_json
|
47
|
+
@elm_json ||= fetch_file_if_present("elm.json")
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
Dependabot::FileFetchers.register("elm-package", Dependabot::Elm::FileFetcher)
|
@@ -0,0 +1,137 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "dependabot/dependency"
|
4
|
+
require "dependabot/errors"
|
5
|
+
require "dependabot/file_parsers"
|
6
|
+
require "dependabot/file_parsers/base"
|
7
|
+
require "dependabot/elm/requirement"
|
8
|
+
|
9
|
+
module Dependabot
|
10
|
+
module Elm
|
11
|
+
class FileParser < Dependabot::FileParsers::Base
|
12
|
+
require "dependabot/file_parsers/base/dependency_set"
|
13
|
+
|
14
|
+
DEPENDENCY_TYPES = %w(dependencies test-dependencies).freeze
|
15
|
+
|
16
|
+
def parse
|
17
|
+
dependency_set = DependencySet.new
|
18
|
+
|
19
|
+
dependency_set += elm_package_dependencies if elm_package
|
20
|
+
dependency_set += elm_json_dependencies if elm_json
|
21
|
+
|
22
|
+
dependency_set.dependencies.sort_by(&:name)
|
23
|
+
end
|
24
|
+
|
25
|
+
private
|
26
|
+
|
27
|
+
def elm_package_dependencies
|
28
|
+
dependency_set = DependencySet.new
|
29
|
+
|
30
|
+
parsed_package_file.fetch("dependencies").each do |name, req|
|
31
|
+
dependency_set <<
|
32
|
+
Dependency.new(
|
33
|
+
name: name,
|
34
|
+
version: version_for(req)&.to_s,
|
35
|
+
requirements: [{
|
36
|
+
requirement: req, # 4.0 <= v <= 4.0
|
37
|
+
groups: [], # we don't have this (its dev vs non-dev)
|
38
|
+
source: nil, # elm-package only has elm-package sources
|
39
|
+
file: "elm-package.json"
|
40
|
+
}],
|
41
|
+
package_manager: "elm-package"
|
42
|
+
)
|
43
|
+
end
|
44
|
+
|
45
|
+
dependency_set
|
46
|
+
end
|
47
|
+
|
48
|
+
# For docs on elm.json, see:
|
49
|
+
# https://github.com/elm/compiler/blob/master/docs/elm.json/application.md
|
50
|
+
# https://github.com/elm/compiler/blob/master/docs/elm.json/package.md
|
51
|
+
def elm_json_dependencies
|
52
|
+
dependency_set = DependencySet.new
|
53
|
+
|
54
|
+
DEPENDENCY_TYPES.each do |dep_type|
|
55
|
+
if repo_type == "application"
|
56
|
+
dependencies_hash = parsed_elm_json.fetch(dep_type, {})
|
57
|
+
dependencies_hash.fetch("direct", {}).each do |name, req|
|
58
|
+
dependency_set << build_elm_json_dependency(
|
59
|
+
name: name, group: dep_type, requirement: req, direct: true
|
60
|
+
)
|
61
|
+
end
|
62
|
+
dependencies_hash.fetch("indirect", {}).each do |name, req|
|
63
|
+
dependency_set << build_elm_json_dependency(
|
64
|
+
name: name, group: dep_type, requirement: req, direct: false
|
65
|
+
)
|
66
|
+
end
|
67
|
+
elsif repo_type == "package"
|
68
|
+
parsed_elm_json.fetch(dep_type, {}).each do |name, req|
|
69
|
+
dependency_set << build_elm_json_dependency(
|
70
|
+
name: name, group: dep_type, requirement: req, direct: true
|
71
|
+
)
|
72
|
+
end
|
73
|
+
else raise "Unexpected repo type for Elm repo: #{repo_type}"
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
dependency_set
|
78
|
+
end
|
79
|
+
|
80
|
+
def build_elm_json_dependency(name:, group:, requirement:, direct:)
|
81
|
+
requirements = [{
|
82
|
+
requirement: requirement,
|
83
|
+
groups: [group],
|
84
|
+
source: nil,
|
85
|
+
file: "elm.json"
|
86
|
+
}]
|
87
|
+
|
88
|
+
Dependency.new(
|
89
|
+
name: name,
|
90
|
+
version: version_for(requirement)&.to_s,
|
91
|
+
requirements: direct ? requirements : [],
|
92
|
+
package_manager: "elm-package"
|
93
|
+
)
|
94
|
+
end
|
95
|
+
|
96
|
+
def repo_type
|
97
|
+
parsed_elm_json.fetch("type")
|
98
|
+
end
|
99
|
+
|
100
|
+
def check_required_files
|
101
|
+
return if elm_json || elm_package
|
102
|
+
|
103
|
+
raise "No elm.json or elm-package.json!"
|
104
|
+
end
|
105
|
+
|
106
|
+
def version_for(version_requirement)
|
107
|
+
req = Dependabot::Elm::Requirement.new(version_requirement)
|
108
|
+
|
109
|
+
return unless req.exact?
|
110
|
+
|
111
|
+
req.requirements.first.last
|
112
|
+
end
|
113
|
+
|
114
|
+
def parsed_package_file
|
115
|
+
@parsed_package_file ||= JSON.parse(elm_package.content)
|
116
|
+
rescue JSON::ParserError
|
117
|
+
raise Dependabot::DependencyFileNotParseable, elm_package.path
|
118
|
+
end
|
119
|
+
|
120
|
+
def parsed_elm_json
|
121
|
+
@parsed_elm_json ||= JSON.parse(elm_json.content)
|
122
|
+
rescue JSON::ParserError
|
123
|
+
raise Dependabot::DependencyFileNotParseable, elm_json.path
|
124
|
+
end
|
125
|
+
|
126
|
+
def elm_package
|
127
|
+
@elm_package ||= get_original_file("elm-package.json")
|
128
|
+
end
|
129
|
+
|
130
|
+
def elm_json
|
131
|
+
@elm_json ||= get_original_file("elm.json")
|
132
|
+
end
|
133
|
+
end
|
134
|
+
end
|
135
|
+
end
|
136
|
+
|
137
|
+
Dependabot::FileParsers.register("elm-package", Dependabot::Elm::FileParser)
|
@@ -0,0 +1,80 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "dependabot/file_updaters"
|
4
|
+
require "dependabot/file_updaters/base"
|
5
|
+
|
6
|
+
module Dependabot
|
7
|
+
module Elm
|
8
|
+
class FileUpdater < Dependabot::FileUpdaters::Base
|
9
|
+
require_relative "file_updater/elm_package_updater"
|
10
|
+
require_relative "file_updater/elm_json_updater"
|
11
|
+
|
12
|
+
def self.updated_files_regex
|
13
|
+
[
|
14
|
+
/^elm-package\.json$/,
|
15
|
+
/^elm\.json$/
|
16
|
+
]
|
17
|
+
end
|
18
|
+
|
19
|
+
def updated_dependency_files
|
20
|
+
updated_files = []
|
21
|
+
|
22
|
+
elm_package_files.each do |file|
|
23
|
+
next unless file_changed?(file)
|
24
|
+
|
25
|
+
updated_files <<
|
26
|
+
updated_file(
|
27
|
+
file: file,
|
28
|
+
content: updated_elm_package_content(file)
|
29
|
+
)
|
30
|
+
end
|
31
|
+
|
32
|
+
elm_json_files.each do |file|
|
33
|
+
next unless file_changed?(file)
|
34
|
+
|
35
|
+
updated_files <<
|
36
|
+
updated_file(
|
37
|
+
file: file,
|
38
|
+
content: updated_elm_json_content(file)
|
39
|
+
)
|
40
|
+
end
|
41
|
+
|
42
|
+
raise "No files have changed!" if updated_files.none?
|
43
|
+
|
44
|
+
updated_files
|
45
|
+
end
|
46
|
+
|
47
|
+
private
|
48
|
+
|
49
|
+
def check_required_files
|
50
|
+
return if elm_json_files.any? || elm_package_files.any?
|
51
|
+
|
52
|
+
raise "No elm.json or elm-package.json!"
|
53
|
+
end
|
54
|
+
|
55
|
+
def updated_elm_package_content(file)
|
56
|
+
ElmPackageUpdater.new(
|
57
|
+
dependencies: dependencies,
|
58
|
+
elm_package_file: file
|
59
|
+
).updated_elm_package_file_content
|
60
|
+
end
|
61
|
+
|
62
|
+
def updated_elm_json_content(file)
|
63
|
+
ElmJsonUpdater.new(
|
64
|
+
dependencies: dependencies,
|
65
|
+
elm_json_file: file
|
66
|
+
).updated_content
|
67
|
+
end
|
68
|
+
|
69
|
+
def elm_package_files
|
70
|
+
dependency_files.select { |f| f.name.end_with?("elm-package.json") }
|
71
|
+
end
|
72
|
+
|
73
|
+
def elm_json_files
|
74
|
+
dependency_files.select { |f| f.name.end_with?("elm.json") }
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
Dependabot::FileUpdaters.register("elm-package", Dependabot::Elm::FileUpdater)
|
@@ -0,0 +1,67 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "dependabot/elm/file_updater"
|
4
|
+
|
5
|
+
module Dependabot
|
6
|
+
module Elm
|
7
|
+
class FileUpdater
|
8
|
+
class ElmJsonUpdater
|
9
|
+
def initialize(elm_json_file:, dependencies:)
|
10
|
+
@elm_json_file = elm_json_file
|
11
|
+
@dependencies = dependencies
|
12
|
+
end
|
13
|
+
|
14
|
+
def updated_content
|
15
|
+
dependencies.
|
16
|
+
select { |dep| requirement_changed?(elm_json_file, dep) }.
|
17
|
+
reduce(elm_json_file.content.dup) do |content, dep|
|
18
|
+
updated_content = content
|
19
|
+
|
20
|
+
updated_content = update_requirement(
|
21
|
+
content: updated_content,
|
22
|
+
filename: elm_json_file.name,
|
23
|
+
dependency: dep
|
24
|
+
)
|
25
|
+
|
26
|
+
next updated_content unless content == updated_content
|
27
|
+
|
28
|
+
raise "Expected content to change!"
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
private
|
33
|
+
|
34
|
+
attr_reader :elm_json_file, :dependencies
|
35
|
+
|
36
|
+
def requirement_changed?(file, dependency)
|
37
|
+
changed_requirements =
|
38
|
+
dependency.requirements - dependency.previous_requirements
|
39
|
+
|
40
|
+
changed_requirements.any? { |f| f[:file] == file.name }
|
41
|
+
end
|
42
|
+
|
43
|
+
def update_requirement(content:, filename:, dependency:)
|
44
|
+
updated_req =
|
45
|
+
dependency.requirements.
|
46
|
+
find { |r| r.fetch(:file) == filename }.
|
47
|
+
fetch(:requirement)
|
48
|
+
|
49
|
+
old_req =
|
50
|
+
dependency.previous_requirements.
|
51
|
+
find { |r| r.fetch(:file) == filename }.
|
52
|
+
fetch(:requirement)
|
53
|
+
|
54
|
+
return content unless old_req
|
55
|
+
|
56
|
+
dep = dependency
|
57
|
+
regex =
|
58
|
+
/"#{Regexp.quote(dep.name)}"\s*:\s+"#{Regexp.quote(old_req)}"/
|
59
|
+
|
60
|
+
content.gsub(regex) do |declaration|
|
61
|
+
declaration.gsub(%("#{old_req}"), %("#{updated_req}"))
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
@@ -0,0 +1,67 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "dependabot/elm/file_updater"
|
4
|
+
|
5
|
+
module Dependabot
|
6
|
+
module Elm
|
7
|
+
class FileUpdater
|
8
|
+
class ElmPackageUpdater
|
9
|
+
def initialize(elm_package_file:, dependencies:)
|
10
|
+
@elm_package_file = elm_package_file
|
11
|
+
@dependencies = dependencies
|
12
|
+
end
|
13
|
+
|
14
|
+
def updated_elm_package_file_content
|
15
|
+
dependencies.
|
16
|
+
select { |dep| requirement_changed?(elm_package_file, dep) }.
|
17
|
+
reduce(elm_package_file.content.dup) do |content, dep|
|
18
|
+
updated_content = content
|
19
|
+
|
20
|
+
updated_content = update_requirement(
|
21
|
+
content: updated_content,
|
22
|
+
filename: elm_package_file.name,
|
23
|
+
dependency: dep
|
24
|
+
)
|
25
|
+
|
26
|
+
next updated_content unless content == updated_content
|
27
|
+
|
28
|
+
raise "Expected content to change!"
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
private
|
33
|
+
|
34
|
+
attr_reader :elm_package_file, :dependencies
|
35
|
+
|
36
|
+
def requirement_changed?(file, dependency)
|
37
|
+
changed_requirements =
|
38
|
+
dependency.requirements - dependency.previous_requirements
|
39
|
+
|
40
|
+
changed_requirements.any? { |f| f[:file] == file.name }
|
41
|
+
end
|
42
|
+
|
43
|
+
def update_requirement(content:, filename:, dependency:)
|
44
|
+
updated_req =
|
45
|
+
dependency.requirements.
|
46
|
+
find { |r| r.fetch(:file) == filename }.
|
47
|
+
fetch(:requirement)
|
48
|
+
|
49
|
+
old_req =
|
50
|
+
dependency.previous_requirements.
|
51
|
+
find { |r| r.fetch(:file) == filename }.
|
52
|
+
fetch(:requirement)
|
53
|
+
|
54
|
+
return content unless old_req
|
55
|
+
|
56
|
+
dep = dependency
|
57
|
+
regex =
|
58
|
+
/"#{Regexp.quote(dep.name)}"\s*:\s+"#{Regexp.quote(old_req)}"/
|
59
|
+
|
60
|
+
content.gsub(regex) do |declaration|
|
61
|
+
declaration.gsub(%("#{old_req}"), %("#{updated_req}"))
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "dependabot/metadata_finders"
|
4
|
+
require "dependabot/metadata_finders/base"
|
5
|
+
require "dependabot/source"
|
6
|
+
|
7
|
+
module Dependabot
|
8
|
+
module Elm
|
9
|
+
class MetadataFinder < Dependabot::MetadataFinders::Base
|
10
|
+
private
|
11
|
+
|
12
|
+
def look_up_source
|
13
|
+
# For Elm 0.18 an elm-package is guaranteed to be `owner/name`
|
14
|
+
# on github. For 0.19 a lot will change, including the name of
|
15
|
+
# the dependency file, so I won't try to build something more
|
16
|
+
# sophisticated here for now.
|
17
|
+
Source.from_url("https://github.com/" + dependency.name)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
Dependabot::MetadataFinders.
|
24
|
+
register("elm-package", Dependabot::Elm::MetadataFinder)
|
@@ -0,0 +1,94 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "dependabot/utils"
|
4
|
+
require "dependabot/elm/version"
|
5
|
+
|
6
|
+
module Dependabot
|
7
|
+
module Elm
|
8
|
+
class Requirement < Gem::Requirement
|
9
|
+
# Override the version pattern to allow local versions
|
10
|
+
PATTERN_RAW =
|
11
|
+
"(#{Elm::Version::VERSION_PATTERN}) (<=?) v (<=?) " \
|
12
|
+
"(#{Elm::Version::VERSION_PATTERN})"
|
13
|
+
PATTERN = /\A#{PATTERN_RAW}\z/.freeze
|
14
|
+
EXACT_PATTERN = /\A#{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 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 [["=", 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 [["=", Elm::Version.new(matches[4])]]
|
39
|
+
end
|
40
|
+
|
41
|
+
[
|
42
|
+
[matches[2].tr("<", ">"), Elm::Version.new(matches[1])],
|
43
|
+
[matches[3], 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 = Elm::Version.new(version.to_s)
|
87
|
+
super
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
Dependabot::Utils.
|
94
|
+
register_requirement_class("elm-package", Dependabot::Elm::Requirement)
|