fastlane-plugin-test_center 3.6.3.parallelizing.pre.alpha.pre.1 → 3.6.3

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 0b03566f2644f92ffde801c8d83a6bd009e59fd947437cf9b6ea26b737ae0996
4
- data.tar.gz: 80d1d785126c154dfda7a2aee7ded8654bd58776746144550e7d37c863e126c4
3
+ metadata.gz: d4b6e643411a6c7dc79cc1ffdf6f2e92d6eca01a2a31c14c8f2904290f0792a3
4
+ data.tar.gz: d57683f16900bd9460adfe2c613dff614dc11af4a3cccbb315391a773f7ffd12
5
5
  SHA512:
6
- metadata.gz: 481326edd2420e6cc1f5347c434b0089b32dc526e0e09a1279fd8131855771711fb8676a3251e5d3003bb7a35dcd6ba2cb1b505d62b482395fe06ec3df4e5f3b
7
- data.tar.gz: f4360d6b14dda570832bba2b9c86e127beea79f83a23fd3e4c0730e017b2f51e6216c5b0fa4ccd688fc0acd1d01d5d0376718cae53f13f402477f7aa8054ed8e
6
+ metadata.gz: 2662f68881f0cfd6e75721f7fd13e9ee229981d1ddaf6b01ba3c1effd1510ba3e0df7542cf04b89ac7f36d9a83c94f11f201bed01246f376a30ad561c806d610
7
+ data.tar.gz: 5855c0fd93652ac1a034a8a268268c9587ffe5de8420b65d4c1fa4fe614198d4ab9190f63589abaacd961e20517b879b8508453db719c1aff78dd57337b21495
@@ -4,7 +4,7 @@ module Fastlane
4
4
  module TestCenter
5
5
  # Return all .rb files inside the "actions" and "helper" directory
6
6
  def self.all_classes
7
- Dir[File.expand_path('**/{actions,helper}/**/*.rb', File.dirname(__FILE__))]
7
+ Dir[File.expand_path('**/{actions,helper}/*.rb', File.dirname(__FILE__))]
8
8
  end
9
9
  end
10
10
  end
@@ -14,7 +14,7 @@ module Fastlane
14
14
  collate_bundles(base_bundle_path, other_bundlepath)
15
15
  end
16
16
  end
17
- # FileUtils.rm_rf(params[:collated_bundle])
17
+ FileUtils.rm_rf(params[:collated_bundle])
18
18
  FileUtils.cp_r(base_bundle_path, params[:collated_bundle])
19
19
  UI.message("Finished collating test_result bundle to '#{params[:collated_bundle]}'")
20
20
  end
@@ -5,7 +5,6 @@ module Fastlane
5
5
  require 'shellwords'
6
6
  require 'xctest_list'
7
7
  require 'plist'
8
- require_relative '../helper/multi_scan_manager/runner'
9
8
 
10
9
  class MultiScanAction < Action
11
10
  def self.run(params)
@@ -20,13 +19,9 @@ module Fastlane
20
19
  params._values
21
20
  )
22
21
  end
23
- runner = ::TestCenter::Helper::MultiScanManager::Runner.new(params.values)
24
- tests_passed = runner.scan
25
- if params[:fail_build] && !tests_passed
26
- raise UI.test_failure!('Tests have failed')
27
- end
28
-
29
- summary = run_summary(params, tests_passed, runner.retry_total_count)
22
+ smart_scanner = ::TestCenter::Helper::CorrectingScanHelper.new(params.values)
23
+ tests_passed = smart_scanner.scan
24
+ summary = run_summary(params, tests_passed, smart_scanner.retry_total_count)
30
25
  unless Helper.test?
31
26
  FastlaneCore::PrintTable.print_values(
32
27
  config: summary,
@@ -89,19 +84,17 @@ module Fastlane
89
84
  options_to_remove = %i[
90
85
  try_count
91
86
  batch_count
92
- output_files
93
- parallelize
94
87
  quit_simulators
95
88
  testrun_completed_block
96
89
  test_without_building
97
90
  output_types
91
+ output_files
98
92
  ]
99
93
  config = FastlaneCore::Configuration.create(
100
94
  Fastlane::Actions::ScanAction.available_options,
101
95
  scan_options.merge(build_for_testing: true).reject { |k, _| options_to_remove.include?(k) }
102
96
  )
103
97
  Fastlane::Actions::ScanAction.run(config)
104
- remove_build_report_files
105
98
 
106
99
  scan_options.merge!(
107
100
  test_without_building: true,
@@ -109,16 +102,6 @@ module Fastlane
109
102
  ).delete(:build_for_testing)
110
103
  end
111
104
 
112
- def self.remove_build_report_files
113
- report_options = Scan::XCPrettyReporterOptionsGenerator.generate_from_scan_config
114
- output_files = report_options.instance_variable_get(:@output_files)
115
- output_directory = report_options.instance_variable_get(:@output_directory)
116
-
117
- output_files.each do |output_file|
118
- FileUtils.rm_f(File.join(output_directory, output_file))
119
- end
120
- end
121
-
122
105
  #####################################################
123
106
  # @!group Documentation
124
107
  #####################################################
@@ -189,13 +172,6 @@ module Fastlane
189
172
  description: "Comma separated list of the output types (e.g. html, junit, json, json-compilation-database)",
190
173
  default_value: "html,junit"
191
174
  ),
192
- FastlaneCore::ConfigItem.new(
193
- key: :parallelize,
194
- description: 'Run each batch of tests and/or each test target in parallel on its own Simulator',
195
- optional: true,
196
- is_string: false,
197
- default_value: false
198
- ),
199
175
  FastlaneCore::ConfigItem.new(
200
176
  key: :testrun_completed_block,
201
177
  description: 'A block invoked each time a test run completes',
@@ -341,26 +317,6 @@ module Fastlane
341
317
  output_files: 'report.json',
342
318
  fail_build: false
343
319
  )
344
- ",
345
- "
346
- UI.important(
347
- 'example: ' \\
348
- 'use the :xctestrun parameter instead of the :project parameter to find, ' \\
349
- 'build, and test the iOS app.'
350
- )
351
- Dir.mktmpdir do |derived_data_path|
352
- project_path = '/Users/lyndsey.ferguson/repo/fastlane-plugin-test_center/AtomicBoy/AtomicBoy.xcodeproj'
353
- command = \"bundle exec fastlane scan --build_for_testing true --project '#{project_path}' --derived_data_path #{derived_data_path} --scheme AtomicBoy\"
354
- `#{command}`
355
- xctestrun_file = Dir.glob(\"#{derived_data_path}/Build/Products/AtomicBoy*.xctestrun\").first
356
- multi_scan(
357
- scheme: 'AtomicBoy',
358
- try_count: 3,
359
- fail_build: false,
360
- xctestrun: xctestrun_file,
361
- test_without_building: true
362
- )
363
- end
364
320
  "
365
321
  ]
366
322
  end
@@ -0,0 +1,293 @@
1
+ module TestCenter
2
+ module Helper
3
+ require 'fastlane_core/ui/ui.rb'
4
+ require 'plist'
5
+ require 'json'
6
+ class CorrectingScanHelper
7
+ attr_reader :retry_total_count
8
+
9
+ def initialize(multi_scan_options)
10
+ @batch_count = multi_scan_options[:batch_count] || 1
11
+ @output_directory = multi_scan_options[:output_directory] || 'test_results'
12
+ @try_count = multi_scan_options[:try_count]
13
+ @quit_simulators = multi_scan_options[:quit_simulators]
14
+ @retry_total_count = 0
15
+ @testrun_completed_block = multi_scan_options[:testrun_completed_block]
16
+ @given_custom_report_file_name = multi_scan_options[:custom_report_file_name]
17
+ @given_output_types = multi_scan_options[:output_types]
18
+ @given_output_files = multi_scan_options[:output_files]
19
+ @scan_options = multi_scan_options.reject do |option, _|
20
+ %i[
21
+ output_directory
22
+ only_testing
23
+ skip_testing
24
+ clean
25
+ try_count
26
+ batch_count
27
+ quit_simulators
28
+ custom_report_file_name
29
+ fail_build
30
+ testrun_completed_block
31
+ output_types
32
+ output_files
33
+ ].include?(option)
34
+ end
35
+ @scan_options[:clean] = false
36
+ @test_collector = TestCollector.new(multi_scan_options)
37
+ end
38
+
39
+ def scan
40
+ tests_passed = true
41
+ @testables_count = @test_collector.testables.size
42
+ @test_collector.testables.each do |testable|
43
+ tests_passed = scan_testable(testable) && tests_passed
44
+ end
45
+ tests_passed
46
+ end
47
+
48
+ def scan_testable(testable)
49
+ tests_passed = true
50
+ reportnamer = ReportNameHelper.new(
51
+ @given_output_types,
52
+ @given_output_files,
53
+ @given_custom_report_file_name
54
+ )
55
+ output_directory = @output_directory
56
+ testable_tests = @test_collector.testables_tests[testable]
57
+ if testable_tests.empty?
58
+ FastlaneCore::UI.important("There are no tests to run in testable '#{testable}'. Skipping")
59
+ return true
60
+ end
61
+
62
+ if @batch_count > 1 || @testables_count > 1
63
+ current_batch = 1
64
+ testable_tests.each_slice((testable_tests.length / @batch_count.to_f).round).to_a.each do |tests_batch|
65
+ if @testables_count > 1
66
+ output_directory = File.join(@output_directory, "results-#{testable}")
67
+ end
68
+ FastlaneCore::UI.header("Starting test run on testable '#{testable}'")
69
+ if @scan_options[:result_bundle]
70
+ FastlaneCore::UI.message("Clearing out previous test_result bundles in #{output_directory}")
71
+ FileUtils.rm_rf(Dir.glob("#{output_directory}/*.test_result"))
72
+ end
73
+
74
+ tests_passed = correcting_scan(
75
+ {
76
+ only_testing: tests_batch,
77
+ output_directory: output_directory
78
+ },
79
+ current_batch,
80
+ reportnamer
81
+ ) && tests_passed
82
+ current_batch += 1
83
+ reportnamer.increment
84
+ end
85
+ else
86
+ options = {
87
+ output_directory: output_directory,
88
+ only_testing: testable_tests
89
+ }
90
+ tests_passed = correcting_scan(options, 1, reportnamer) && tests_passed
91
+ end
92
+ collate_reports(output_directory, reportnamer)
93
+ tests_passed
94
+ end
95
+
96
+ def test_result_bundlepaths(output_directory, reportnamer)
97
+ [
98
+ File.join(output_directory, @scan_options[:scheme]) + '.test_result',
99
+ File.join(output_directory, @scan_options[:scheme]) + "_#{reportnamer.report_count}.test_result"
100
+ ]
101
+ end
102
+
103
+ def collate_reports(output_directory, reportnamer)
104
+ collate_junit_reports(output_directory, reportnamer)
105
+
106
+ if reportnamer.includes_html?
107
+ collate_html_reports(output_directory, reportnamer)
108
+ end
109
+
110
+ if reportnamer.includes_json?
111
+ collate_json_reports(output_directory, reportnamer)
112
+ end
113
+
114
+ if @scan_options[:result_bundle]
115
+ collate_test_result_bundles(output_directory, reportnamer)
116
+ end
117
+ end
118
+
119
+ def passed_test_count_from_summary(summary)
120
+ /.*Executed (?<test_count>\d+) test, with (?<test_failures>\d+) failure/ =~ summary
121
+ test_count.to_i - test_failures.to_i
122
+ end
123
+
124
+ def collate_test_result_bundles(output_directory, reportnamer)
125
+ test_result_bundlepaths = Dir.glob("#{output_directory}/#{@scan_options[:scheme]}*.test_result").map do |relative_test_result_bundle_filepath|
126
+ File.absolute_path(relative_test_result_bundle_filepath)
127
+ end
128
+ if test_result_bundlepaths.size > 1
129
+ config = FastlaneCore::Configuration.create(
130
+ Fastlane::Actions::CollateTestResultBundlesAction.available_options,
131
+ {
132
+ bundles: test_result_bundlepaths.sort { |f1, f2| File.mtime(f1) <=> File.mtime(f2) },
133
+ collated_bundle: File.join(output_directory, @scan_options[:scheme]) + '.test_result'
134
+ }
135
+ )
136
+ Fastlane::Actions::CollateTestResultBundlesAction.run(config)
137
+ end
138
+ retried_test_result_bundlepaths = Dir.glob("#{output_directory}/#{@scan_options[:scheme]}_*.test_result")
139
+ FileUtils.rm_rf(retried_test_result_bundlepaths)
140
+ end
141
+
142
+ def collate_json_reports(output_directory, reportnamer)
143
+ report_filepaths = Dir.glob("#{output_directory}/#{reportnamer.json_fileglob}").map do |relative_filepath|
144
+ File.absolute_path(relative_filepath)
145
+ end
146
+ if report_filepaths.size > 1
147
+ config = FastlaneCore::Configuration.create(
148
+ Fastlane::Actions::CollateJsonReportsAction.available_options,
149
+ {
150
+ reports: report_filepaths.sort { |f1, f2| File.mtime(f1) <=> File.mtime(f2) },
151
+ collated_report: File.absolute_path(File.join(output_directory, reportnamer.json_reportname))
152
+ }
153
+ )
154
+ Fastlane::Actions::CollateJsonReportsAction.run(config)
155
+ end
156
+ retried_json_reportfiles = Dir.glob("#{output_directory}/#{reportnamer.json_numbered_fileglob}")
157
+ FileUtils.rm_f(retried_json_reportfiles)
158
+ end
159
+
160
+ def collate_html_reports(output_directory, reportnamer)
161
+ report_files = Dir.glob("#{output_directory}/#{reportnamer.html_fileglob}").map do |relative_filepath|
162
+ File.absolute_path(relative_filepath)
163
+ end
164
+ if report_files.size > 1
165
+ config = FastlaneCore::Configuration.create(
166
+ Fastlane::Actions::CollateHtmlReportsAction.available_options,
167
+ {
168
+ reports: report_files.sort { |f1, f2| File.mtime(f1) <=> File.mtime(f2) },
169
+ collated_report: File.absolute_path(File.join(output_directory, reportnamer.html_reportname))
170
+ }
171
+ )
172
+ Fastlane::Actions::CollateHtmlReportsAction.run(config)
173
+ end
174
+ retried_html_reportfiles = Dir.glob("#{output_directory}/#{reportnamer.html_numbered_fileglob}")
175
+ FileUtils.rm_f(retried_html_reportfiles)
176
+ end
177
+
178
+ def collate_junit_reports(output_directory, reportnamer)
179
+ report_files = Dir.glob("#{output_directory}/#{reportnamer.junit_fileglob}").map do |relative_filepath|
180
+ File.absolute_path(relative_filepath)
181
+ end
182
+ if report_files.size > 1
183
+ config = FastlaneCore::Configuration.create(
184
+ Fastlane::Actions::CollateJunitReportsAction.available_options,
185
+ {
186
+ reports: report_files.sort { |f1, f2| File.mtime(f1) <=> File.mtime(f2) },
187
+ collated_report: File.absolute_path(File.join(output_directory, reportnamer.junit_reportname))
188
+ }
189
+ )
190
+ Fastlane::Actions::CollateJunitReportsAction.run(config)
191
+ end
192
+ retried_junit_reportfiles = Dir.glob("#{output_directory}/#{reportnamer.junit_numbered_fileglob}")
193
+ FileUtils.rm_f(retried_junit_reportfiles)
194
+ end
195
+
196
+ def correcting_scan(scan_run_options, batch, reportnamer)
197
+ scan_options = @scan_options.merge(scan_run_options)
198
+ try_count = 0
199
+ tests_passed = true
200
+ xcpretty_json_file_output = ENV['XCPRETTY_JSON_FILE_OUTPUT']
201
+ begin
202
+ try_count += 1
203
+ config = FastlaneCore::Configuration.create(
204
+ Fastlane::Actions::ScanAction.available_options,
205
+ scan_options.merge(reportnamer.scan_options)
206
+ )
207
+ quit_simulators
208
+ if reportnamer.includes_json?
209
+ ENV['XCPRETTY_JSON_FILE_OUTPUT'] = File.join(
210
+ scan_options[:output_directory],
211
+ reportnamer.json_last_reportname
212
+ )
213
+ end
214
+ Fastlane::Actions::ScanAction.run(config)
215
+ @testrun_completed_block && @testrun_completed_block.call(
216
+ testrun_info(batch, try_count, reportnamer, scan_options[:output_directory])
217
+ )
218
+ tests_passed = true
219
+ rescue FastlaneCore::Interface::FastlaneTestFailure => e
220
+ FastlaneCore::UI.verbose("Scan failed with #{e}")
221
+ info = testrun_info(batch, try_count, reportnamer, scan_options[:output_directory])
222
+ @testrun_completed_block && @testrun_completed_block.call(
223
+ info
224
+ )
225
+ if try_count < @try_count
226
+ @retry_total_count += 1
227
+ scan_options.delete(:code_coverage)
228
+ scan_options[:only_testing] = info[:failed].map(&:shellsafe_testidentifier)
229
+ FastlaneCore::UI.message('Re-running scan on only failed tests')
230
+ reportnamer.increment
231
+ if @scan_options[:result_bundle]
232
+ built_test_result, moved_test_result = test_result_bundlepaths(
233
+ scan_options[:output_directory], reportnamer
234
+ )
235
+ FileUtils.mv(built_test_result, moved_test_result)
236
+ end
237
+ retry
238
+ end
239
+ tests_passed = false
240
+ ensure
241
+ ENV['XCPRETTY_JSON_FILE_OUTPUT'] = xcpretty_json_file_output
242
+ end
243
+ tests_passed
244
+ end
245
+
246
+ def testrun_info(batch, try_count, reportnamer, output_directory)
247
+ report_filepath = File.join(output_directory, reportnamer.junit_last_reportname)
248
+ config = FastlaneCore::Configuration.create(
249
+ Fastlane::Actions::TestsFromJunitAction.available_options,
250
+ {
251
+ junit: File.absolute_path(report_filepath)
252
+ }
253
+ )
254
+ junit_results = Fastlane::Actions::TestsFromJunitAction.run(config)
255
+
256
+ info = {
257
+ failed: junit_results[:failed],
258
+ passing: junit_results[:passing],
259
+ batch: batch,
260
+ try_count: try_count,
261
+ report_filepath: report_filepath
262
+ }
263
+ if reportnamer.includes_html?
264
+ html_report_filepath = File.join(output_directory, reportnamer.html_last_reportname)
265
+ info[:html_report_filepath] = html_report_filepath
266
+ end
267
+ if reportnamer.includes_json?
268
+ json_report_filepath = File.join(output_directory, reportnamer.json_last_reportname)
269
+ info[:json_report_filepath] = json_report_filepath
270
+ end
271
+ if @scan_options[:result_bundle]
272
+ test_result_suffix = '.test_result'
273
+ test_result_suffix.prepend("_#{reportnamer.report_count}") unless reportnamer.report_count.zero?
274
+ test_result_bundlepath = File.join(output_directory, @scan_options[:scheme]) + test_result_suffix
275
+ info[:test_result_bundlepath] = test_result_bundlepath
276
+ end
277
+ info
278
+ end
279
+
280
+ def quit_simulators
281
+ return unless @quit_simulators
282
+
283
+ Fastlane::Actions.sh("killall -9 'iPhone Simulator' 'Simulator' 'SimulatorBridge' &> /dev/null || true", log: false)
284
+ launchctl_list_count = 0
285
+ while Fastlane::Actions.sh('launchctl list | grep com.apple.CoreSimulator.CoreSimulatorService || true', log: false) != ''
286
+ break if (launchctl_list_count += 1) > 10
287
+ Fastlane::Actions.sh('launchctl remove com.apple.CoreSimulator.CoreSimulatorService &> /dev/null || true', log: false)
288
+ sleep(1)
289
+ end
290
+ end
291
+ end
292
+ end
293
+ end
@@ -64,12 +64,9 @@ module TestCenter
64
64
  numbered_filename(@output_files.to_s.split(',')[junit_index])
65
65
  end
66
66
 
67
- def junit_reportname(suffix = '')
67
+ def junit_reportname
68
68
  junit_index = @output_types.split(',').find_index('junit')
69
- report_name = @output_files.to_s.split(',')[junit_index]
70
- return report_name if suffix.empty?
71
-
72
- "#{File.basename(report_name, '.*')}-#{suffix}#{junit_filextension}"
69
+ @output_files.to_s.split(',')[junit_index]
73
70
  end
74
71
 
75
72
  def junit_filextension
@@ -93,12 +90,9 @@ module TestCenter
93
90
  numbered_filename(@output_files.to_s.split(',')[html_index])
94
91
  end
95
92
 
96
- def html_reportname(suffix = '')
93
+ def html_reportname
97
94
  html_index = @output_types.split(',').find_index('html')
98
- report_name = @output_files.to_s.split(',')[html_index]
99
- return report_name if suffix.empty?
100
-
101
- "#{File.basename(report_name, '.*')}-#{suffix}#{html_filextension}"
95
+ @output_files.to_s.split(',')[html_index]
102
96
  end
103
97
 
104
98
  def html_filextension
@@ -122,12 +116,9 @@ module TestCenter
122
116
  numbered_filename(@output_files.to_s.split(',')[json_index])
123
117
  end
124
118
 
125
- def json_reportname(suffix = '')
119
+ def json_reportname
126
120
  json_index = @output_types.split(',').find_index('json')
127
- report_name = @output_files.to_s.split(',')[json_index]
128
- return report_name if suffix.empty?
129
-
130
- "#{File.basename(report_name, '.*')}-#{suffix}#{json_filextension}"
121
+ @output_files.to_s.split(',')[json_index]
131
122
  end
132
123
 
133
124
  def json_filextension