dependabot-go_modules 0.120.4 → 0.122.1

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: fd5bd86e2db4a63bf585f2811548d8bedcff1a1b9c4fcf7ef46c12e9e174894a
4
- data.tar.gz: 734b450561f99006c351af51ca91a07a5cef07312faa3cf5adf44b6d0fd1daa4
3
+ metadata.gz: da8437c4b2e42e473b12e787510f09a045cf46d79c6efd807d276cea8048ea52
4
+ data.tar.gz: 21b14468c658ed748c3adfa41e90fa1f86dbf9dc90510dfc963b70f9d49f8839
5
5
  SHA512:
6
- metadata.gz: de4e7c309a4c299a9ab32e1372d1d06949ef3cdf15dc405e03e4eff0731af8f5c1dae4a377c8321d10eba0c2c64d332ba3e382fa08bbe586396903c58d9ee373
7
- data.tar.gz: 54461612c6078e1ba42257d0b7519d76da0ac53339d68f6792eedc35480803c03a6f95576b77f352dab5668744af4f80d2df57668e30638d5c9dd0c18c57f8a5
6
+ metadata.gz: 38d199a506af5f10c71d48e381f33dcb480f80baf39905ac507bea51d57dae65ec7c200fe77a3e5b0ff7a0fa00b487372d45705b97a293064b0eaf9f6c2ff179
7
+ data.tar.gz: 132db9b235fbe89ec4f39c759e95d6b0d60ad539762aada40794245020cbe23c68bee171c6115fd33766688e30e9ad4a92e719f6ffbe53de53d1f53f1b145a8b
@@ -17,3 +17,6 @@ Dependabot::PullRequestCreator::Labeler.
17
17
  require "dependabot/dependency"
18
18
  Dependabot::Dependency.
19
19
  register_production_check("go_modules", ->(_) { true })
20
+
21
+ require "dependabot/utils"
22
+ Dependabot::Utils.register_always_clone("go_modules")
@@ -17,23 +17,31 @@ module Dependabot
17
17
  private
18
18
 
19
19
  def fetch_files
20
- unless go_mod
21
- raise(
22
- Dependabot::DependencyFileNotFound,
23
- File.join(directory, "go.mod")
24
- )
20
+ # Ensure we always check out the full repo contents for go_module
21
+ # updates.
22
+ SharedHelpers.in_a_temporary_repo_directory(
23
+ directory,
24
+ clone_repo_contents
25
+ ) do
26
+ unless go_mod
27
+ raise(
28
+ Dependabot::DependencyFileNotFound,
29
+ Pathname.new(File.join(directory, "go.mod")).
30
+ cleanpath.to_path
31
+ )
32
+ end
33
+
34
+ fetched_files = [go_mod]
35
+
36
+ # Fetch the (optional) go.sum
37
+ fetched_files << go_sum if go_sum
38
+
39
+ # Fetch the main.go file if present, as this will later identify
40
+ # this repo as an app.
41
+ fetched_files << main if main
42
+
43
+ fetched_files
25
44
  end
26
-
27
- fetched_files = [go_mod]
28
-
29
- # Fetch the (optional) go.sum
30
- fetched_files << go_sum if go_sum
31
-
32
- # Fetch the main.go file if present, as this will later identify
33
- # this repo as an app.
34
- fetched_files << main if main
35
-
36
- fetched_files
37
45
  end
38
46
 
39
47
  def go_mod
@@ -45,15 +53,21 @@ module Dependabot
45
53
  end
46
54
 
47
55
  def main
48
- return @main if @main
56
+ return @main if defined?(@main)
49
57
 
50
- go_files = repo_contents.select { |f| f.name.end_with?(".go") }
58
+ go_files = Dir.glob("*.go")
51
59
 
52
- go_files.each do |go_file|
53
- file = fetch_file_from_host(go_file.name, type: "package_main")
54
- next unless file.content.match?(/\s*package\s+main/)
60
+ go_files.each do |filename|
61
+ file_content = File.read(filename)
62
+ next unless file_content.match?(/\s*package\s+main/)
55
63
 
56
- return @main = file.tap { |f| f.support_file = true }
64
+ return @main = DependencyFile.new(
65
+ name: Pathname.new(filename).cleanpath.to_path,
66
+ directory: "/",
67
+ type: "package_main",
68
+ support_file: true,
69
+ content: file_content
70
+ )
57
71
  end
58
72
 
59
73
  nil
@@ -3,12 +3,34 @@
3
3
  require "dependabot/shared_helpers"
4
4
  require "dependabot/file_updaters"
5
5
  require "dependabot/file_updaters/base"
6
+ require "dependabot/file_updaters/vendor_updater"
6
7
 
7
8
  module Dependabot
8
9
  module GoModules
9
10
  class FileUpdater < Dependabot::FileUpdaters::Base
10
11
  require_relative "file_updater/go_mod_updater"
11
12
 
13
+ def initialize(dependencies:, dependency_files:, repo_contents_path: nil,
14
+ credentials:, options: {})
15
+ super
16
+ return unless repo_contents_path.nil?
17
+
18
+ # masquerade repo_contents_path for GoModUpdater during transition
19
+ tmp = Dir.mktmpdir
20
+ Dir.chdir(tmp) do
21
+ dependency_files.each do |file|
22
+ File.write(file.name, file.content)
23
+ end
24
+ `git config --global user.email "no-reply@github.com"`
25
+ `git config --global user.name "Dependabot"`
26
+ `git init .`
27
+ `git add .`
28
+ `git commit -m'fake repo_contents_path'`
29
+ end
30
+ @repo_contents_path = tmp
31
+ @repo_contents_stub = true
32
+ end
33
+
12
34
  def self.updated_files_regex
13
35
  [
14
36
  /^go\.mod$/,
@@ -33,6 +55,12 @@ module Dependabot
33
55
  content: file_updater.updated_go_sum_content
34
56
  )
35
57
  end
58
+
59
+ vendor_updater.
60
+ updated_vendor_cache_files(base_directory: directory).
61
+ each do |file|
62
+ updated_files << file
63
+ end
36
64
  end
37
65
 
38
66
  raise "No files changed!" if updated_files.none?
@@ -56,15 +84,40 @@ module Dependabot
56
84
  @go_sum ||= get_original_file("go.sum")
57
85
  end
58
86
 
87
+ def directory
88
+ dependency_files.first.directory
89
+ end
90
+
91
+ def vendor_dir
92
+ File.join(repo_contents_path, directory, "vendor")
93
+ end
94
+
95
+ def vendor_updater
96
+ Dependabot::FileUpdaters::VendorUpdater.new(
97
+ repo_contents_path: repo_contents_path,
98
+ vendor_dir: vendor_dir
99
+ )
100
+ end
101
+
59
102
  def file_updater
60
103
  @file_updater ||=
61
104
  GoModUpdater.new(
62
105
  dependencies: dependencies,
63
- go_mod: go_mod,
64
- go_sum: go_sum,
65
- credentials: credentials
106
+ credentials: credentials,
107
+ repo_contents_path: repo_contents_path,
108
+ directory: directory,
109
+ options: { tidy: tidy?, vendor: vendor? }
66
110
  )
67
111
  end
112
+
113
+ def tidy?
114
+ !@repo_contents_stub && options.fetch(:go_mod_tidy, false)
115
+ end
116
+
117
+ def vendor?
118
+ File.exist?(File.join(vendor_dir, "modules.txt")) &&
119
+ options.fetch(:go_mod_vendor, false)
120
+ end
68
121
  end
69
122
  end
70
123
  end
@@ -16,7 +16,8 @@ module Dependabot
16
16
  RESOLVABILITY_ERROR_REGEXES = [
17
17
  /go: .*: git fetch .*: exit status 128/.freeze,
18
18
  /verifying .*: checksum mismatch/.freeze,
19
- /build .*: cannot find module providing package/.freeze
19
+ /build .*: cannot find module providing package/.freeze,
20
+ /module .* found \(.*\), but does not contain package/m.freeze
20
21
  ].freeze
21
22
 
22
23
  MODULE_PATH_MISMATCH_REGEXES = [
@@ -25,11 +26,14 @@ module Dependabot
25
26
  /go: ([^@\s]+)(?:@[^\s]+)?: .* declares its path as: ([\S]*)/m
26
27
  ].freeze
27
28
 
28
- def initialize(dependencies:, go_mod:, go_sum:, credentials:)
29
+ def initialize(dependencies:, credentials:, repo_contents_path:,
30
+ directory:, options:)
29
31
  @dependencies = dependencies
30
- @go_mod = go_mod
31
- @go_sum = go_sum
32
32
  @credentials = credentials
33
+ @repo_contents_path = repo_contents_path
34
+ @directory = directory
35
+ @tidy = options.fetch(:tidy, false)
36
+ @vendor = options.fetch(:vendor, false)
33
37
  end
34
38
 
35
39
  def updated_go_mod_content
@@ -42,64 +46,83 @@ module Dependabot
42
46
 
43
47
  private
44
48
 
45
- attr_reader :dependencies, :go_mod, :go_sum, :credentials
49
+ attr_reader :dependencies, :credentials, :repo_contents_path,
50
+ :directory
46
51
 
47
52
  def updated_files
48
53
  @updated_files ||= update_files
49
54
  end
50
55
 
51
- # rubocop:disable Metrics/AbcSize
52
- def update_files
53
- # Map paths in local replace directives to path hashes
54
- substitutions = replace_directive_substitutions(go_mod.content)
55
- stub_dirs = substitutions.values
56
+ def update_files # rubocop:disable Metrics/AbcSize
57
+ in_repo_path do
58
+ # Map paths in local replace directives to path hashes
56
59
 
57
- # Replace full paths with path hashes in the go.mod
58
- clean_go_mod = substitute_all(go_mod.content, substitutions)
60
+ original_go_mod = File.read("go.mod")
61
+ original_manifest = parse_manifest
62
+ original_go_sum = File.read("go.sum") if File.exist?("go.sum")
59
63
 
60
- # Set the new dependency versions in the go.mod
61
- updated_go_mod = in_temp_dir(stub_dirs) do
62
- update_go_mod(clean_go_mod, dependencies)
63
- end
64
+ substitutions = replace_directive_substitutions(original_manifest)
65
+ build_module_stubs(substitutions.values)
64
66
 
65
- # Then run `go get` to pick up other changes to the file caused by
66
- # the upgrade
67
- regenerated_files = in_temp_dir(stub_dirs) do
68
- run_go_get(updated_go_mod, go_sum)
69
- end
67
+ # Replace full paths with path hashes in the go.mod
68
+ substitute_all(substitutions)
70
69
 
71
- # At this point, the go.mod returned from run_go_get contains the
72
- # correct set of modules, but running `go get` can change the file in
73
- # undesirable ways (such as injecting the current Go version), so we
74
- # need to update the original go.mod with the updated set of
75
- # requirements rather than using the regenerated file directly
76
- original_reqs = in_temp_dir(stub_dirs) do
77
- parse_manifest_requirements(go_mod.content)
78
- end
79
- updated_reqs = in_temp_dir(stub_dirs) do
80
- parse_manifest_requirements(regenerated_files[:go_mod])
81
- end
70
+ # Set the stubbed replace directives
71
+ update_go_mod(dependencies)
82
72
 
83
- original_paths = original_reqs.map { |r| r["Path"] }
84
- updated_paths = updated_reqs.map { |r| r["Path"] }
85
- req_paths_to_remove = original_paths - updated_paths
73
+ # Then run `go get` to pick up other changes to the file caused by
74
+ # the upgrade
75
+ run_go_get
76
+ run_go_vendor
77
+ run_go_mod_tidy
86
78
 
87
- output_go_mod = in_temp_dir(stub_dirs) do
88
- remove_requirements(go_mod.content, req_paths_to_remove)
89
- end
79
+ # At this point, the go.mod returned from run_go_get contains the
80
+ # correct set of modules, but running `go get` can change the file
81
+ # in undesirable ways (such as injecting the current Go version),
82
+ # so we need to update the original go.mod with the updated set of
83
+ # requirements rather than using the regenerated file directly
84
+ original_reqs = original_manifest["Require"] || []
85
+ updated_reqs = parse_manifest["Require"] || []
90
86
 
91
- output_go_mod = in_temp_dir(stub_dirs) do
87
+ original_paths = original_reqs.map { |r| r["Path"] }
88
+ updated_paths = updated_reqs.map { |r| r["Path"] }
89
+ req_paths_to_remove = original_paths - updated_paths
90
+
91
+ # Put back the original content before we replace just the updated
92
+ # dependencies.
93
+ write_go_mod(original_go_mod)
94
+
95
+ remove_requirements(req_paths_to_remove)
92
96
  deps = updated_reqs.map { |r| requirement_to_dependency_obj(r) }
93
- update_go_mod(output_go_mod, deps)
97
+ update_go_mod(deps)
98
+
99
+ # put the old replace directives back again
100
+ substitute_all(substitutions.invert)
101
+
102
+ updated_go_sum = original_go_sum ? File.read("go.sum") : nil
103
+ updated_go_mod = File.read("go.mod")
104
+
105
+ { go_mod: updated_go_mod, go_sum: updated_go_sum }
94
106
  end
107
+ end
108
+
109
+ def run_go_mod_tidy
110
+ return unless tidy?
95
111
 
96
- { go_mod: output_go_mod, go_sum: regenerated_files[:go_sum] }
112
+ command = "go mod tidy"
113
+ _, stderr, status = Open3.capture3(ENVIRONMENT, command)
114
+ handle_subprocess_error(stderr) unless status.success?
97
115
  end
98
- # rubocop:enable Metrics/AbcSize
99
116
 
100
- def update_go_mod(go_mod_content, dependencies)
101
- File.write("go.mod", go_mod_content)
117
+ def run_go_vendor
118
+ return unless vendor?
119
+
120
+ command = "go mod vendor"
121
+ _, stderr, status = Open3.capture3(ENVIRONMENT, command)
122
+ handle_subprocess_error(stderr) unless status.success?
123
+ end
102
124
 
125
+ def update_go_mod(dependencies)
103
126
  deps = dependencies.map do |dep|
104
127
  {
105
128
  name: dep.name,
@@ -108,78 +131,75 @@ module Dependabot
108
131
  }
109
132
  end
110
133
 
111
- SharedHelpers.run_helper_subprocess(
134
+ body = SharedHelpers.run_helper_subprocess(
112
135
  command: NativeHelpers.helper_path,
113
136
  env: ENVIRONMENT,
114
137
  function: "updateDependencyFile",
115
138
  args: { dependencies: deps }
116
139
  )
140
+
141
+ write_go_mod(body)
117
142
  end
118
143
 
119
- def run_go_get(go_mod_content, go_sum)
120
- File.write("go.mod", go_mod_content)
121
- File.write("go.sum", go_sum.content) if go_sum
122
- File.write("main.go", dummy_main_go)
144
+ def run_go_get
145
+ tmp_go_file = "#{SecureRandom.hex}.go"
146
+
147
+ unless Dir.glob("*.go").any?
148
+ File.write(tmp_go_file, "package dummypkg\n")
149
+ end
123
150
 
124
151
  _, stderr, status = Open3.capture3(ENVIRONMENT, "go get -d")
125
152
  handle_subprocess_error(stderr) unless status.success?
126
-
127
- updated_go_sum = go_sum ? File.read("go.sum") : nil
128
- { go_mod: File.read("go.mod"), go_sum: updated_go_sum }
153
+ ensure
154
+ File.delete(tmp_go_file) if File.exist?(tmp_go_file)
129
155
  end
130
156
 
131
- def parse_manifest_requirements(go_mod_content)
132
- File.write("go.mod", go_mod_content)
133
-
157
+ def parse_manifest
134
158
  command = "go mod edit -json"
135
159
  stdout, stderr, status = Open3.capture3(ENVIRONMENT, command)
136
160
  handle_subprocess_error(stderr) unless status.success?
137
161
 
138
- JSON.parse(stdout)["Require"] || []
162
+ JSON.parse(stdout) || {}
139
163
  end
140
164
 
141
- def remove_requirements(go_mod_content, requirement_paths)
142
- File.write("go.mod", go_mod_content)
143
-
165
+ def remove_requirements(requirement_paths)
144
166
  requirement_paths.each do |path|
145
167
  escaped_path = Shellwords.escape(path)
146
168
  command = "go mod edit -droprequire #{escaped_path}"
147
169
  _, stderr, status = Open3.capture3(ENVIRONMENT, command)
148
170
  handle_subprocess_error(stderr) unless status.success?
149
171
  end
150
-
151
- File.read("go.mod")
152
172
  end
153
173
 
154
- def add_requirements(go_mod_content, requirements)
155
- File.write("go.mod", go_mod_content)
156
-
174
+ def add_requirements(requirements)
157
175
  requirements.each do |r|
158
176
  escaped_req = Shellwords.escape("#{r['Path']}@#{r['Version']}")
159
177
  command = "go mod edit -require #{escaped_req}"
160
178
  _, stderr, status = Open3.capture3(ENVIRONMENT, command)
161
179
  handle_subprocess_error(stderr) unless status.success?
162
180
  end
163
-
164
- File.read("go.mod")
165
181
  end
166
182
 
167
- def in_temp_dir(stub_paths, &block)
168
- SharedHelpers.in_a_temporary_directory do
183
+ def in_repo_path(&block)
184
+ SharedHelpers.
185
+ in_a_temporary_repo_directory(directory, repo_contents_path) do
169
186
  SharedHelpers.with_git_configured(credentials: credentials) do
170
- # Create a fake empty module for each local module so that
171
- # `go get -d` works, even if some modules have been `replace`d
172
- # with a local module that we don't have access to.
173
- stub_paths.each do |stub_path|
174
- Dir.mkdir(stub_path) unless Dir.exist?(stub_path)
175
- FileUtils.touch(File.join(stub_path, "go.mod"))
176
- end
177
-
178
187
  block.call
179
188
  end
180
189
  end
181
190
  end
182
191
 
192
+ def build_module_stubs(stub_paths)
193
+ # Create a fake empty module for each local module so that
194
+ # `go get -d` works, even if some modules have been `replace`d
195
+ # with a local module that we don't have access to.
196
+ stub_paths.each do |stub_path|
197
+ Dir.mkdir(stub_path) unless Dir.exist?(stub_path)
198
+ FileUtils.touch(File.join(stub_path, "go.mod"))
199
+ FileUtils.touch(File.join(stub_path, "main.go"))
200
+ end
201
+ end
202
+
183
203
  # Given a go.mod file, find all `replace` directives pointing to a path
184
204
  # on the local filesystem, and return an array of pairs mapping the
185
205
  # original path to a hash of the path.
@@ -188,22 +208,14 @@ module Dependabot
188
208
  # the layout of the filesystem with a structure we can reproduce (i.e.
189
209
  # no paths such as ../../../foo), run the Go tooling, then reverse the
190
210
  # process afterwards.
191
- def replace_directive_substitutions(go_mod_content)
211
+ def replace_directive_substitutions(manifest)
192
212
  @replace_directive_substitutions ||=
193
- SharedHelpers.in_a_temporary_directory do |path|
194
- File.write("go.mod", go_mod_content)
195
-
196
- # Parse the go.mod to get a JSON representation of the replace
197
- # directives
198
- command = "go mod edit -json"
199
- stdout, stderr, status = Open3.capture3(ENVIRONMENT, command)
200
- handle_subprocess_error(path, stderr) unless status.success?
201
-
213
+ begin
202
214
  # Find all the local replacements, and return them with a stub
203
215
  # path we can use in their place. Using generated paths is safer
204
216
  # as it means we don't need to worry about references to parent
205
217
  # directories, etc.
206
- (JSON.parse(stdout)["Replace"] || []).
218
+ (manifest["Replace"] || []).
207
219
  map { |r| r["New"]["Path"] }.
208
220
  compact.
209
221
  select { |p| p.start_with?(".") || p.start_with?("/") }.
@@ -212,10 +224,12 @@ module Dependabot
212
224
  end
213
225
  end
214
226
 
215
- def substitute_all(file, substitutions)
216
- substitutions.reduce(file) do |text, (a, b)|
227
+ def substitute_all(substitutions)
228
+ body = substitutions.reduce(File.read("go.mod")) do |text, (a, b)|
217
229
  text.sub(a, b)
218
230
  end
231
+
232
+ write_go_mod(body)
219
233
  end
220
234
 
221
235
  def handle_subprocess_error(stderr)
@@ -231,28 +245,18 @@ module Dependabot
231
245
  if path_regex
232
246
  match = path_regex.match(stderr)
233
247
  raise Dependabot::GoModulePathMismatch.
234
- new(go_mod.path, match[1], match[2])
248
+ new(go_mod_path, match[1], match[2])
235
249
  end
236
250
 
237
251
  msg = stderr.lines.last(10).join.strip
238
- raise Dependabot::DependencyFileNotParseable.new(go_mod.path, msg)
252
+ raise Dependabot::DependencyFileNotParseable.
253
+ new(go_mod_path, msg)
239
254
  end
240
255
 
241
- def dummy_main_go
242
- # If we use `main` as the package name, running `go get -d` seems to
243
- # invoke the build systems, which can cause problems. For instance,
244
- # if the go.mod includes a module that doesn't have a top-level
245
- # package, we have no way of working out the import path, so the
246
- # build step fails.
247
- #
248
- # In due course, if we end up fetching the full repo, it might be
249
- # good to switch back to `main` so we can surface more errors.
250
- lines = ["package dummypkg", "import ("]
251
- dependencies.each do |dep|
252
- lines << "_ \"#{dep.name}\"" unless dep.requirements.empty?
253
- end
254
- lines << ")"
255
- lines.join("\n")
256
+ def go_mod_path
257
+ return "go.mod" if directory == "/"
258
+
259
+ File.join(directory, "go.mod")
256
260
  end
257
261
 
258
262
  def requirement_to_dependency_obj(req)
@@ -272,6 +276,18 @@ module Dependabot
272
276
  package_manager: "go_modules"
273
277
  )
274
278
  end
279
+
280
+ def write_go_mod(body)
281
+ File.write("go.mod", body)
282
+ end
283
+
284
+ def tidy?
285
+ !!@tidy
286
+ end
287
+
288
+ def vendor?
289
+ !!@vendor
290
+ end
275
291
  end
276
292
  end
277
293
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: dependabot-go_modules
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.120.4
4
+ version: 0.122.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Dependabot
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2020-10-01 00:00:00.000000000 Z
11
+ date: 2020-10-13 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.120.4
19
+ version: 0.122.1
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.120.4
26
+ version: 0.122.1
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: byebug
29
29
  requirement: !ruby/object:Gem::Requirement
@@ -100,14 +100,42 @@ dependencies:
100
100
  requirements:
101
101
  - - "~>"
102
102
  - !ruby/object:Gem::Version
103
- version: 0.91.0
103
+ version: 0.93.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: 0.91.0
110
+ version: 0.93.0
111
+ - !ruby/object:Gem::Dependency
112
+ name: simplecov
113
+ requirement: !ruby/object:Gem::Requirement
114
+ requirements:
115
+ - - "~>"
116
+ - !ruby/object:Gem::Version
117
+ version: 0.19.0
118
+ type: :development
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ requirements:
122
+ - - "~>"
123
+ - !ruby/object:Gem::Version
124
+ version: 0.19.0
125
+ - !ruby/object:Gem::Dependency
126
+ name: simplecov-console
127
+ requirement: !ruby/object:Gem::Requirement
128
+ requirements:
129
+ - - "~>"
130
+ - !ruby/object:Gem::Version
131
+ version: 0.7.2
132
+ type: :development
133
+ prerelease: false
134
+ version_requirements: !ruby/object:Gem::Requirement
135
+ requirements:
136
+ - - "~>"
137
+ - !ruby/object:Gem::Version
138
+ version: 0.7.2
111
139
  - !ruby/object:Gem::Dependency
112
140
  name: vcr
113
141
  requirement: !ruby/object:Gem::Requirement