dependabot-terraform 0.276.0 → 0.278.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/dependabot/terraform/file_parser.rb +62 -15
- data/lib/dependabot/terraform/requirements_updater.rb +40 -5
- metadata +5 -5
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: '0059476ade84fa4d8a339c043e92765b9d6450709dd8aa8586028475cd81e5c1'
|
4
|
+
data.tar.gz: 33bc7b677c302cec97626e87afa70403e1d00b36555ebd98e2cd650feb2d69f6
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 15a6b7ed503d8fcd2b74a71313738e22fe147c1cdccbac4d7ae19e95e7f19be0dc41b1dabde9dfb0d4323c5835e23a0efe050e9d8489daf69117df74a119c5e5
|
7
|
+
data.tar.gz: eb68a5abb5816299d59c31d937cef7327860f9fd22966f979d78df4a5b7ad0b69db6d73c5db8ca8540c824463530487cc3b82e3d20e1e28867c463071f2a5a47
|
@@ -1,4 +1,4 @@
|
|
1
|
-
# typed:
|
1
|
+
# typed: strict
|
2
2
|
# frozen_string_literal: true
|
3
3
|
|
4
4
|
require "cgi"
|
@@ -30,6 +30,7 @@ module Dependabot
|
|
30
30
|
# https://www.terraform.io/docs/language/providers/requirements.html#source-addresses
|
31
31
|
PROVIDER_SOURCE_ADDRESS = %r{\A((?<hostname>.+)/)?(?<namespace>.+)/(?<name>.+)\z}
|
32
32
|
|
33
|
+
sig { override.returns(T::Array[Dependabot::Dependency]) }
|
33
34
|
def parse
|
34
35
|
dependency_set = DependencySet.new
|
35
36
|
|
@@ -42,6 +43,7 @@ module Dependabot
|
|
42
43
|
|
43
44
|
private
|
44
45
|
|
46
|
+
sig { params(dependency_set: Dependabot::FileParsers::Base::DependencySet).void }
|
45
47
|
def parse_terraform_files(dependency_set)
|
46
48
|
terraform_files.each do |file|
|
47
49
|
modules = parsed_file(file).fetch("module", {})
|
@@ -50,9 +52,9 @@ module Dependabot
|
|
50
52
|
|
51
53
|
source = source_from(details)
|
52
54
|
# Cannot update local path modules, skip
|
53
|
-
next if source[:type] == "path"
|
55
|
+
next if source && source[:type] == "path"
|
54
56
|
|
55
|
-
dependency_set << build_terraform_dependency(file, name, source, details)
|
57
|
+
dependency_set << build_terraform_dependency(file, name, T.must(source), details)
|
56
58
|
end
|
57
59
|
|
58
60
|
parsed_file(file).fetch("terraform", []).each do |terraform|
|
@@ -66,6 +68,7 @@ module Dependabot
|
|
66
68
|
end
|
67
69
|
end
|
68
70
|
|
71
|
+
sig { params(dependency_set: Dependabot::FileParsers::Base::DependencySet).void }
|
69
72
|
def parse_terragrunt_files(dependency_set)
|
70
73
|
terragrunt_files.each do |file|
|
71
74
|
modules = parsed_file(file).fetch("terraform", [])
|
@@ -81,6 +84,15 @@ module Dependabot
|
|
81
84
|
end
|
82
85
|
end
|
83
86
|
|
87
|
+
sig do
|
88
|
+
params(
|
89
|
+
file: Dependabot::DependencyFile,
|
90
|
+
name: String,
|
91
|
+
source: T::Hash[Symbol, T.untyped],
|
92
|
+
details: T.untyped
|
93
|
+
)
|
94
|
+
.returns(Dependabot::Dependency)
|
95
|
+
end
|
84
96
|
def build_terraform_dependency(file, name, source, details)
|
85
97
|
# dep_name should be unique for a source, using the info derived from
|
86
98
|
# the source or the source name provides this uniqueness
|
@@ -109,17 +121,25 @@ module Dependabot
|
|
109
121
|
)
|
110
122
|
end
|
111
123
|
|
124
|
+
sig do
|
125
|
+
params(
|
126
|
+
file: Dependabot::DependencyFile,
|
127
|
+
name: String,
|
128
|
+
details: T.any(String, T::Hash[String, T.untyped])
|
129
|
+
)
|
130
|
+
.returns(Dependabot::Dependency)
|
131
|
+
end
|
112
132
|
def build_provider_dependency(file, name, details = {})
|
113
133
|
deprecated_provider_error(file) if deprecated_provider?(details)
|
114
134
|
|
115
|
-
source_address = details.fetch("source", nil)
|
135
|
+
source_address = T.cast(details, T::Hash[String, T.untyped]).fetch("source", nil)
|
116
136
|
version_req = details["version"]&.strip
|
117
137
|
hostname, namespace, name = provider_source_from(source_address, name)
|
118
138
|
dependency_name = source_address ? "#{namespace}/#{name}" : name
|
119
139
|
|
120
140
|
Dependency.new(
|
121
|
-
name: dependency_name,
|
122
|
-
version: determine_version_for(hostname, namespace, name, version_req),
|
141
|
+
name: T.must(dependency_name),
|
142
|
+
version: determine_version_for(T.must(hostname), T.must(namespace), T.must(name), version_req),
|
123
143
|
package_manager: "terraform",
|
124
144
|
requirements: [
|
125
145
|
requirement: version_req,
|
@@ -134,6 +154,7 @@ module Dependabot
|
|
134
154
|
)
|
135
155
|
end
|
136
156
|
|
157
|
+
sig { params(file: Dependabot::DependencyFile).returns(T.noreturn) }
|
137
158
|
def deprecated_provider_error(file)
|
138
159
|
raise Dependabot::DependencyFileNotParseable.new(
|
139
160
|
file.path,
|
@@ -143,18 +164,20 @@ module Dependabot
|
|
143
164
|
)
|
144
165
|
end
|
145
166
|
|
167
|
+
sig { params(details: Object).returns(T::Boolean) }
|
146
168
|
def deprecated_provider?(details)
|
147
169
|
# The old syntax for terraform providers v0.12- looked like
|
148
170
|
# "tls ~> 2.1" which gets parsed as a string instead of a hash
|
149
171
|
details.is_a?(String)
|
150
172
|
end
|
151
173
|
|
174
|
+
sig { params(file: Dependabot::DependencyFile, source: T::Hash[Symbol, String]).returns(Dependabot::Dependency) }
|
152
175
|
def build_terragrunt_dependency(file, source)
|
153
176
|
dep_name = Source.from_url(source[:url]) ? T.must(Source.from_url(source[:url])).repo : source[:url]
|
154
177
|
version = version_from_ref(source[:ref])
|
155
178
|
|
156
179
|
Dependency.new(
|
157
|
-
name: dep_name,
|
180
|
+
name: T.must(dep_name),
|
158
181
|
version: version,
|
159
182
|
package_manager: "terraform",
|
160
183
|
requirements: [
|
@@ -167,6 +190,7 @@ module Dependabot
|
|
167
190
|
end
|
168
191
|
|
169
192
|
# Full docs at https://www.terraform.io/docs/modules/sources.html
|
193
|
+
sig { params(details_hash: T::Hash[String, String]).returns(T.nilable(T::Hash[Symbol, T.untyped])) }
|
170
194
|
def source_from(details_hash)
|
171
195
|
raw_source = details_hash.fetch("source")
|
172
196
|
bare_source = RegistryClient.get_proxied_source(raw_source)
|
@@ -183,10 +207,11 @@ module Dependabot
|
|
183
207
|
return nil
|
184
208
|
end
|
185
209
|
|
186
|
-
source_details[:proxy_url] = raw_source if raw_source != bare_source
|
210
|
+
T.must(source_details)[:proxy_url] = raw_source if raw_source != bare_source
|
187
211
|
source_details
|
188
212
|
end
|
189
213
|
|
214
|
+
sig { params(source_address: T.nilable(String), name: String).returns(T::Array[String]) }
|
190
215
|
def provider_source_from(source_address, name)
|
191
216
|
matches = source_address&.match(PROVIDER_SOURCE_ADDRESS)
|
192
217
|
matches = {} if matches.nil?
|
@@ -198,6 +223,7 @@ module Dependabot
|
|
198
223
|
]
|
199
224
|
end
|
200
225
|
|
226
|
+
sig { params(source_string: T.untyped).returns(T::Hash[Symbol, String]) }
|
201
227
|
def registry_source_details_from(source_string)
|
202
228
|
parts = source_string.split("//").first.split("/")
|
203
229
|
|
@@ -219,6 +245,7 @@ module Dependabot
|
|
219
245
|
end
|
220
246
|
end
|
221
247
|
|
248
|
+
sig { params(name: String, source: T::Hash[Symbol, T.untyped]).returns(String) }
|
222
249
|
def git_dependency_name(name, source)
|
223
250
|
git_source = Source.from_url(source[:url])
|
224
251
|
if git_source && source[:ref]
|
@@ -233,13 +260,14 @@ module Dependabot
|
|
233
260
|
end
|
234
261
|
end
|
235
262
|
|
263
|
+
sig { params(source_string: String).returns(T::Hash[Symbol, T.nilable(String)]) }
|
236
264
|
def git_source_details_from(source_string)
|
237
265
|
git_url = source_string.strip.gsub(/^git::/, "")
|
238
266
|
git_url = "https://" + git_url unless git_url.start_with?("git@") || git_url.include?("://")
|
239
267
|
|
240
268
|
bare_uri =
|
241
269
|
if git_url.include?("git@")
|
242
|
-
git_url.split("git@").last.sub(":", "/")
|
270
|
+
T.must(git_url.split("git@").last).sub(":", "/")
|
243
271
|
else
|
244
272
|
git_url.sub(%r{.*?://}, "")
|
245
273
|
end
|
@@ -255,14 +283,16 @@ module Dependabot
|
|
255
283
|
}
|
256
284
|
end
|
257
285
|
|
286
|
+
sig { params(ref: T.nilable(String)).returns(T.nilable(String)) }
|
258
287
|
def version_from_ref(ref)
|
259
288
|
version_regex = GitCommitChecker::VERSION_REGEX
|
260
289
|
return unless ref&.match?(version_regex)
|
261
290
|
|
262
|
-
ref.match(version_regex)
|
291
|
+
ref.match(version_regex)&.named_captures&.fetch("version")
|
263
292
|
end
|
264
293
|
|
265
294
|
# rubocop:disable Metrics/PerceivedComplexity
|
295
|
+
sig { params(source_string: String).returns(Symbol) }
|
266
296
|
def source_type(source_string)
|
267
297
|
return :interpolation if source_string.include?("${")
|
268
298
|
return :path if source_string.start_with?(".")
|
@@ -272,11 +302,11 @@ module Dependabot
|
|
272
302
|
return :mercurial if source_string.start_with?("hg::")
|
273
303
|
return :s3 if source_string.start_with?("s3::")
|
274
304
|
|
275
|
-
raise "Unknown src: #{source_string}" if source_string.split("/").first
|
305
|
+
raise "Unknown src: #{source_string}" if source_string.split("/").first&.include?("::")
|
276
306
|
|
277
307
|
return :registry unless source_string.start_with?("http")
|
278
308
|
|
279
|
-
path_uri = URI.parse(source_string.split(%r{(?<!:)//}).first)
|
309
|
+
path_uri = URI.parse(T.must(source_string.split(%r{(?<!:)//}).first))
|
280
310
|
query_uri = URI.parse(source_string)
|
281
311
|
return :http_archive if path_uri.path.end_with?(*RegistryClient::ARCHIVE_EXTENSIONS)
|
282
312
|
return :http_archive if query_uri.query&.include?("archive=")
|
@@ -307,8 +337,9 @@ module Dependabot
|
|
307
337
|
# }
|
308
338
|
# ],
|
309
339
|
# }
|
340
|
+
sig { params(file: Dependabot::DependencyFile).returns(T::Hash[String, T.untyped]) }
|
310
341
|
def parsed_file(file)
|
311
|
-
@parsed_buildfile ||= {}
|
342
|
+
@parsed_buildfile ||= T.let({}, T.nilable(T::Hash[String, T.untyped]))
|
312
343
|
@parsed_buildfile[file.name] ||= SharedHelpers.in_a_temporary_directory do
|
313
344
|
File.write("tmp.tf", file.content)
|
314
345
|
|
@@ -335,27 +366,40 @@ module Dependabot
|
|
335
366
|
raise Dependabot::DependencyFileNotParseable.new(file.path, msg)
|
336
367
|
end
|
337
368
|
|
369
|
+
sig { returns(String) }
|
338
370
|
def terraform_parser_path
|
339
371
|
helper_bin_dir = File.join(native_helpers_root, "terraform/bin")
|
340
372
|
Pathname.new(File.join(helper_bin_dir, "json2hcl")).cleanpath.to_path
|
341
373
|
end
|
342
374
|
|
375
|
+
sig { returns(String) }
|
343
376
|
def terraform_hcl2_parser_path
|
344
377
|
helper_bin_dir = File.join(native_helpers_root, "terraform/bin")
|
345
378
|
Pathname.new(File.join(helper_bin_dir, "hcl2json")).cleanpath.to_path
|
346
379
|
end
|
347
380
|
|
381
|
+
sig { returns(String) }
|
348
382
|
def native_helpers_root
|
349
383
|
default_path = File.join(__dir__, "../../../helpers/install-dir")
|
350
384
|
ENV.fetch("DEPENDABOT_NATIVE_HELPERS_PATH", default_path)
|
351
385
|
end
|
352
386
|
|
387
|
+
sig { override.void }
|
353
388
|
def check_required_files
|
354
389
|
return if [*terraform_files, *terragrunt_files].any?
|
355
390
|
|
356
391
|
raise "No Terraform configuration file!"
|
357
392
|
end
|
358
393
|
|
394
|
+
sig do
|
395
|
+
params(
|
396
|
+
hostname: String,
|
397
|
+
namespace: String,
|
398
|
+
name: String,
|
399
|
+
constraint: T.nilable(String)
|
400
|
+
)
|
401
|
+
.returns(T.nilable(String))
|
402
|
+
end
|
359
403
|
def determine_version_for(hostname, namespace, name, constraint)
|
360
404
|
return constraint if constraint&.match?(/\A\d/)
|
361
405
|
|
@@ -363,14 +407,17 @@ module Dependabot
|
|
363
407
|
.dig("provider", "#{hostname}/#{namespace}/#{name}", 0, "version")
|
364
408
|
end
|
365
409
|
|
410
|
+
sig { returns(T::Hash[String, T.untyped]) }
|
366
411
|
def lockfile_content
|
367
|
-
@lockfile_content ||=
|
412
|
+
@lockfile_content ||= T.let(
|
368
413
|
begin
|
369
414
|
lockfile = dependency_files.find do |file|
|
370
415
|
file.name == ".terraform.lock.hcl"
|
371
416
|
end
|
372
417
|
lockfile ? parsed_file(lockfile) : {}
|
373
|
-
end
|
418
|
+
end,
|
419
|
+
T.nilable(T::Hash[String, T.untyped])
|
420
|
+
)
|
374
421
|
end
|
375
422
|
end
|
376
423
|
end
|
@@ -1,4 +1,4 @@
|
|
1
|
-
# typed:
|
1
|
+
# typed: strict
|
2
2
|
# frozen_string_literal: true
|
3
3
|
|
4
4
|
####################################################################
|
@@ -6,6 +6,8 @@
|
|
6
6
|
# https://www.terraform.io/docs/modules/usage.html#module-versions #
|
7
7
|
####################################################################
|
8
8
|
|
9
|
+
require "sorbet-runtime"
|
10
|
+
|
9
11
|
require "dependabot/terraform/version"
|
10
12
|
require "dependabot/terraform/requirement"
|
11
13
|
|
@@ -46,9 +48,18 @@ module Dependabot
|
|
46
48
|
# }
|
47
49
|
# }
|
48
50
|
class RequirementsUpdater
|
51
|
+
extend T::Sig
|
52
|
+
|
49
53
|
# @param requirements [Hash{Symbol => String, Array, Hash}]
|
50
54
|
# @param latest_version [Dependabot::Terraform::Version]
|
51
55
|
# @param tag_for_latest_version [String, NilClass]
|
56
|
+
sig do
|
57
|
+
params(
|
58
|
+
requirements: T::Array[T::Hash[Symbol, T.untyped]],
|
59
|
+
latest_version: T.nilable(Dependabot::Version::VersionParameter),
|
60
|
+
tag_for_latest_version: T.nilable(String)
|
61
|
+
).void
|
62
|
+
end
|
52
63
|
def initialize(requirements:, latest_version:, tag_for_latest_version:)
|
53
64
|
@requirements = requirements
|
54
65
|
@tag_for_latest_version = tag_for_latest_version
|
@@ -56,7 +67,7 @@ module Dependabot
|
|
56
67
|
return unless latest_version
|
57
68
|
return unless version_class.correct?(latest_version)
|
58
69
|
|
59
|
-
@latest_version = version_class.new(latest_version)
|
70
|
+
@latest_version = T.let(version_class.new(latest_version), Dependabot::Terraform::Version)
|
60
71
|
end
|
61
72
|
|
62
73
|
# @return requirements [Hash{Symbol => String, Array, Hash}]
|
@@ -64,9 +75,8 @@ module Dependabot
|
|
64
75
|
# * groups [Array] no-op for terraform
|
65
76
|
# * file [String] the file that specified this dependency
|
66
77
|
# * source [Hash{Symbol => String}] The updated git or registry source details
|
78
|
+
sig { returns(T::Array[T::Hash[Symbol, T.untyped]]) }
|
67
79
|
def updated_requirements
|
68
|
-
return requirements unless latest_version
|
69
|
-
|
70
80
|
# NOTE: Order is important here. The FileUpdater needs the updated
|
71
81
|
# requirement at index `i` to correspond to the previous requirement
|
72
82
|
# at the same index.
|
@@ -81,10 +91,16 @@ module Dependabot
|
|
81
91
|
|
82
92
|
private
|
83
93
|
|
94
|
+
sig { returns(T::Array[T::Hash[Symbol, T.untyped]]) }
|
84
95
|
attr_reader :requirements
|
96
|
+
|
97
|
+
sig { returns(Dependabot::Terraform::Version) }
|
85
98
|
attr_reader :latest_version
|
99
|
+
|
100
|
+
sig { returns(T.nilable(String)) }
|
86
101
|
attr_reader :tag_for_latest_version
|
87
102
|
|
103
|
+
sig { params(req: T::Hash[Symbol, T.untyped]).returns(T::Hash[Symbol, T.untyped]) }
|
88
104
|
def update_git_requirement(req)
|
89
105
|
return req unless req.dig(:source, :ref)
|
90
106
|
return req unless tag_for_latest_version
|
@@ -92,6 +108,7 @@ module Dependabot
|
|
92
108
|
req.merge(source: req[:source].merge(ref: tag_for_latest_version))
|
93
109
|
end
|
94
110
|
|
111
|
+
sig { params(req: T::Hash[Symbol, T.untyped]).returns(T::Hash[Symbol, T.untyped]) }
|
95
112
|
def update_registry_requirement(req)
|
96
113
|
return req if req.fetch(:requirement).nil?
|
97
114
|
|
@@ -111,6 +128,7 @@ module Dependabot
|
|
111
128
|
end
|
112
129
|
|
113
130
|
# Updates the version in a "~>" constraint to allow the given version
|
131
|
+
sig { params(req_string: String).returns(String) }
|
114
132
|
def update_twiddle_version(req_string)
|
115
133
|
old_version = requirement_class.new(req_string)
|
116
134
|
.requirements.first.last
|
@@ -118,6 +136,7 @@ module Dependabot
|
|
118
136
|
req_string.sub(old_version.to_s, updated_version)
|
119
137
|
end
|
120
138
|
|
139
|
+
sig { params(req_string: String).returns(T::Array[Dependabot::Terraform::Requirement]) }
|
121
140
|
def update_range(req_string)
|
122
141
|
requirement_class.new(req_string).requirements.flat_map do |r|
|
123
142
|
ruby_req = requirement_class.new(r.join(" "))
|
@@ -131,6 +150,13 @@ module Dependabot
|
|
131
150
|
end
|
132
151
|
end
|
133
152
|
|
153
|
+
sig do
|
154
|
+
params(
|
155
|
+
new_version: Dependabot::Terraform::Version,
|
156
|
+
old_version: Dependabot::Terraform::Version
|
157
|
+
)
|
158
|
+
.returns(String)
|
159
|
+
end
|
134
160
|
def at_same_precision(new_version, old_version)
|
135
161
|
release_precision =
|
136
162
|
old_version.to_s.split(".").count { |i| i.match?(/^\d+$/) }
|
@@ -149,6 +175,13 @@ module Dependabot
|
|
149
175
|
|
150
176
|
# Updates the version in a "<" or "<=" constraint to allow the given
|
151
177
|
# version
|
178
|
+
sig do
|
179
|
+
params(
|
180
|
+
requirement: Dependabot::Requirement,
|
181
|
+
version_to_be_permitted: T.any(String, Dependabot::Terraform::Version)
|
182
|
+
)
|
183
|
+
.returns(Dependabot::Terraform::Requirement)
|
184
|
+
end
|
152
185
|
def update_greatest_version(requirement, version_to_be_permitted)
|
153
186
|
if version_to_be_permitted.is_a?(String)
|
154
187
|
version_to_be_permitted =
|
@@ -164,7 +197,7 @@ module Dependabot
|
|
164
197
|
if index < index_to_update
|
165
198
|
version_to_be_permitted.segments[index]
|
166
199
|
elsif index == index_to_update
|
167
|
-
version_to_be_permitted.segments[index] + 1
|
200
|
+
version_to_be_permitted.segments[index].to_i + 1
|
168
201
|
else
|
169
202
|
0
|
170
203
|
end
|
@@ -173,10 +206,12 @@ module Dependabot
|
|
173
206
|
requirement_class.new("#{op} #{new_segments.join('.')}")
|
174
207
|
end
|
175
208
|
|
209
|
+
sig { returns(T.class_of(Dependabot::Terraform::Version)) }
|
176
210
|
def version_class
|
177
211
|
Version
|
178
212
|
end
|
179
213
|
|
214
|
+
sig { returns(T.class_of(Dependabot::Terraform::Requirement)) }
|
180
215
|
def requirement_class
|
181
216
|
Requirement
|
182
217
|
end
|
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.278.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Dependabot
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2024-09-
|
11
|
+
date: 2024-09-26 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.278.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.278.0
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
28
|
name: debug
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
@@ -260,7 +260,7 @@ licenses:
|
|
260
260
|
- MIT
|
261
261
|
metadata:
|
262
262
|
bug_tracker_uri: https://github.com/dependabot/dependabot-core/issues
|
263
|
-
changelog_uri: https://github.com/dependabot/dependabot-core/releases/tag/v0.
|
263
|
+
changelog_uri: https://github.com/dependabot/dependabot-core/releases/tag/v0.278.0
|
264
264
|
post_install_message:
|
265
265
|
rdoc_options: []
|
266
266
|
require_paths:
|