fastlane-plugin-try_scan 0.2.0 → 0.5.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 +4 -4
- data/README.md +20 -19
- data/lib/fastlane/plugin/try_scan/actions/try_scan_action.rb +34 -60
- data/lib/fastlane/plugin/try_scan/helper/scan_helper.rb +1 -23
- data/lib/fastlane/plugin/try_scan/helper/try_scan_runner.rb +61 -97
- data/lib/fastlane/plugin/try_scan/version.rb +1 -1
- metadata +2 -30
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 9b2cd7acb930212c6e8cf756c89e71741878e510c46af3f3f747feaafc3d5bac
|
4
|
+
data.tar.gz: 8e11f9f1caf48d396983cfd2aabdb30c49d5da44a7ef0db43ec4314765dbb7aa
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 98f4a9b2f8db939dcf38507ad52ad275799b56a14cb3cc804fa20f9133e6bc01a7106ca3c38709d71b698941fff16b9b40b4330107b19545a2053810eff565a1
|
7
|
+
data.tar.gz: 8b0bcc7346f9fc389946e74fd1e22880e1f1cf82199c82f3cc3d2c2c21f416ad8ac84e734a130de5d62114c84c968d29a2c32d4073d37e6d34479430994d469b
|
data/README.md
CHANGED
@@ -2,36 +2,37 @@
|
|
2
2
|
|
3
3
|
[](https://rubygems.org/gems/fastlane-plugin-try_scan)
|
4
4
|
|
5
|
+
## About try_scan
|
6
|
+
|
7
|
+
The easiest way to rerun tests of your iOS and Mac app 🚀
|
8
|
+
|
9
|
+
Under the hood `try_scan` uses official [`fastlane scan action`](https://docs.fastlane.tools/actions/scan/), it means that you are able to provide any `scan` options and use `Scanfile` as before — everything will work like a charm, `try_scan` just brings couple of new amazing options:
|
10
|
+
|
11
|
+
| Option | Description | Default |
|
12
|
+
| ------- |------------ | ------- |
|
13
|
+
| try_count | Number of times to try to get your tests green | 1 |
|
14
|
+
| try_parallel | Should first run be executed in parallel? Equivalent to `-parallel-testing-enabled` | true |
|
15
|
+
| retry_parallel | Should subsequent runs be executed in parallel? Required `try_parallel: true` | true |
|
16
|
+
| parallel_workers | Specify the exact number of test runners that will be spawned during parallel testing. Equivalent to `-parallel-testing-worker-count` and `concurrent_workers` | |
|
17
|
+
|
18
|
+
## Requirements
|
19
|
+
|
20
|
+
* Xcode 11.x or greater. Download it at the [Apple Developer - Downloads](https://developer.apple.com/downloads) or the [Mac App Store](https://apps.apple.com/us/app/xcode/id497799835?mt=12).
|
21
|
+
|
5
22
|
## Getting Started
|
6
23
|
|
7
|
-
|
24
|
+
To get started with `try_scan`, add it to your project by running:
|
8
25
|
|
9
26
|
```bash
|
10
|
-
fastlane add_plugin try_scan
|
27
|
+
$ fastlane add_plugin try_scan
|
11
28
|
```
|
12
29
|
|
13
|
-
## About try_scan
|
14
|
-
|
15
|
-
Simple way to retry your scan action 🚀
|
16
|
-
|
17
30
|
## Usage
|
18
31
|
|
19
32
|
```ruby
|
20
33
|
try_scan(
|
21
34
|
workspace: "Example.xcworkspace",
|
22
|
-
devices: ["iPhone
|
35
|
+
devices: ["iPhone 7", "iPad Air"],
|
23
36
|
try_count: 3
|
24
37
|
)
|
25
38
|
```
|
26
|
-
|
27
|
-
## Issues and Feedback
|
28
|
-
|
29
|
-
For any other issues and feedback about this plugin, please submit it to this repository.
|
30
|
-
|
31
|
-
## Troubleshooting
|
32
|
-
|
33
|
-
If you have trouble using plugins, check out the [Plugins Troubleshooting](https://docs.fastlane.tools/plugins/plugins-troubleshooting/) guide.
|
34
|
-
|
35
|
-
## About _fastlane_
|
36
|
-
|
37
|
-
_fastlane_ is the easiest way to automate beta deployments and releases for your iOS and Android apps. To learn more, check out [fastlane.tools](https://fastlane.tools).
|
@@ -2,7 +2,6 @@ module Fastlane
|
|
2
2
|
module Actions
|
3
3
|
|
4
4
|
require 'json'
|
5
|
-
require 'nokogiri'
|
6
5
|
require 'fastlane/actions/scan'
|
7
6
|
require_relative '../helper/scan_helper'
|
8
7
|
require_relative '../helper/try_scan_runner'
|
@@ -11,61 +10,16 @@ module Fastlane
|
|
11
10
|
|
12
11
|
class TryScanAction < Action
|
13
12
|
def self.run(params)
|
14
|
-
|
15
|
-
|
13
|
+
if Helper.xcode_at_least?('11.0.0')
|
14
|
+
params[:destination] = [params[:destination]] if params[:destination] && !params[:destination].kind_of?(Array)
|
15
|
+
success = TryScanManager::Runner.new(params.values).run
|
16
16
|
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
def self.prepare_for_testing(params)
|
21
|
-
warn_of_xcode11_result_bundle_incompatability(params)
|
22
|
-
use_scanfile_to_override_settings(params.values)
|
23
|
-
turn_off_concurrent_workers(params.values)
|
24
|
-
prepare_scan_config(params.values)
|
25
|
-
coerce_destination_to_array(params)
|
26
|
-
end
|
27
|
-
|
28
|
-
def self.warn_of_xcode11_result_bundle_incompatability(params)
|
29
|
-
if FastlaneCore::Helper.xcode_at_least?('11.0.0')
|
30
|
-
if params[:result_bundle]
|
31
|
-
FastlaneCore::UI.important('As of Xcode 11, test_result bundles created in the output directory are actually symbolic links to an xcresult bundle')
|
32
|
-
end
|
33
|
-
elsif params[:output_types]&.include?('xcresult')
|
34
|
-
FastlaneCore::UI.important("The 'xcresult' :output_type is only supported for Xcode 11 and greater. You are using #{FastlaneCore::Helper.xcode_version}.")
|
35
|
-
end
|
36
|
-
end
|
37
|
-
|
38
|
-
def self.coerce_destination_to_array(params)
|
39
|
-
destination = params[:destination] || Scan.config[:destination] || []
|
40
|
-
unless destination.kind_of?(Array)
|
41
|
-
params[:destination] = Scan.config[:destination] = [destination]
|
17
|
+
raise FastlaneCore::UI.test_failure!('Tests have failed') if params[:fail_build] && !success
|
18
|
+
else
|
19
|
+
raise FastlaneCore::UI.user_error!("Minimum supported Xcode: `v11.0.0` (used: `v#{Helper.xcode_version}`)")
|
42
20
|
end
|
43
21
|
end
|
44
22
|
|
45
|
-
def self.turn_off_concurrent_workers(scan_options)
|
46
|
-
if Gem::Version.new(Fastlane::VERSION) >= Gem::Version.new('2.142.0')
|
47
|
-
scan_options.delete(:concurrent_workers) if scan_options[:concurrent_workers].to_i > 0
|
48
|
-
end
|
49
|
-
end
|
50
|
-
|
51
|
-
def self.use_scanfile_to_override_settings(scan_options)
|
52
|
-
overridden_options = FastlaneScanHelper.options_from_configuration_file(
|
53
|
-
FastlaneScanHelper.scan_options_from_try_scan_options(scan_options)
|
54
|
-
)
|
55
|
-
|
56
|
-
unless overridden_options.empty?
|
57
|
-
FastlaneCore::UI.important("Scanfile found: overriding try_scan options with it's values.")
|
58
|
-
overridden_options.each { |key, val| scan_options[key] = val }
|
59
|
-
end
|
60
|
-
end
|
61
|
-
|
62
|
-
def self.prepare_scan_config(scan_options)
|
63
|
-
Scan.config ||= FastlaneCore::Configuration.create(
|
64
|
-
Fastlane::Actions::ScanAction.available_options,
|
65
|
-
FastlaneScanHelper.scan_options_from_try_scan_options(scan_options)
|
66
|
-
)
|
67
|
-
end
|
68
|
-
|
69
23
|
#####################################################
|
70
24
|
# Documentation #
|
71
25
|
#####################################################
|
@@ -78,20 +32,40 @@ module Fastlane
|
|
78
32
|
["Alexey Alter-Pesotskiy"]
|
79
33
|
end
|
80
34
|
|
81
|
-
def self.scan_options
|
82
|
-
ScanAction.available_options.reject { |config| %i[output_types].include?(config.key) }
|
83
|
-
end
|
84
|
-
|
85
35
|
def self.available_options
|
86
|
-
|
87
|
-
scan_options + [
|
36
|
+
ScanAction.available_options + [
|
88
37
|
FastlaneCore::ConfigItem.new(
|
89
38
|
key: :try_count,
|
90
39
|
env_name: "FL_TRY_SCAN_TRY_COUNT",
|
91
|
-
description: "
|
40
|
+
description: "Number of times to try to get your tests green",
|
92
41
|
type: Integer,
|
93
42
|
is_string: false,
|
43
|
+
optional: true,
|
94
44
|
default_value: 1
|
45
|
+
),
|
46
|
+
FastlaneCore::ConfigItem.new(
|
47
|
+
key: :try_parallel,
|
48
|
+
env_name: "FL_TRY_SCAN_TRY_PARALLEL",
|
49
|
+
description: "Should first run be executed in parallel? Equivalent to -parallel-testing-enabled",
|
50
|
+
is_string: false,
|
51
|
+
optional: true,
|
52
|
+
default_value: true
|
53
|
+
),
|
54
|
+
FastlaneCore::ConfigItem.new(
|
55
|
+
key: :retry_parallel,
|
56
|
+
env_name: "FL_TRY_SCAN_RETRY_PARALLEL",
|
57
|
+
description: "Should subsequent runs be executed in parallel? Required :try_parallel: true",
|
58
|
+
is_string: false,
|
59
|
+
optional: true,
|
60
|
+
default_value: true
|
61
|
+
),
|
62
|
+
FastlaneCore::ConfigItem.new(
|
63
|
+
key: :parallel_workers,
|
64
|
+
env_name: "FL_TRY_SCAN_PARALLEL_WORKERS",
|
65
|
+
description: "Specify the exact number of test runners that will be spawned during parallel testing. Equivalent to -parallel-testing-worker-count and :concurrent_workers",
|
66
|
+
type: Integer,
|
67
|
+
is_string: false,
|
68
|
+
optional: true
|
95
69
|
)
|
96
70
|
]
|
97
71
|
end
|
@@ -101,7 +75,7 @@ module Fastlane
|
|
101
75
|
end
|
102
76
|
|
103
77
|
def self.is_supported?(platform)
|
104
|
-
[:ios].include?(platform)
|
78
|
+
[:ios, :mac].include?(platform)
|
105
79
|
end
|
106
80
|
end
|
107
81
|
end
|
@@ -19,31 +19,9 @@ module TryScanManager
|
|
19
19
|
end
|
20
20
|
|
21
21
|
def self.scan_options_from_try_scan_options(params)
|
22
|
-
valid_scan_keys = Fastlane::Actions::ScanAction.available_options.map(&:key)
|
23
22
|
params.select { |key, _| valid_scan_keys.include?(key) }
|
24
23
|
end
|
25
24
|
|
26
|
-
def self.options_from_configuration_file(params)
|
27
|
-
config = FastlaneCore::Configuration.create(
|
28
|
-
Fastlane::Actions::ScanAction.available_options,
|
29
|
-
params
|
30
|
-
)
|
31
|
-
config_file = config.load_configuration_file(Scan.scanfile_name, nil, true)
|
32
|
-
overridden_options = config_file ? config_file.options : {}
|
33
|
-
|
34
|
-
FastlaneCore::Project.detect_projects(config)
|
35
|
-
project = FastlaneCore::Project.new(config)
|
36
|
-
|
37
|
-
imported_path = File.expand_path(Scan.scanfile_name)
|
38
|
-
Dir.chdir(File.expand_path("..", project.path)) do
|
39
|
-
if File.expand_path(Scan.scanfile_name) != imported_path
|
40
|
-
config_file = config.load_configuration_file(Scan.scanfile_name, nil, true)
|
41
|
-
end
|
42
|
-
overridden_options.merge!(config_file.options) if config_file
|
43
|
-
end
|
44
|
-
overridden_options
|
45
|
-
end
|
46
|
-
|
47
25
|
def self.remove_preexisting_simulator_logs(params)
|
48
26
|
return unless params[:include_simulator_logs]
|
49
27
|
|
@@ -90,4 +68,4 @@ module TryScanManager
|
|
90
68
|
end
|
91
69
|
end
|
92
70
|
end
|
93
|
-
end
|
71
|
+
end
|
@@ -5,42 +5,39 @@ module TryScanManager
|
|
5
5
|
|
6
6
|
def initialize(options = {})
|
7
7
|
@options = options
|
8
|
+
@options[:try_count] = 1 if @options[:try_count] < 1
|
9
|
+
@options[:result_bundle] = true
|
8
10
|
end
|
9
11
|
|
10
12
|
def run
|
11
|
-
|
13
|
+
configure_xcargs
|
14
|
+
prepare_scan_config(@options)
|
12
15
|
print_summary
|
13
16
|
@attempt = 1
|
14
17
|
begin
|
15
18
|
warn_of_performing_attempts
|
16
19
|
clear_preexisting_data
|
17
20
|
Scan::Runner.new.run
|
18
|
-
|
21
|
+
print_try_scan_result
|
19
22
|
return true
|
20
23
|
rescue FastlaneCore::Interface::FastlaneTestFailure => _
|
21
|
-
failed_tests =
|
22
|
-
|
23
|
-
|
24
|
-
return false if @attempt >= @options[:try_count]
|
24
|
+
failed_tests = failed_tests_from_xcresult_report
|
25
|
+
print_try_scan_result(failed_tests_count: failed_tests.size)
|
26
|
+
return false if finish?
|
25
27
|
|
26
28
|
@attempt += 1
|
27
29
|
update_scan_options(failed_tests)
|
28
30
|
retry
|
29
31
|
rescue FastlaneCore::Interface::FastlaneBuildFailure => _
|
30
|
-
return false if
|
32
|
+
return false if finish?
|
31
33
|
|
32
34
|
@attempt += 1
|
33
35
|
retry
|
34
36
|
end
|
35
37
|
end
|
36
38
|
|
37
|
-
def
|
38
|
-
|
39
|
-
output_types = Scan.config[:output_types].split(',')
|
40
|
-
output_types << 'junit'
|
41
|
-
Scan.config[:output_types] = output_types.join(',')
|
42
|
-
end
|
43
|
-
@options[:try_count] = 1 if @options[:try_count] < 1
|
39
|
+
def finish?
|
40
|
+
@attempt >= @options[:try_count]
|
44
41
|
end
|
45
42
|
|
46
43
|
def print_summary
|
@@ -70,9 +67,7 @@ module TryScanManager
|
|
70
67
|
FastlaneScanHelper.remove_report_files
|
71
68
|
end
|
72
69
|
|
73
|
-
def
|
74
|
-
return unless parallel_running?
|
75
|
-
|
70
|
+
def print_try_scan_result(failed_tests_count: 0)
|
76
71
|
FastlaneCore::UI.important("TryScan: result after #{ordinalized_attempt} shot 👇")
|
77
72
|
FastlaneCore::PrintTable.print_values(
|
78
73
|
config: {"Number of tests" => tests_count_from_xcresult_report, "Number of failures" => failed_tests_count},
|
@@ -93,98 +88,61 @@ module TryScanManager
|
|
93
88
|
end
|
94
89
|
end
|
95
90
|
|
96
|
-
def
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
scan_options[:skip_build] = true
|
102
|
-
scan_options[:test_without_building] = true
|
103
|
-
scan_options[:build_for_testing] = false
|
104
|
-
scan_options.delete(:skip_testing)
|
105
|
-
Scan.cache.clear
|
106
|
-
scan_options.each do |key, val|
|
107
|
-
next if val.nil?
|
108
|
-
|
109
|
-
Scan.config.set(key, val) unless val.nil?
|
110
|
-
FastlaneCore::UI.verbose("\tSetting #{key.to_s} to #{val}")
|
111
|
-
end
|
91
|
+
def prepare_scan_config(scan_options)
|
92
|
+
Scan.config = FastlaneCore::Configuration.create(
|
93
|
+
Fastlane::Actions::ScanAction.available_options,
|
94
|
+
FastlaneScanHelper.scan_options_from_try_scan_options(scan_options)
|
95
|
+
)
|
112
96
|
end
|
113
97
|
|
114
|
-
def
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
xcargs.slice!('build-for-testing')
|
119
|
-
end
|
120
|
-
if xcargs.include?('-quiet')
|
121
|
-
FastlaneCore::UI.important('Disabling -quiet as failing tests cannot be found with it enabled.')
|
122
|
-
xcargs.gsub!('-quiet', '')
|
98
|
+
def configure_xcargs
|
99
|
+
if @options[:xcargs]&.include?('-parallel-testing-enabled')
|
100
|
+
FastlaneCore::UI.important("TryScan overwrites `-parallel-testing-enabled` in :xcargs, use :try_parallel option instead")
|
101
|
+
@options[:xcargs].gsub!(/-parallel-testing-enabled(=|\s+)(YES|NO)/, '')
|
123
102
|
end
|
124
|
-
@options.select { |key, _| FastlaneScanHelper.valid_scan_keys.include?(key) }.merge({ xcargs: xcargs })
|
125
|
-
end
|
126
103
|
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
else
|
131
|
-
failed_tests_from_junit_report
|
104
|
+
if @options[:xcargs]&.include?('-parallel-testing-worker-count')
|
105
|
+
FastlaneCore::UI.important("TryScan overwrites `-parallel-testing-worker-count` in :xcargs, use :concurrent_workers option instead")
|
106
|
+
@options[:xcargs].gsub!(/-parallel-testing-worker-count(=|\s+)(\d+)/, '')
|
132
107
|
end
|
133
|
-
end
|
134
108
|
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
end
|
140
|
-
|
141
|
-
def failed_tests_from_junit_report
|
142
|
-
report = junit_report
|
143
|
-
suite_name = report.xpath('testsuites/@name').to_s.split('.')[0]
|
144
|
-
test_cases = report.xpath('//testcase')
|
145
|
-
only_testing = []
|
146
|
-
test_cases.each do |test_case|
|
147
|
-
next if test_case.xpath('failure').empty?
|
148
|
-
|
149
|
-
test_class = test_case.xpath('@classname').to_s.split('.')[1]
|
150
|
-
test_name = test_case.xpath('@name')
|
151
|
-
only_testing << "#{suite_name}/#{test_class}/#{test_name}"
|
109
|
+
if @options[:xcargs]&.include?('build-for-testing') || @options[:build_for_testing]
|
110
|
+
FastlaneCore::UI.important("TryScan rejects `build-for-testing` request, use it in a separate scan lane")
|
111
|
+
@options[:xcargs].slice!('build-for-testing')
|
112
|
+
@options[:build_for_testing] = nil
|
152
113
|
end
|
153
|
-
only_testing
|
154
|
-
end
|
155
114
|
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
115
|
+
xcargs = []
|
116
|
+
if @options[:try_parallel]
|
117
|
+
xcargs << '-parallel-testing-enabled YES'
|
118
|
+
if @options[:parallel_workers] || @options[:concurrent_workers]
|
119
|
+
workers_count = [@options[:parallel_workers].to_i, @options[:concurrent_workers].to_i].max
|
120
|
+
xcargs << "-parallel-testing-worker-count #{workers_count}"
|
121
|
+
@options[:concurrent_workers] = nil
|
122
|
+
end
|
123
|
+
else
|
124
|
+
xcargs << '-parallel-testing-enabled NO'
|
164
125
|
end
|
165
|
-
@
|
126
|
+
@options[:xcargs] = "#{@options[:xcargs].to_s} #{xcargs.join(' ')}"
|
166
127
|
end
|
167
128
|
|
168
|
-
def
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
new_suites.css("testsuite").zip(old_suites.css("testsuite")).each do |new_suite, old_suite|
|
177
|
-
old_suite.attributes["failures"].value = new_suite.attributes["failures"].value
|
178
|
-
end
|
129
|
+
def update_scan_options(failed_tests)
|
130
|
+
scan_options = FastlaneScanHelper.scan_options_from_try_scan_options(@options)
|
131
|
+
scan_options[:only_testing] = failed_tests
|
132
|
+
scan_options[:skip_build] = true
|
133
|
+
scan_options.delete(:skip_testing)
|
134
|
+
if @options[:try_parallel] && !@options[:retry_parallel]
|
135
|
+
scan_options[:xcargs].gsub!(/-parallel-testing-enabled(=|\s+)(YES|NO)/, '-parallel-testing-enabled NO')
|
136
|
+
scan_options[:xcargs].gsub!(/-parallel-testing-worker-count(=|\s+)(\d+)/, '')
|
179
137
|
end
|
180
138
|
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
end
|
185
|
-
end
|
139
|
+
Scan.cache.clear
|
140
|
+
scan_options.each do |key, val|
|
141
|
+
next if val.nil?
|
186
142
|
|
187
|
-
|
143
|
+
Scan.config.set(key, val)
|
144
|
+
FastlaneCore::UI.verbose("\tSetting #{key.to_s} to #{val}")
|
145
|
+
end
|
188
146
|
end
|
189
147
|
|
190
148
|
def parse_xcresult_report
|
@@ -201,8 +159,14 @@ module TryScanManager
|
|
201
159
|
only_testing = []
|
202
160
|
parse_xcresult_report['issues']['testFailureSummaries']['_values'].each do |failed_test|
|
203
161
|
suite_name = failed_test['producingTarget']['_value']
|
204
|
-
|
205
|
-
|
162
|
+
test_path = failed_test['testCaseName']['_value']
|
163
|
+
begin
|
164
|
+
test_class = test_path.split('.').first
|
165
|
+
test_name = test_path.split('.')[1].split('(').first
|
166
|
+
rescue NoMethodError => _
|
167
|
+
test_class = test_path.split('[')[1].split(' ').first
|
168
|
+
test_name = test_path.split(' ')[1].split(']').first
|
169
|
+
end
|
206
170
|
only_testing << "#{suite_name}/#{test_class}/#{test_name}"
|
207
171
|
end
|
208
172
|
only_testing
|
metadata
CHANGED
@@ -1,43 +1,15 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: fastlane-plugin-try_scan
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.5.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Alexey Alter-Pesotskiy
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2020-06-
|
11
|
+
date: 2020-06-25 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
|
-
- !ruby/object:Gem::Dependency
|
14
|
-
name: nokogiri
|
15
|
-
requirement: !ruby/object:Gem::Requirement
|
16
|
-
requirements:
|
17
|
-
- - ">="
|
18
|
-
- !ruby/object:Gem::Version
|
19
|
-
version: '0'
|
20
|
-
type: :runtime
|
21
|
-
prerelease: false
|
22
|
-
version_requirements: !ruby/object:Gem::Requirement
|
23
|
-
requirements:
|
24
|
-
- - ">="
|
25
|
-
- !ruby/object:Gem::Version
|
26
|
-
version: '0'
|
27
|
-
- !ruby/object:Gem::Dependency
|
28
|
-
name: json
|
29
|
-
requirement: !ruby/object:Gem::Requirement
|
30
|
-
requirements:
|
31
|
-
- - ">="
|
32
|
-
- !ruby/object:Gem::Version
|
33
|
-
version: '0'
|
34
|
-
type: :runtime
|
35
|
-
prerelease: false
|
36
|
-
version_requirements: !ruby/object:Gem::Requirement
|
37
|
-
requirements:
|
38
|
-
- - ">="
|
39
|
-
- !ruby/object:Gem::Version
|
40
|
-
version: '0'
|
41
13
|
- !ruby/object:Gem::Dependency
|
42
14
|
name: pry
|
43
15
|
requirement: !ruby/object:Gem::Requirement
|