fastlane-plugin-test_center 3.10.0 → 3.11.1

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: e5adcd23e02c79f85550d8bb05a638eeffa1db8461d07c3a17901e12f0a7e7f3
4
- data.tar.gz: '059db5183c79f5775d97cb6f38c534b1cb0b916315479ec68311fe953f624062'
3
+ metadata.gz: bddea97ab673c1bd898093a97dbb8382f71a45b43c3383cd4324742f0074492a
4
+ data.tar.gz: 727b0661fc19d6a710f793b8f5f9392ea62a195891b1149a244dd5aefbaf10a4
5
5
  SHA512:
6
- metadata.gz: 17582ea3a4f1dbc6ed043fa54bc9949e167cd884b9bd24335b91164cc365b15c9bdaaa697c6c727a921b9ea15ea10f4a2b6d0bc02448e2b7064d05097e36bbdc
7
- data.tar.gz: 73ae34df7f25fe36dae15fbf8c9ce8bccc1368194a4e03e086a2463440e9815f495a5f4073b30daac52ca0bb64da75d1403a3a4c7fe614fe486a01ef5a977724
6
+ metadata.gz: c686a799d1e1cc3d20066357b62e895ae68504b0438374958a3d1bea6da748bba1665fd5b8d77629d975ee0dd0d1fddb3ee4e992bee3e0773f3fde95dc009234
7
+ data.tar.gz: ffd5facb9d4e62ad79ae59852b5794bba8fabceb327e3aa628152d7004e1fba6c0694a1746fdbd186b9e474d3dc31820d2c453afeaab009778a3b8445d47b1b6
data/README.md CHANGED
@@ -21,7 +21,7 @@ Have you ever spent too much time trying to fix fragile tests only to give up wi
21
21
 
22
22
  ## Features
23
23
 
24
- This plugin makes testing your iOS app easier by providing you actions that give you greater control over everything related to testing your app.
24
+ This plugin makes testing your iOS app easier by providing you actions that give you greater control over everything related to testing your app.
25
25
 
26
26
  `multi_scan` began when I created an action to only re-run the failed tests in order to determine if they were truly failing, or if they were failing randomly due to a fragile infrastructure. This action morphed into an entire plugin with many actions in the testing category.
27
27
 
@@ -35,6 +35,8 @@ _read the documentation on each action by clicking on the action name_
35
35
  | [`suppress_tests_from_junit`](docs/feature_details/suppress_tests_from_junit.md) | suppress tests in an Xcode Scheme using those in a Junit test report | ios, mac |
36
36
  | [`suppress_tests`](docs/feature_details/suppress_tests.md) | suppress tests in an Xcode Scheme | ios, mac |
37
37
  | [`suppressed_tests`](docs/feature_details/suppressed_tests.md) | returns a list of the suppressed tests in your Xcode Project or Scheme | ios, mac |
38
+ | [`test_options_from_testplan`](docs/feature_details/test_options_from_testplan.md) | returns the tests and test code coverage configuration for a given testplan | ios, mac |
39
+ | [`testplans_from_scheme`](docs/feature_details/testplans_from_scheme.md) | returns the testplans that an Xcode Scheme references | ios, mac |
38
40
  | [`tests_from_junit`](docs/feature_details/tests_from_junit.md) | returns the passing and failing tests in a Junit test report | ios, mac |
39
41
  | [`tests_from_xctestrun`](docs/feature_details/tests_from_xctestrun.md) | returns a list of tests for each test target in a `xctestrun` file | ios, mac |
40
42
  | [`collate_junit_reports`](docs/feature_details/collate_junit_reports.md) | combines multiple Junit test reports into one report | ios, mac |
@@ -62,7 +64,7 @@ The most popular action in the `test_center` plugin is `multi_scan`, and if you
62
64
  multi_scan(
63
65
  project: File.absolute_path('../AtomicBoy/AtomicBoy.xcodeproj'),
64
66
  scheme: 'AtomicBoy',
65
- try_count: 3, # retry _failing_ tests up to three times^1.
67
+ try_count: 3, # retry _failing_ tests up to three times^1.
66
68
  fail_build: false,
67
69
  parallel_testrun_count: 4 # run subsets of your tests on parallel simulators^2
68
70
  )
@@ -91,6 +93,11 @@ For more information about how the `fastlane` plugin system works, check out the
91
93
 
92
94
  _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).
93
95
 
96
+ ## Supporters
97
+
98
+ ![Владислав Давыдов](https://avatars1.githubusercontent.com/u/47553334?s=44&u=4691860dba898943b947180b3d28bb85851b0d7c&v=4)
99
+ [vdavydovHH](https://github.com/vdavydovHH)
100
+
94
101
  ## License
95
102
 
96
103
  MIT
@@ -14,6 +14,10 @@ module Fastlane
14
14
  class MultiScanAction < Action
15
15
  def self.run(params)
16
16
  params[:quit_simulators] = params._values[:force_quit_simulator] if params._values[:force_quit_simulator]
17
+ if params[:try_count] < 1
18
+ UI.important('multi_scan will not test any if :try_count < 0, setting to 1')
19
+ params[:try_count] = 1
20
+ end
17
21
 
18
22
  strip_leading_and_trailing_whitespace_from_output_types(params)
19
23
 
@@ -228,7 +232,7 @@ module Fastlane
228
232
  end
229
233
 
230
234
  def self.prepare_scan_options_for_build_for_testing(scan_options)
231
- build_options = scan_options.merge(build_for_testing: true).reject { |k| k == :test_without_building }
235
+ build_options = scan_options.merge(build_for_testing: true).reject { |k| %i[test_without_building, testplan].include?(k) }
232
236
  Scan.config = FastlaneCore::Configuration.create(
233
237
  Fastlane::Actions::ScanAction.available_options,
234
238
  ScanHelper.scan_options_from_multi_scan_options(build_options)
@@ -240,7 +244,11 @@ module Fastlane
240
244
  end
241
245
 
242
246
  def self.update_xctestrun_after_build(scan_options)
243
- xctestrun_files = Dir.glob("#{Scan.config[:derived_data_path]}/Build/Products/*.xctestrun")
247
+ glob_pattern = "#{Scan.config[:derived_data_path]}/Build/Products/*.xctestrun"
248
+ if scan_options[:testplan]
249
+ glob_pattern = "#{Scan.config[:derived_data_path]}/Build/Products/*#{scan_options[:testplan]}*.xctestrun"
250
+ end
251
+ xctestrun_files = Dir.glob(glob_pattern)
244
252
  UI.verbose("After building, found xctestrun files #{xctestrun_files} (choosing 1st)")
245
253
  scan_options[:xctestrun] = xctestrun_files.first
246
254
  end
@@ -0,0 +1,90 @@
1
+ require 'json'
2
+
3
+ module Fastlane
4
+ module Actions
5
+ class TestOptionsFromTestplanAction < Action
6
+ def self.run(params)
7
+ testplan_path = params[:testplan]
8
+
9
+ testplan = JSON.load(File.open(testplan_path))
10
+ only_testing = []
11
+ UI.verbose("Examining testplan JSON: #{testplan}")
12
+ testplan['testTargets'].each do |test_target|
13
+ testable = test_target.dig('target', 'name')
14
+ if test_target.key?('selectedTests')
15
+ UI.verbose(" Found selectedTests")
16
+ test_identifiers = test_target['selectedTests'].each do |selected_test|
17
+ UI.verbose(" Found test: '#{selected_test}'")
18
+ only_testing << "#{testable}/#{selected_test.sub('\/', '/')}"
19
+ end
20
+ else
21
+ UI.verbose(" No selected tests, using testable '#{testable}'")
22
+ only_testing << testable
23
+ end
24
+ end
25
+ {
26
+ code_coverage: testplan.dig('defaultOptions', 'codeCoverage'),
27
+ only_testing: only_testing
28
+ }
29
+ end
30
+
31
+ #####################################################
32
+ # @!group Documentation
33
+ #####################################################
34
+
35
+ def self.description
36
+ "☑️ Gets test info from a given test plan"
37
+ end
38
+
39
+ def self.details
40
+ "Gets tests info consisting of tests to run and whether or not code coverage is enabled"
41
+ end
42
+
43
+ def self.available_options
44
+ [
45
+ FastlaneCore::ConfigItem.new(
46
+ key: :testplan,
47
+ optional: true,
48
+ env_name: "FL_TEST_OPTIONS_FROM_TESTPLAN_TESTPLAN",
49
+ description: "The Xcode testplan to read the test info from",
50
+ verify_block: proc do |test_plan|
51
+ UI.user_error!("Error: Xcode Test Plan '#{test_plan}' is not valid!") if test_plan and test_plan.empty?
52
+ UI.user_error!("Error: Test Plan does not exist at path '#{test_plan}'") unless File.exist?(test_plan)
53
+ end
54
+ )
55
+ ]
56
+ end
57
+
58
+ def self.return_value
59
+ "Returns a Hash with keys :code_coverage and :only_testing for the given testplan"
60
+ end
61
+
62
+ def self.example_code
63
+ [
64
+ "
65
+ UI.important(
66
+ 'example: ' \\
67
+ 'get the tests and the test coverage configuration from a given testplan'
68
+ )
69
+ test_options = test_options_from_testplan(
70
+ testplan: 'AtomicBoy/AtomicBoy_2.xctestplan'
71
+ )
72
+ UI.message(\"The AtomicBoy_2 testplan has the following tests: \#{test_options[:only_testing]}\")
73
+ "
74
+ ]
75
+ end
76
+
77
+ def self.authors
78
+ ["lyndsey-ferguson/lyndseydf"]
79
+ end
80
+
81
+ def self.category
82
+ :testing
83
+ end
84
+
85
+ def self.is_supported?(platform)
86
+ %i[ios mac].include?(platform)
87
+ end
88
+ end
89
+ end
90
+ end
@@ -0,0 +1,120 @@
1
+ module Fastlane
2
+ module Actions
3
+ class TestplansFromSchemeAction < Action
4
+ def self.run(params)
5
+ scheme = params[:scheme]
6
+ scheme_filepaths = schemes_from_project(params[:xcodeproj], scheme) || schemes_from_workspace(params[:workspace], scheme)
7
+ if scheme_filepaths.length.zero?
8
+ UI.user_error!("Error: cannot find any schemes in the Xcode project") if params[:xcodeproj]
9
+ UI.user_error!("Error: cannot find any schemes in the Xcode workspace") if params[:workspace]
10
+ end
11
+ testplan_paths = []
12
+ scheme_filepaths.each do |scheme_filepath|
13
+ UI.verbose("Looking in Scheme '#{scheme_filepath}' for any testplans")
14
+ xcscheme = Xcodeproj::XCScheme.new(scheme_filepath)
15
+ next if xcscheme.test_action.nil?
16
+ next if xcscheme.test_action.testables.to_a.empty?
17
+ next if xcscheme.test_action.testables[0].buildable_references.to_a.empty?
18
+ next if xcscheme.test_action.test_plans.to_a.empty?
19
+
20
+ xcodeproj = xcscheme.test_action.testables[0].buildable_references[0].target_referenced_container.sub('container:', '')
21
+ container_dir = scheme_filepath.sub(/#{xcodeproj}.*/, '')
22
+ xcscheme.test_action.test_plans.each do |testplan|
23
+ testplan_path = File.absolute_path(File.join(container_dir, testplan.target_referenced_container.sub('container:', '')))
24
+ UI.verbose(" found testplan '#{testplan_path}'")
25
+ testplan_paths << testplan_path
26
+ end
27
+ end
28
+ testplan_paths
29
+ end
30
+
31
+ def self.schemes_from_project(project_path, scheme)
32
+ return nil unless project_path
33
+
34
+ Dir.glob("#{project_path}/{xcshareddata,xcuserdata}/**/xcschemes/#{scheme || '*'}.xcscheme")
35
+ end
36
+
37
+ def self.schemes_from_workspace(workspace_path, scheme)
38
+ return nil unless workspace_path
39
+
40
+ xcworkspace = Xcodeproj::Workspace.new_from_xcworkspace(workspace_path)
41
+ scheme_filepaths = []
42
+ xcworkspace.file_references.each do |file_reference|
43
+ next if file_reference.path.include?('Pods/Pods.xcodeproj')
44
+
45
+ project_path = file_reference.absolute_path(File.dirname(workspace_path))
46
+ scheme_filepaths.concat(schemes_from_project(project_path, scheme))
47
+ end
48
+ scheme_filepaths
49
+ end
50
+
51
+ def self.description
52
+ "☑️Gets all the testplans that a Scheme references"
53
+ end
54
+
55
+ def self.authors
56
+ ["lyndsey-ferguson/lyndseydf"]
57
+ end
58
+
59
+ def self.available_options
60
+ [
61
+ FastlaneCore::ConfigItem.new(
62
+ key: :xcodeproj,
63
+ env_name: "FL_TESTPLANS_FROM_SCHEME_XCODE_PROJECT",
64
+ optional: true,
65
+ description: "The file path to the Xcode project file that references the Scheme",
66
+ verify_block: proc do |path|
67
+ path = File.expand_path(path.to_s)
68
+ UI.user_error!("Error: Xcode project file path not given!") unless path and !path.empty?
69
+ UI.user_error!("Error: Xcode project '#{path}' not found!") unless Dir.exist?(path)
70
+ end
71
+ ),
72
+ FastlaneCore::ConfigItem.new(
73
+ key: :workspace,
74
+ env_name: "FL_TESTPLANS_FROM_SCHEME_XCODE_WORKSPACE",
75
+ optional: true,
76
+ description: "The file path to the Xcode workspace file that references the Scheme",
77
+ verify_block: proc do |value|
78
+ v = File.expand_path(value.to_s)
79
+ UI.user_error!("Error: Workspace file not found at path '#{v}'") unless Dir.exist?(v)
80
+ UI.user_error!("Error: Workspace file is not a workspace, must end with .xcworkspace") unless v.include?(".xcworkspace")
81
+ end
82
+ ),
83
+ FastlaneCore::ConfigItem.new(
84
+ key: :scheme,
85
+ optional: true,
86
+ env_name: "FL_TESTPLANS_FROM_SCHEME_XCODE_SCHEME",
87
+ description: "The Xcode scheme referencing the testplan",
88
+ verify_block: proc do |scheme_name|
89
+ UI.user_error!("Error: Xcode Scheme '#{scheme_name}' is not valid!") if scheme_name and scheme_name.empty?
90
+ end
91
+ )
92
+ ]
93
+ end
94
+
95
+ def self.example_code
96
+ [
97
+ "
98
+ UI.important(
99
+ 'example: ' \\
100
+ 'get all the testplans that an Xcode Scheme references'
101
+ )
102
+ testplans = testplans_from_scheme(
103
+ xcodeproj: 'AtomicBoy/AtomicBoy.xcodeproj',
104
+ scheme: 'AtomicBoy'
105
+ )
106
+ UI.message(\"The AtomicBoy uses the following testplans: \#{testplans}\")
107
+ "
108
+ ]
109
+ end
110
+
111
+ def self.category
112
+ :testing
113
+ end
114
+
115
+ def self.is_supported?(platform)
116
+ %i[ios mac].include?(platform)
117
+ end
118
+ end
119
+ end
120
+ end
@@ -1,3 +1,5 @@
1
+ require_relative 'reportname_helper'
2
+ require_relative 'test_collector'
1
3
  require_relative 'multi_scan_manager/device_manager'
2
4
  require_relative 'multi_scan_manager/report_collator'
3
5
  require_relative 'multi_scan_manager/retrying_scan_helper'
@@ -17,16 +17,18 @@ module TestCenter
17
17
  end
18
18
  # :nocov:
19
19
 
20
- def prepare_scan_config_for_destination
20
+ def prepare_scan_config
21
21
  # this allows multi_scan's `destination` option to be picked up by `scan`
22
22
  scan_config._values.delete(:device)
23
23
  ENV.delete('SCAN_DEVICE')
24
24
  scan_config._values.delete(:devices)
25
25
  ENV.delete('SCAN_DEVICES')
26
+ # this prevents double -resultBundlePath args to xcodebuild
26
27
  if ReportNameHelper.includes_xcresult?(@options[:output_types])
27
28
  scan_config._values.delete(:result_bundle)
28
29
  ENV.delete('SCAN_RESULT_BUNDLE')
29
30
  end
31
+ scan_config._values.delete(:skip_testing)
30
32
  scan_cache.clear
31
33
  end
32
34
 
@@ -35,8 +37,9 @@ module TestCenter
35
37
  scan_options = @options.select { |k,v| valid_scan_keys.include?(k) }
36
38
  .merge(@retrying_scan_helper.scan_options)
37
39
 
38
- prepare_scan_config_for_destination
40
+ prepare_scan_config
39
41
  scan_options[:build_for_testing] = false
42
+ scan_options.delete(:skip_testing)
40
43
  FastlaneCore::UI.verbose("retrying_scan #update_scan_options")
41
44
  scan_options.each do |k,v|
42
45
  next if v.nil?
@@ -45,7 +45,7 @@ module TestCenter
45
45
 
46
46
  derived_data_path = File.expand_path(@options[:derived_data_path] || Scan.config[:derived_data_path])
47
47
  xcresults = Dir.glob("#{derived_data_path}/Logs/Test/*.xcresult")
48
- if FastlaneCore::Helper.xcode_at_least?('11.0.0')
48
+ if FastlaneCore::Helper.xcode_at_least?('11')
49
49
  xcresults += Dir.glob("#{output_directory}/*.xcresult")
50
50
  end
51
51
  FastlaneCore::UI.verbose("Deleting xcresults:")
@@ -93,6 +93,10 @@ module TestCenter
93
93
  FastlaneCore::UI.important(":xcargs, #{xcargs}, contained 'build-for-testing', removing it")
94
94
  xcargs.slice!('build-for-testing')
95
95
  end
96
+ if xcargs.include?('-quiet')
97
+ FastlaneCore::UI.important('Disabling -quiet as failing tests cannot be found with it enabled.')
98
+ xcargs.gsub!('-quiet', '')
99
+ end
96
100
  xcargs.gsub!(/-parallel-testing-enabled(=|\s+)(YES|NO)/, '')
97
101
  retrying_scan_options = @reportnamer.scan_options.merge(
98
102
  {
@@ -245,7 +249,7 @@ module TestCenter
245
249
  junit: File.absolute_path(report_filepath)
246
250
  }
247
251
  )
248
- @options[:only_testing] = @options[:only_testing] - Fastlane::Actions::TestsFromJunitAction.run(config).fetch(:passing, Hash.new).map(&:shellsafe_testidentifier)
252
+ @options[:only_testing] = (@options[:only_testing] || []) - Fastlane::Actions::TestsFromJunitAction.run(config).fetch(:passing, Hash.new).map(&:shellsafe_testidentifier)
249
253
  if @options[:invocation_based_tests]
250
254
  @options[:only_testing] = @options[:only_testing].map(&:strip_testcase).uniq
251
255
  end
@@ -288,6 +292,27 @@ module TestCenter
288
292
  end
289
293
 
290
294
  def retrieve_test_operation_failure(test_session_last_messages)
295
+ if FastlaneCore::Helper.xcode_at_least?('11')
296
+ retrieve_test_operation_failure_post_xcode11(test_session_last_messages)
297
+ else
298
+ retrieve_test_operation_failure_pre_xcode11(test_session_last_messages)
299
+ end
300
+ end
301
+
302
+ def retrieve_test_operation_failure_post_xcode11(test_session_last_messages)
303
+ if /Connection peer refused channel request/ =~ test_session_last_messages
304
+ test_operation_failure = 'Lost connection to testmanagerd'
305
+ elsif /Please unlock your device and reattach/ =~ test_session_last_messages
306
+ test_operation_failure = 'Test device locked'
307
+ elsif /Test runner exited before starting test execution/ =~ test_session_last_messages
308
+ test_operation_failure = 'Test runner exited before starting test execution'
309
+ else
310
+ test_operation_failure = 'Unknown test operation failure'
311
+ end
312
+ test_operation_failure
313
+ end
314
+
315
+ def retrieve_test_operation_failure_pre_xcode11(test_session_last_messages)
291
316
  test_operation_failure_match = /Test operation failure: (?<test_operation_failure>.*)$/ =~ test_session_last_messages
292
317
  if test_operation_failure_match.nil?
293
318
  test_operation_failure = 'Unknown test operation failure'
@@ -323,15 +348,17 @@ module TestCenter
323
348
  def move_test_result_bundle_for_next_run
324
349
  return unless @options[:result_bundle]
325
350
 
326
- glob_pattern = "#{output_directory}/*.test_result"
351
+ result_extension = FastlaneCore::Helper.xcode_at_least?('11') ? '.xcresult' : '.test_result'
352
+
353
+ glob_pattern = "#{output_directory}/*#{result_extension}"
327
354
  preexisting_test_result_bundles = Dir.glob(glob_pattern)
328
355
  unnumbered_test_result_bundles = preexisting_test_result_bundles.reject do |test_result|
329
- test_result =~ /.*-\d+\.test_result/
356
+ test_result =~ /.*-\d+\#{result_extension}/
330
357
  end
331
358
  src_test_bundle = unnumbered_test_result_bundles.first
332
359
  dst_test_bundle_parent_dir = File.dirname(src_test_bundle)
333
- dst_test_bundle_basename = File.basename(src_test_bundle, '.test_result')
334
- dst_test_bundle = "#{dst_test_bundle_parent_dir}/#{dst_test_bundle_basename}-#{@testrun_count}.test_result"
360
+ dst_test_bundle_basename = File.basename(src_test_bundle, result_extension)
361
+ dst_test_bundle = "#{dst_test_bundle_parent_dir}/#{dst_test_bundle_basename}-#{@testrun_count}#{result_extension}"
335
362
  FastlaneCore::UI.verbose("Moving test_result '#{src_test_bundle}' to '#{dst_test_bundle}'")
336
363
  File.rename(src_test_bundle, dst_test_bundle)
337
364
  end
@@ -1,4 +1,3 @@
1
-
2
1
  module TestCenter
3
2
  module Helper
4
3
  module MultiScanManager
@@ -7,7 +6,7 @@ module TestCenter
7
6
  require 'json'
8
7
  require 'shellwords'
9
8
  require 'snapshot/reset_simulators'
10
-
9
+
11
10
  class Runner
12
11
  attr_reader :retry_total_count
13
12
 
@@ -40,7 +39,8 @@ module TestCenter
40
39
  return if @options[:invocation_based_tests] && @options[:only_testing].nil?
41
40
  return if @test_collector
42
41
 
43
- @test_collector = TestCenter::Helper::TestCollector.new(@options)
42
+ @test_collector = TestCollector.new(@options)
43
+ @options.reject! { |key| %i[testplan].include?(key) }
44
44
  @batch_count = @test_collector.test_batches.size
45
45
  end
46
46
 
@@ -66,12 +66,12 @@ module TestCenter
66
66
  end
67
67
 
68
68
  unless tests_passed || @options[:try_count] < 1
69
- setup_testcollector
69
+ setup_testcollector
70
70
  tests_passed = run_test_batches
71
71
  end
72
72
  tests_passed
73
73
  end
74
-
74
+
75
75
  def should_run_tests_through_single_try?
76
76
  should_run_for_invocation_tests = @options[:invocation_based_tests] && @options[:only_testing].nil?
77
77
  should_run_for_skip_build = @options[:skip_build]
@@ -114,16 +114,16 @@ module TestCenter
114
114
  end
115
115
  @options[:output_directory] = output_directory
116
116
  @options[:destination] = Scan.config[:destination]
117
-
117
+
118
118
  # We do not want Scan.config to _not_ have :device :devices, we want to
119
119
  # use :destination. We remove :force_quit_simulator as we do not want
120
120
  # Scan to handle it as multi_scan takes care of it in its own way
121
121
  options = @options.reject { |key| %i[device devices force_quit_simulator].include?(key) }
122
122
  options[:try_count] = 1
123
-
123
+
124
124
  tests_passed = RetryingScan.run(options)
125
125
  @options[:try_count] -= 1
126
-
126
+
127
127
  reportnamer = ReportNameHelper.new(
128
128
  @options[:output_types],
129
129
  @options[:output_files],
@@ -138,12 +138,12 @@ module TestCenter
138
138
  )
139
139
  @options[:only_testing] = retrieve_failed_single_try_tests
140
140
  @options[:only_testing] = @options[:only_testing].map(&:strip_testcase).uniq
141
-
141
+
142
142
  symlink_result_bundle_to_xcresult(output_directory, reportnamer)
143
143
 
144
144
  tests_passed
145
145
  end
146
-
146
+
147
147
  def retrieve_failed_single_try_tests
148
148
  reportnamer = ReportNameHelper.new(
149
149
  @options[:output_types],
@@ -168,10 +168,10 @@ module TestCenter
168
168
 
169
169
  pool = TestBatchWorkerPool.new(pool_options)
170
170
  pool.setup_workers
171
-
171
+
172
172
  remaining_test_batches = @test_collector.test_batches.clone
173
173
  remaining_test_batches.each_with_index do |test_batch, current_batch_index|
174
- worker = pool.wait_for_worker
174
+ worker = pool.wait_for_worker
175
175
  FastlaneCore::UI.message("Starting test run #{current_batch_index + 1}")
176
176
  worker.run(scan_options_for_worker(test_batch, current_batch_index))
177
177
  end
@@ -189,7 +189,7 @@ module TestCenter
189
189
  batch: batch_index + 1
190
190
  }
191
191
  end
192
-
192
+
193
193
  def collate_batched_reports
194
194
  return unless @batch_count > 1
195
195
  return unless @options[:collate_reports]
@@ -207,10 +207,44 @@ module TestCenter
207
207
  File.absolute_path(output_directory),
208
208
  @test_collector.testables.first
209
209
  )
210
+ merge_single_testable_xcresult_with_final_xcresult(report_files_dir, File.absolute_path(output_directory))
210
211
  FileUtils.cp_r("#{report_files_dir}/.", File.absolute_path(output_directory))
211
212
  FileUtils.rm_rf(report_files_dir)
212
213
  end
213
214
 
215
+ def merge_single_testable_xcresult_with_final_xcresult(testable_output_dir, final_output_dir)
216
+ reportnamer = ReportNameHelper.new(
217
+ @options[:output_types],
218
+ @options[:output_files],
219
+ @options[:custom_report_file_name]
220
+ )
221
+ return unless reportnamer.includes_xcresult?
222
+
223
+ xcresult_bundlename = reportnamer.xcresult_bundlename
224
+ src_xcresult_bundlepath = File.join(testable_output_dir, xcresult_bundlename)
225
+ dst_xcresult_bundlepath = File.join(final_output_dir, xcresult_bundlename)
226
+
227
+ # We do not need to merge if one of these do not exist
228
+ return unless File.exist?(src_xcresult_bundlepath) || File.exist?(dst_xcresult_bundlepath)
229
+
230
+ config = FastlaneCore::Configuration.create(
231
+ Fastlane::Actions::CollateXcresultsAction.available_options,
232
+ {
233
+ xcresults: [src_xcresult_bundlepath, dst_xcresult_bundlepath],
234
+ collated_xcresult: dst_xcresult_bundlepath
235
+ }
236
+ )
237
+ FastlaneCore::UI.verbose("Merging xcresult '#{src_xcresult_bundlepath}' to '#{dst_xcresult_bundlepath}'")
238
+ Fastlane::Actions::CollateXcresultsAction.run(config)
239
+ FileUtils.rm_rf(src_xcresult_bundlepath)
240
+ if @result_bundle_desired
241
+ xcresult_bundlename = reportnamer.xcresult_bundlename
242
+ test_result_bundlename = File.basename(xcresult_bundlename, '.*') + '.test_result'
243
+ test_result_bundlename_path = File.join(testable_output_dir, test_result_bundlename)
244
+ FileUtils.rm_rf(test_result_bundlename_path)
245
+ end
246
+ end
247
+
214
248
  def symlink_result_bundle_to_xcresult(output_dir, reportname_helper)
215
249
  return unless @result_bundle_desired && reportname_helper.includes_xcresult?
216
250
 
@@ -15,7 +15,7 @@ module TestCenter
15
15
  unless @xctestrun_path && File.exist?(@xctestrun_path)
16
16
  FastlaneCore::UI.user_error!("Error: cannot find xctestrun file '#{@xctestrun_path}'")
17
17
  end
18
- @only_testing = options[:only_testing]
18
+ @only_testing = options[:only_testing] || only_testing_from_testplan(options)
19
19
  if @only_testing.kind_of?(String)
20
20
  @only_testing = @only_testing.split(',')
21
21
  end
@@ -27,6 +27,36 @@ module TestCenter
27
27
  end
28
28
  end
29
29
 
30
+ def only_testing_from_testplan(options)
31
+ return unless options[:testplan] && options[:scheme]
32
+
33
+ config = FastlaneCore::Configuration.create(
34
+ Fastlane::Actions::TestplansFromSchemeAction.available_options,
35
+ {
36
+ workspace: options[:workspace],
37
+ xcodeproj: options[:project],
38
+ scheme: options[:scheme]
39
+ }
40
+ )
41
+ testplans = Fastlane::Actions::TestplansFromSchemeAction.run(config)
42
+ FastlaneCore::UI.verbose("TestCollector found testplans: #{testplans}")
43
+ testplan = testplans.find do |testplan_path|
44
+ %r{(.*/?#{ options[:testplan] })\.xctestplan}.match?(testplan_path)
45
+ end
46
+ FastlaneCore::UI.verbose(" using :testplan option, #{options[:testplan]}, using found one: #{testplan}")
47
+
48
+ return if testplan.nil?
49
+
50
+ config = FastlaneCore::Configuration.create(
51
+ Fastlane::Actions::TestOptionsFromTestplanAction.available_options,
52
+ {
53
+ testplan: testplan
54
+ }
55
+ )
56
+ test_options = Fastlane::Actions::TestOptionsFromTestplanAction.run(config)
57
+ return test_options[:only_testing]
58
+ end
59
+
30
60
  def default_derived_data_path(options)
31
61
  project_derived_data_path = Scan.project.build_settings(key: "BUILT_PRODUCTS_DIR")
32
62
  File.expand_path("../../..", project_derived_data_path)
@@ -42,9 +72,7 @@ module TestCenter
42
72
  if @only_testing
43
73
  @testables ||= only_testing_to_testables_tests.keys
44
74
  else
45
- @testables ||= Plist.parse_xml(@xctestrun_path).keys.reject do |key|
46
- key == '__xctestrun_metadata__'
47
- end
75
+ @testables = xctestrun_known_tests.keys
48
76
  end
49
77
  end
50
78
  @testables
@@ -80,7 +108,7 @@ module TestCenter
80
108
  known_tests += xctestrun_known_tests[testable]
81
109
  test_components = test.split('/')
82
110
  testsuite = test_components.size == 1 ? test_components[0] : test_components[1]
83
- @testables_tests[testable][index] = known_tests.select { |known_test| known_test.include?(testsuite) }
111
+ @testables_tests[testable][index] = known_tests.select { |known_test| known_test.include?(testsuite) }
84
112
  end
85
113
  end
86
114
  @testables_tests[testable].flatten!
@@ -106,7 +134,7 @@ module TestCenter
106
134
  end
107
135
  end
108
136
  end
109
-
137
+
110
138
  @testables_tests
111
139
  end
112
140
 
@@ -1,5 +1,5 @@
1
1
  module Fastlane
2
2
  module TestCenter
3
- VERSION = "3.10.0"
3
+ VERSION = "3.11.1"
4
4
  end
5
5
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: fastlane-plugin-test_center
3
3
  version: !ruby/object:Gem::Version
4
- version: 3.10.0
4
+ version: 3.11.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Lyndsey Ferguson
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2020-03-26 00:00:00.000000000 Z
11
+ date: 2020-06-10 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: json
@@ -267,6 +267,8 @@ files:
267
267
  - lib/fastlane/plugin/test_center/actions/suppress_tests.rb
268
268
  - lib/fastlane/plugin/test_center/actions/suppress_tests_from_junit.rb
269
269
  - lib/fastlane/plugin/test_center/actions/suppressed_tests.rb
270
+ - lib/fastlane/plugin/test_center/actions/test_options_from_testplan.rb
271
+ - lib/fastlane/plugin/test_center/actions/testplans_from_scheme.rb
270
272
  - lib/fastlane/plugin/test_center/actions/tests_from_junit.rb
271
273
  - lib/fastlane/plugin/test_center/actions/tests_from_xctestrun.rb
272
274
  - lib/fastlane/plugin/test_center/helper/html_test_report.rb