dependabot-terraform 0.145.4 → 0.148.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 +4 -4
- data/helpers/build +7 -4
- data/lib/dependabot/terraform/file_fetcher.rb +5 -2
- data/lib/dependabot/terraform/file_parser.rb +82 -44
- data/lib/dependabot/terraform/file_selector.rb +17 -0
- data/lib/dependabot/terraform/file_updater.rb +6 -11
- data/lib/dependabot/terraform/metadata_finder.rb +2 -19
- data/lib/dependabot/terraform/registry_client.rb +103 -0
- data/lib/dependabot/terraform/requirements_updater.rb +44 -3
- data/lib/dependabot/terraform/update_checker.rb +30 -16
- metadata +8 -6
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 7d7706b0b1a4caf093c24a35a6c49398abfa8c96b6ad18dc7db44bab894c7581
|
4
|
+
data.tar.gz: f482a7a71f487f0815ff464b189edab66c0a77e3d4ffdd1b5a5080e17680de27
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: bc1983b4f79f865bac2a1f12f379c96f649b7b4056d67c96a6a3d6d2ad0a27e653b216baad1f85aba931bd8c1510a01e4913e32307b91a4311b2160c60e80f44
|
7
|
+
data.tar.gz: d7b18e3cb48784d3fe22c305b6f609d75a7c553d3191305c3b30d2cecd45274a85b615f9513867f08a9d9ff07ae8b248dab1a8198a3c724b159c58016c0126f4
|
data/helpers/build
CHANGED
@@ -13,7 +13,10 @@ if [ ! -d "$install_dir/bin" ]; then
|
|
13
13
|
fi
|
14
14
|
|
15
15
|
os="$(uname -s | tr '[:upper:]' '[:lower:]')"
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
16
|
+
|
17
|
+
hcl2json_checksum="24068f1e25a34d8f8ca763f34fce11527472891bfa834d1504f665855021d5d4"
|
18
|
+
hcl2json_url="https://github.com/tmccombs/hcl2json/releases/download/v0.3.3/hcl2json_${os}_amd64"
|
19
|
+
hcl2json_path="$install_dir/bin/hcl2json"
|
20
|
+
wget -O "$hcl2json_path" "$hcl2json_url"
|
21
|
+
echo "$hcl2json_checksum $hcl2json_path" | sha256sum -c
|
22
|
+
chmod +x "$install_dir/bin/hcl2json"
|
@@ -2,12 +2,15 @@
|
|
2
2
|
|
3
3
|
require "dependabot/file_fetchers"
|
4
4
|
require "dependabot/file_fetchers/base"
|
5
|
+
require "dependabot/terraform/file_selector"
|
5
6
|
|
6
7
|
module Dependabot
|
7
8
|
module Terraform
|
8
9
|
class FileFetcher < Dependabot::FileFetchers::Base
|
10
|
+
include FileSelector
|
11
|
+
|
9
12
|
def self.required_files_in?(filenames)
|
10
|
-
filenames.any? { |f| f.end_with?(".tf", ".
|
13
|
+
filenames.any? { |f| f.end_with?(".tf", ".hcl") }
|
11
14
|
end
|
12
15
|
|
13
16
|
def self.required_files_message
|
@@ -39,7 +42,7 @@ module Dependabot
|
|
39
42
|
def terragrunt_files
|
40
43
|
@terragrunt_files ||=
|
41
44
|
repo_contents(raise_errors: false).
|
42
|
-
select { |f| f.type == "file" && f.name
|
45
|
+
select { |f| f.type == "file" && terragrunt_file?(f.name) }.
|
43
46
|
map { |f| fetch_file_from_host(f.name) }
|
44
47
|
end
|
45
48
|
end
|
@@ -10,27 +10,38 @@ require "dependabot/file_parsers/base"
|
|
10
10
|
require "dependabot/git_commit_checker"
|
11
11
|
require "dependabot/shared_helpers"
|
12
12
|
require "dependabot/errors"
|
13
|
+
require "dependabot/terraform/file_selector"
|
13
14
|
|
14
15
|
module Dependabot
|
15
16
|
module Terraform
|
16
17
|
class FileParser < Dependabot::FileParsers::Base
|
17
18
|
require "dependabot/file_parsers/base/dependency_set"
|
18
19
|
|
20
|
+
include FileSelector
|
21
|
+
|
19
22
|
ARCHIVE_EXTENSIONS = %w(.zip .tbz2 .tgz .txz).freeze
|
20
23
|
|
21
24
|
def parse
|
22
25
|
dependency_set = DependencySet.new
|
23
26
|
|
24
27
|
terraform_files.each do |file|
|
25
|
-
modules = parsed_file(file).fetch("module",
|
28
|
+
modules = parsed_file(file).fetch("module", {})
|
26
29
|
modules.each do |name, details|
|
27
|
-
dependency_set << build_terraform_dependency(file, name, details)
|
30
|
+
dependency_set << build_terraform_dependency(file, name, details, false)
|
31
|
+
end
|
32
|
+
|
33
|
+
parsed_file(file).fetch("terraform", []).each do |terraform|
|
34
|
+
required_providers = terraform.fetch("required_providers", {})
|
35
|
+
required_providers.each do |provider|
|
36
|
+
provider.each do |name, details|
|
37
|
+
dependency_set << build_terraform_dependency(file, name, details, true)
|
38
|
+
end
|
39
|
+
end
|
28
40
|
end
|
29
41
|
end
|
30
42
|
|
31
43
|
terragrunt_files.each do |file|
|
32
|
-
modules = parsed_file(file).fetch("
|
33
|
-
modules = modules.fetch("terraform", [])
|
44
|
+
modules = parsed_file(file).fetch("terraform", [])
|
34
45
|
modules.each do |details|
|
35
46
|
next unless details["source"]
|
36
47
|
|
@@ -38,17 +49,20 @@ module Dependabot
|
|
38
49
|
end
|
39
50
|
end
|
40
51
|
|
41
|
-
dependency_set.dependencies
|
52
|
+
dependency_set.dependencies.sort_by(&:name)
|
42
53
|
end
|
43
54
|
|
44
55
|
private
|
45
56
|
|
46
|
-
def build_terraform_dependency(file, name, details)
|
47
|
-
details = details.first
|
57
|
+
def build_terraform_dependency(file, name, details, provider)
|
58
|
+
details = details.is_a?(Array) ? details.first : details
|
48
59
|
|
49
|
-
source = source_from(details)
|
50
|
-
dep_name =
|
51
|
-
|
60
|
+
source = source_from(details, provider)
|
61
|
+
dep_name = case source[:type]
|
62
|
+
when "registry" then source[:module_identifier]
|
63
|
+
when "provider" then details["source"]
|
64
|
+
else name
|
65
|
+
end
|
52
66
|
version_req = details["version"]&.strip
|
53
67
|
version =
|
54
68
|
if source[:type] == "git" then version_from_ref(source[:ref])
|
@@ -69,7 +83,7 @@ module Dependabot
|
|
69
83
|
end
|
70
84
|
|
71
85
|
def build_terragrunt_dependency(file, details)
|
72
|
-
source = source_from(details)
|
86
|
+
source = source_from(details, false)
|
73
87
|
dep_name =
|
74
88
|
if Source.from_url(source[:url])
|
75
89
|
Source.from_url(source[:url]).repo
|
@@ -93,7 +107,7 @@ module Dependabot
|
|
93
107
|
end
|
94
108
|
|
95
109
|
# Full docs at https://www.terraform.io/docs/modules/sources.html
|
96
|
-
def source_from(details_hash)
|
110
|
+
def source_from(details_hash, provider)
|
97
111
|
raw_source = details_hash.fetch("source")
|
98
112
|
bare_source = get_proxied_source(raw_source)
|
99
113
|
|
@@ -104,17 +118,23 @@ module Dependabot
|
|
104
118
|
when :github, :bitbucket, :git
|
105
119
|
git_source_details_from(bare_source)
|
106
120
|
when :registry
|
107
|
-
registry_source_details_from(bare_source)
|
121
|
+
registry_source_details_from(bare_source, provider)
|
108
122
|
end
|
109
123
|
|
110
124
|
source_details[:proxy_url] = raw_source if raw_source != bare_source
|
111
125
|
source_details
|
112
126
|
end
|
113
127
|
|
114
|
-
def registry_source_details_from(source_string)
|
128
|
+
def registry_source_details_from(source_string, provider)
|
115
129
|
parts = source_string.split("//").first.split("/")
|
116
130
|
|
117
|
-
if parts.count ==
|
131
|
+
if provider && parts.count == 2
|
132
|
+
{
|
133
|
+
"type": "provider",
|
134
|
+
"registry_hostname": "registry.terraform.io",
|
135
|
+
"module_identifier": source_string
|
136
|
+
}
|
137
|
+
elsif parts.count == 3
|
118
138
|
{
|
119
139
|
type: "registry",
|
120
140
|
registry_hostname: "registry.terraform.io",
|
@@ -210,30 +230,51 @@ module Dependabot
|
|
210
230
|
end
|
211
231
|
# rubocop:enable Metrics/PerceivedComplexity
|
212
232
|
|
233
|
+
# == Returns:
|
234
|
+
# A Hash representing each module found in the specified file
|
235
|
+
#
|
236
|
+
# E.g.
|
237
|
+
# {
|
238
|
+
# "module" => {
|
239
|
+
# {
|
240
|
+
# "consul" => [
|
241
|
+
# {
|
242
|
+
# "source"=>"consul/aws",
|
243
|
+
# "version"=>"0.1.0"
|
244
|
+
# }
|
245
|
+
# ]
|
246
|
+
# }
|
247
|
+
# },
|
248
|
+
# "terragrunt"=>[
|
249
|
+
# {
|
250
|
+
# "include"=>[{ "path"=>"${find_in_parent_folders()}" }],
|
251
|
+
# "terraform"=>[{ "source" => "git::git@github.com:gruntwork-io/modules-example.git//consul?ref=v0.0.2" }]
|
252
|
+
# }
|
253
|
+
# ],
|
254
|
+
# }
|
213
255
|
def parsed_file(file)
|
214
256
|
@parsed_buildfile ||= {}
|
215
|
-
@parsed_buildfile[file.name] ||=
|
216
|
-
|
217
|
-
|
218
|
-
|
219
|
-
|
220
|
-
|
221
|
-
|
222
|
-
|
223
|
-
|
224
|
-
|
225
|
-
|
226
|
-
|
227
|
-
|
228
|
-
|
229
|
-
|
230
|
-
|
231
|
-
|
232
|
-
)
|
233
|
-
end
|
234
|
-
|
235
|
-
JSON.parse(stdout)
|
257
|
+
@parsed_buildfile[file.name] ||= SharedHelpers.in_a_temporary_directory do
|
258
|
+
File.write("tmp.tf", file.content)
|
259
|
+
|
260
|
+
command = "#{terraform_hcl2_parser_path} < tmp.tf"
|
261
|
+
start = Time.now
|
262
|
+
stdout, stderr, process = Open3.capture3(command)
|
263
|
+
time_taken = Time.now - start
|
264
|
+
|
265
|
+
unless process.success?
|
266
|
+
raise SharedHelpers::HelperSubprocessFailed.new(
|
267
|
+
message: stderr,
|
268
|
+
error_context: {
|
269
|
+
command: command,
|
270
|
+
time_taken: time_taken,
|
271
|
+
process_exit_value: process.to_s
|
272
|
+
}
|
273
|
+
)
|
236
274
|
end
|
275
|
+
|
276
|
+
JSON.parse(stdout)
|
277
|
+
end
|
237
278
|
rescue SharedHelpers::HelperSubprocessFailed => e
|
238
279
|
msg = e.message.strip
|
239
280
|
raise Dependabot::DependencyFileNotParseable.new(file.path, msg)
|
@@ -244,19 +285,16 @@ module Dependabot
|
|
244
285
|
Pathname.new(File.join(helper_bin_dir, "json2hcl")).cleanpath.to_path
|
245
286
|
end
|
246
287
|
|
288
|
+
def terraform_hcl2_parser_path
|
289
|
+
helper_bin_dir = File.join(native_helpers_root, "terraform/bin")
|
290
|
+
Pathname.new(File.join(helper_bin_dir, "hcl2json")).cleanpath.to_path
|
291
|
+
end
|
292
|
+
|
247
293
|
def native_helpers_root
|
248
294
|
default_path = File.join(__dir__, "../../../helpers/install-dir")
|
249
295
|
ENV.fetch("DEPENDABOT_NATIVE_HELPERS_PATH", default_path)
|
250
296
|
end
|
251
297
|
|
252
|
-
def terraform_files
|
253
|
-
dependency_files.select { |f| f.name.end_with?(".tf") }
|
254
|
-
end
|
255
|
-
|
256
|
-
def terragrunt_files
|
257
|
-
dependency_files.select { |f| f.name.end_with?(".tfvars") }
|
258
|
-
end
|
259
|
-
|
260
298
|
def check_required_files
|
261
299
|
return if [*terraform_files, *terragrunt_files].any?
|
262
300
|
|
@@ -0,0 +1,17 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module FileSelector
|
4
|
+
private
|
5
|
+
|
6
|
+
def terraform_files
|
7
|
+
dependency_files.select { |f| f.name.end_with?(".tf") }
|
8
|
+
end
|
9
|
+
|
10
|
+
def terragrunt_files
|
11
|
+
dependency_files.select { |f| terragrunt_file?(f.name) }
|
12
|
+
end
|
13
|
+
|
14
|
+
def terragrunt_file?(file_name)
|
15
|
+
file_name != ".terraform.lock.hcl" && file_name.end_with?(".hcl")
|
16
|
+
end
|
17
|
+
end
|
@@ -3,12 +3,15 @@
|
|
3
3
|
require "dependabot/file_updaters"
|
4
4
|
require "dependabot/file_updaters/base"
|
5
5
|
require "dependabot/errors"
|
6
|
+
require "dependabot/terraform/file_selector"
|
6
7
|
|
7
8
|
module Dependabot
|
8
9
|
module Terraform
|
9
10
|
class FileUpdater < Dependabot::FileUpdaters::Base
|
11
|
+
include FileSelector
|
12
|
+
|
10
13
|
def self.updated_files_regex
|
11
|
-
[/\.tf$/, /\.
|
14
|
+
[/\.tf$/, /\.hcl$/]
|
12
15
|
end
|
13
16
|
|
14
17
|
def updated_dependency_files
|
@@ -44,7 +47,7 @@ module Dependabot
|
|
44
47
|
case new_req[:source][:type]
|
45
48
|
when "git"
|
46
49
|
update_git_declaration(new_req, old_req, content, file.name)
|
47
|
-
when "registry"
|
50
|
+
when "registry", "provider"
|
48
51
|
update_registry_declaration(new_req, old_req, content)
|
49
52
|
else
|
50
53
|
raise "Don't know how to update a #{new_req[:source][:type]} "\
|
@@ -87,14 +90,6 @@ module Dependabot
|
|
87
90
|
dependency_files.select { |file| filenames.include?(file.name) }
|
88
91
|
end
|
89
92
|
|
90
|
-
def terraform_files
|
91
|
-
dependency_files.select { |f| f.name.end_with?(".tf") }
|
92
|
-
end
|
93
|
-
|
94
|
-
def terragrunt_files
|
95
|
-
dependency_files.select { |f| f.name.end_with?(".tfvars") }
|
96
|
-
end
|
97
|
-
|
98
93
|
def check_required_files
|
99
94
|
return if [*terraform_files, *terragrunt_files].any?
|
100
95
|
|
@@ -113,7 +108,7 @@ module Dependabot
|
|
113
108
|
def git_declaration_regex(filename)
|
114
109
|
# For terragrunt dependencies there's not a lot we can base the
|
115
110
|
# regex on. Just look for declarations within a `terraform` block
|
116
|
-
return /terraform\s*\{(?:(?!^\}).)*/m if
|
111
|
+
return /terraform\s*\{(?:(?!^\}).)*/m if terragrunt_file?(filename)
|
117
112
|
|
118
113
|
# For modules we can do better - filter for module blocks that use the
|
119
114
|
# name of the dependency
|
@@ -15,6 +15,7 @@ module Dependabot
|
|
15
15
|
case new_source_type
|
16
16
|
when "git" then find_source_from_git_url
|
17
17
|
when "registry" then find_source_from_registry_details
|
18
|
+
when "provider" then find_source_from_provider_details
|
18
19
|
else raise "Unexpected source type: #{new_source_type}"
|
19
20
|
end
|
20
21
|
end
|
@@ -36,29 +37,11 @@ module Dependabot
|
|
36
37
|
Source.from_url(url)
|
37
38
|
end
|
38
39
|
|
39
|
-
# Registry API docs:
|
40
|
-
# https://www.terraform.io/docs/registry/api.html
|
41
40
|
def find_source_from_registry_details
|
42
41
|
info = dependency.requirements.map { |r| r[:source] }.compact.first
|
43
|
-
|
44
42
|
hostname = info[:registry_hostname] || info["registry_hostname"]
|
45
43
|
|
46
|
-
|
47
|
-
return unless hostname == "registry.terraform.io"
|
48
|
-
|
49
|
-
url = "https://registry.terraform.io/v1/modules/"\
|
50
|
-
"#{dependency.name}/#{dependency.version}"
|
51
|
-
|
52
|
-
response = Excon.get(
|
53
|
-
url,
|
54
|
-
idempotent: true,
|
55
|
-
**SharedHelpers.excon_defaults
|
56
|
-
)
|
57
|
-
|
58
|
-
raise "Response from registry was #{response.status}" unless response.status == 200
|
59
|
-
|
60
|
-
source_url = JSON.parse(response.body).fetch("source")
|
61
|
-
Source.from_url(source_url) if source_url
|
44
|
+
RegistryClient.new(hostname: hostname).source(dependency: dependency)
|
62
45
|
end
|
63
46
|
end
|
64
47
|
end
|
@@ -0,0 +1,103 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "dependabot/dependency"
|
4
|
+
require "dependabot/source"
|
5
|
+
require "dependabot/terraform/version"
|
6
|
+
|
7
|
+
module Dependabot
|
8
|
+
module Terraform
|
9
|
+
# Terraform::RegistryClient is a basic API client to interact with a
|
10
|
+
# terraform registry: https://www.terraform.io/docs/registry/api.html
|
11
|
+
class RegistryClient
|
12
|
+
PUBLIC_HOSTNAME = "registry.terraform.io"
|
13
|
+
|
14
|
+
def initialize(hostname:)
|
15
|
+
@hostname = hostname
|
16
|
+
end
|
17
|
+
|
18
|
+
# Fetch all the versions of a provider, and return a Version
|
19
|
+
# representation of them.
|
20
|
+
#
|
21
|
+
# @param identifier [String] the identifier for the dependency, i.e:
|
22
|
+
# "hashicorp/aws"
|
23
|
+
# @return [Array<Dependabot::Terraform::Version>]
|
24
|
+
# @raise [RuntimeError] when the versions cannot be retrieved
|
25
|
+
def all_provider_versions(identifier:)
|
26
|
+
# TODO: Implement service discovery for custom registries
|
27
|
+
return [] unless hostname == PUBLIC_HOSTNAME
|
28
|
+
|
29
|
+
response = get(endpoint: "providers/#{identifier}/versions")
|
30
|
+
|
31
|
+
JSON.parse(response).
|
32
|
+
fetch("versions").
|
33
|
+
map { |release| version_class.new(release.fetch("version")) }
|
34
|
+
end
|
35
|
+
|
36
|
+
# Fetch all the versions of a module, and return a Version
|
37
|
+
# representation of them.
|
38
|
+
#
|
39
|
+
# @param identifier [String] the identifier for the dependency, i.e:
|
40
|
+
# "hashicorp/consul/aws"
|
41
|
+
# @return [Array<Dependabot::Terraform::Version>]
|
42
|
+
# @raise [RuntimeError] when the versions cannot be retrieved
|
43
|
+
def all_module_versions(identifier:)
|
44
|
+
# TODO: Implement service discovery for custom registries
|
45
|
+
return [] unless hostname == PUBLIC_HOSTNAME
|
46
|
+
|
47
|
+
response = get(endpoint: "modules/#{identifier}/versions")
|
48
|
+
|
49
|
+
JSON.parse(response).
|
50
|
+
fetch("modules").first.fetch("versions").
|
51
|
+
map { |release| version_class.new(release.fetch("version")) }
|
52
|
+
end
|
53
|
+
|
54
|
+
# Fetch the "source" for a module or provider. We use the API to fetch
|
55
|
+
# the source for a dependency, this typically points to a source code
|
56
|
+
# repository, and then instantiate a Dependabot::Source object that we
|
57
|
+
# can use to fetch Metadata about a specific version of the dependency.
|
58
|
+
#
|
59
|
+
# @param dependency [Dependabot::Dependency] the dependency who's source
|
60
|
+
# we're attempting to find
|
61
|
+
# @return Dependabot::Source
|
62
|
+
# @raise [RuntimeError] when the source cannot be retrieved
|
63
|
+
def source(dependency:)
|
64
|
+
# TODO: Implement service discovery for custom registries
|
65
|
+
return unless hostname == PUBLIC_HOSTNAME
|
66
|
+
|
67
|
+
endpoint = if dependency.requirements.first[:source][:type] == "registry"
|
68
|
+
"modules/#{dependency.name}/#{dependency.version}"
|
69
|
+
elsif dependency.source[:type] == "provider"
|
70
|
+
"providers/#{dependency.name}/#{dependency.version}"
|
71
|
+
else
|
72
|
+
raise "Invalid source type"
|
73
|
+
end
|
74
|
+
response = get(endpoint: endpoint)
|
75
|
+
|
76
|
+
source_url = JSON.parse(response).fetch("source")
|
77
|
+
Source.from_url(source_url) if source_url
|
78
|
+
end
|
79
|
+
|
80
|
+
private
|
81
|
+
|
82
|
+
attr_reader :hostname
|
83
|
+
|
84
|
+
def get(endpoint:)
|
85
|
+
url = "https://#{hostname}/v1/#{endpoint}"
|
86
|
+
|
87
|
+
response = Excon.get(
|
88
|
+
url,
|
89
|
+
idempotent: true,
|
90
|
+
**SharedHelpers.excon_defaults
|
91
|
+
)
|
92
|
+
|
93
|
+
raise "Response from registry was #{response.status}" unless response.status == 200
|
94
|
+
|
95
|
+
response.body
|
96
|
+
end
|
97
|
+
|
98
|
+
def version_class
|
99
|
+
Version
|
100
|
+
end
|
101
|
+
end
|
102
|
+
end
|
103
|
+
end
|
@@ -10,9 +10,45 @@ require "dependabot/terraform/requirement"
|
|
10
10
|
|
11
11
|
module Dependabot
|
12
12
|
module Terraform
|
13
|
+
# Takes an array of `requirements` hashes for a dependency at the old
|
14
|
+
# version and a new version, and generates a set of new `requirements`
|
15
|
+
# hashes at the new version.
|
16
|
+
#
|
17
|
+
# A requirements hash is a basic description of a dependency at a certain
|
18
|
+
# version constraint, and it includes the data that is needed to update the
|
19
|
+
# manifest (i.e. the `.tf` file) with the new version.
|
20
|
+
#
|
21
|
+
# A requirements hash looks like this for a registry hosted requirement:
|
22
|
+
# ```ruby
|
23
|
+
# {
|
24
|
+
# requirement: "~> 0.2.1",
|
25
|
+
# groups: [],
|
26
|
+
# file: "main.tf",
|
27
|
+
# source: {
|
28
|
+
# type: "registry",
|
29
|
+
# registry_hostname: "registry.terraform.io",
|
30
|
+
# module_identifier: "hashicorp/consul/aws"
|
31
|
+
# }
|
32
|
+
# }
|
33
|
+
#
|
34
|
+
# And like this for a git requirement:
|
35
|
+
# ```ruby
|
36
|
+
# {
|
37
|
+
# requirement: nil,
|
38
|
+
# groups: [],
|
39
|
+
# file: "main.tf",
|
40
|
+
# source: {
|
41
|
+
# type: "git",
|
42
|
+
# url: "https://github.com/cloudposse/terraform-null-label.git",
|
43
|
+
# branch: nil,
|
44
|
+
# ref: nil
|
45
|
+
# }
|
46
|
+
# }
|
13
47
|
class RequirementsUpdater
|
14
|
-
|
15
|
-
|
48
|
+
# @param requirements [Hash{Symbol => String, Array, Hash}]
|
49
|
+
# @param latest_version [Dependabot::Terraform::Version]
|
50
|
+
# @param tag_for_latest_version [String, NilClass]
|
51
|
+
def initialize(requirements:, latest_version:, tag_for_latest_version:)
|
16
52
|
@requirements = requirements
|
17
53
|
@tag_for_latest_version = tag_for_latest_version
|
18
54
|
|
@@ -22,6 +58,11 @@ module Dependabot
|
|
22
58
|
@latest_version = version_class.new(latest_version)
|
23
59
|
end
|
24
60
|
|
61
|
+
# @return requirements [Hash{Symbol => String, Array, Hash}]
|
62
|
+
# * requirement [String, NilClass] the updated version constraint
|
63
|
+
# * groups [Array] no-op for terraform
|
64
|
+
# * file [String] the file that specified this dependency
|
65
|
+
# * source [Hash{Symbol => String}] The updated git or registry source details
|
25
66
|
def updated_requirements
|
26
67
|
return requirements unless latest_version
|
27
68
|
|
@@ -31,7 +72,7 @@ module Dependabot
|
|
31
72
|
requirements.map do |req|
|
32
73
|
case req.dig(:source, :type)
|
33
74
|
when "git" then update_git_requirement(req)
|
34
|
-
when "registry" then update_registry_requirement(req)
|
75
|
+
when "registry", "provider" then update_registry_requirement(req)
|
35
76
|
else req
|
36
77
|
end
|
37
78
|
end
|
@@ -6,6 +6,7 @@ require "dependabot/git_commit_checker"
|
|
6
6
|
require "dependabot/terraform/requirements_updater"
|
7
7
|
require "dependabot/terraform/requirement"
|
8
8
|
require "dependabot/terraform/version"
|
9
|
+
require "dependabot/terraform/registry_client"
|
9
10
|
|
10
11
|
module Dependabot
|
11
12
|
module Terraform
|
@@ -13,6 +14,7 @@ module Dependabot
|
|
13
14
|
def latest_version
|
14
15
|
return latest_version_for_git_dependency if git_dependency?
|
15
16
|
return latest_version_for_registry_dependency if registry_dependency?
|
17
|
+
return latest_version_for_provider_dependency if provider_dependency?
|
16
18
|
# Other sources (mercurial, path dependencies) just return `nil`
|
17
19
|
end
|
18
20
|
|
@@ -65,34 +67,40 @@ module Dependabot
|
|
65
67
|
|
66
68
|
return @latest_version_for_registry_dependency if @latest_version_for_registry_dependency
|
67
69
|
|
68
|
-
versions =
|
70
|
+
versions = all_module_versions
|
69
71
|
versions.reject!(&:prerelease?) unless wants_prerelease?
|
70
72
|
versions.reject! { |v| ignore_requirements.any? { |r| r.satisfied_by?(v) } }
|
71
73
|
|
72
74
|
@latest_version_for_registry_dependency = versions.max
|
73
75
|
end
|
74
76
|
|
75
|
-
def
|
76
|
-
hostname = dependency_source_details.fetch(:registry_hostname)
|
77
|
+
def all_module_versions
|
77
78
|
identifier = dependency_source_details.fetch(:module_identifier)
|
79
|
+
registry_client.all_module_versions(identifier: identifier)
|
80
|
+
end
|
81
|
+
|
82
|
+
def all_provider_versions
|
83
|
+
identifier = dependency_source_details.fetch(:module_identifier)
|
84
|
+
registry_client.all_provider_versions(identifier: identifier)
|
85
|
+
end
|
78
86
|
|
79
|
-
|
80
|
-
|
87
|
+
def registry_client
|
88
|
+
@registry_client ||= begin
|
89
|
+
hostname = dependency_source_details.fetch(:registry_hostname)
|
90
|
+
RegistryClient.new(hostname: hostname)
|
91
|
+
end
|
92
|
+
end
|
81
93
|
|
82
|
-
|
83
|
-
|
94
|
+
def latest_version_for_provider_dependency
|
95
|
+
return unless provider_dependency?
|
84
96
|
|
85
|
-
|
86
|
-
url,
|
87
|
-
idempotent: true,
|
88
|
-
**SharedHelpers.excon_defaults
|
89
|
-
)
|
97
|
+
return @latest_version_for_provider_dependency if @latest_version_for_provider_dependency
|
90
98
|
|
91
|
-
|
99
|
+
versions = all_provider_versions
|
100
|
+
versions.reject!(&:prerelease?) unless wants_prerelease?
|
101
|
+
versions.reject! { |v| ignore_requirements.any? { |r| r.satisfied_by?(v) } }
|
92
102
|
|
93
|
-
|
94
|
-
fetch("modules").first.fetch("versions").
|
95
|
-
map { |release| version_class.new(release.fetch("version")) }
|
103
|
+
@latest_version_for_provider_dependency = versions.max
|
96
104
|
end
|
97
105
|
|
98
106
|
def wants_prerelease?
|
@@ -160,6 +168,12 @@ module Dependabot
|
|
160
168
|
dependency_source_details.fetch(:type) == "registry"
|
161
169
|
end
|
162
170
|
|
171
|
+
def provider_dependency?
|
172
|
+
return false if dependency_source_details.nil?
|
173
|
+
|
174
|
+
dependency_source_details.fetch(:type) == "provider"
|
175
|
+
end
|
176
|
+
|
163
177
|
def dependency_source_details
|
164
178
|
sources =
|
165
179
|
dependency.requirements.map { |r| r.fetch(:source) }.uniq.compact
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: dependabot-terraform
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.148.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Dependabot
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2021-05-
|
11
|
+
date: 2021-05-19 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: dependabot-common
|
@@ -16,14 +16,14 @@ dependencies:
|
|
16
16
|
requirements:
|
17
17
|
- - '='
|
18
18
|
- !ruby/object:Gem::Version
|
19
|
-
version: 0.
|
19
|
+
version: 0.148.0
|
20
20
|
type: :runtime
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
24
|
- - '='
|
25
25
|
- !ruby/object:Gem::Version
|
26
|
-
version: 0.
|
26
|
+
version: 0.148.0
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
28
|
name: byebug
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
@@ -100,14 +100,14 @@ dependencies:
|
|
100
100
|
requirements:
|
101
101
|
- - "~>"
|
102
102
|
- !ruby/object:Gem::Version
|
103
|
-
version: 1.
|
103
|
+
version: 1.15.0
|
104
104
|
type: :development
|
105
105
|
prerelease: false
|
106
106
|
version_requirements: !ruby/object:Gem::Requirement
|
107
107
|
requirements:
|
108
108
|
- - "~>"
|
109
109
|
- !ruby/object:Gem::Version
|
110
|
-
version: 1.
|
110
|
+
version: 1.15.0
|
111
111
|
- !ruby/object:Gem::Dependency
|
112
112
|
name: simplecov
|
113
113
|
requirement: !ruby/object:Gem::Requirement
|
@@ -189,8 +189,10 @@ files:
|
|
189
189
|
- lib/dependabot/terraform.rb
|
190
190
|
- lib/dependabot/terraform/file_fetcher.rb
|
191
191
|
- lib/dependabot/terraform/file_parser.rb
|
192
|
+
- lib/dependabot/terraform/file_selector.rb
|
192
193
|
- lib/dependabot/terraform/file_updater.rb
|
193
194
|
- lib/dependabot/terraform/metadata_finder.rb
|
195
|
+
- lib/dependabot/terraform/registry_client.rb
|
194
196
|
- lib/dependabot/terraform/requirement.rb
|
195
197
|
- lib/dependabot/terraform/requirements_updater.rb
|
196
198
|
- lib/dependabot/terraform/update_checker.rb
|