fastlane 2.196.0 → 2.212.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (211) hide show
  1. checksums.yaml +4 -4
  2. data/LICENSE +1 -1
  3. data/README.md +88 -81
  4. data/cert/lib/cert/runner.rb +19 -8
  5. data/deliver/lib/assets/ScreenshotsHelp +29 -6
  6. data/deliver/lib/deliver/app_screenshot.rb +30 -4
  7. data/deliver/lib/deliver/app_screenshot_iterator.rb +1 -1
  8. data/deliver/lib/deliver/options.rb +6 -2
  9. data/deliver/lib/deliver/runner.rb +88 -24
  10. data/deliver/lib/deliver/submit_for_review.rb +25 -3
  11. data/deliver/lib/deliver/upload_price_tier.rb +3 -1
  12. data/deliver/lib/deliver/upload_screenshots.rb +2 -2
  13. data/fastlane/lib/assets/AppfileTemplate +1 -1
  14. data/fastlane/lib/assets/AppfileTemplate.swift +1 -1
  15. data/fastlane/lib/fastlane/actions/badge.rb +1 -1
  16. data/fastlane/lib/fastlane/actions/changelog_from_git_commits.rb +1 -1
  17. data/fastlane/lib/fastlane/actions/danger.rb +14 -0
  18. data/fastlane/lib/fastlane/actions/docs/build_app.md +5 -5
  19. data/fastlane/lib/fastlane/actions/docs/capture_android_screenshots.md +19 -2
  20. data/fastlane/lib/fastlane/actions/docs/frame_screenshots.md +1 -1
  21. data/fastlane/lib/fastlane/actions/docs/run_tests.md +1 -1
  22. data/fastlane/lib/fastlane/actions/docs/upload_to_app_store.md.erb +1 -1
  23. data/fastlane/lib/fastlane/actions/download_dsyms.rb +62 -46
  24. data/fastlane/lib/fastlane/actions/ensure_git_status_clean.rb +15 -4
  25. data/fastlane/lib/fastlane/actions/ensure_xcode_version.rb +1 -1
  26. data/fastlane/lib/fastlane/actions/get_push_certificate.rb +1 -1
  27. data/fastlane/lib/fastlane/actions/get_version_number.rb +8 -3
  28. data/fastlane/lib/fastlane/actions/git_commit.rb +4 -6
  29. data/fastlane/lib/fastlane/actions/import_certificate.rb +1 -1
  30. data/fastlane/lib/fastlane/actions/notarize.rb +29 -11
  31. data/fastlane/lib/fastlane/actions/pod_lib_lint.rb +1 -1
  32. data/fastlane/lib/fastlane/actions/pod_push.rb +19 -1
  33. data/fastlane/lib/fastlane/actions/read_podspec.rb +1 -1
  34. data/fastlane/lib/fastlane/actions/run_tests.rb +19 -9
  35. data/fastlane/lib/fastlane/actions/set_github_release.rb +11 -5
  36. data/fastlane/lib/fastlane/actions/setup_ci.rb +13 -4
  37. data/fastlane/lib/fastlane/actions/trainer.rb +49 -0
  38. data/fastlane/lib/fastlane/actions/update_code_signing_settings.rb +31 -4
  39. data/fastlane/lib/fastlane/actions/update_info_plist.rb +1 -1
  40. data/fastlane/lib/fastlane/actions/update_project_provisioning.rb +10 -1
  41. data/fastlane/lib/fastlane/actions/upload_symbols_to_sentry.rb +1 -1
  42. data/fastlane/lib/fastlane/actions/verify_build.rb +1 -1
  43. data/fastlane/lib/fastlane/actions/xcode_install.rb +5 -1
  44. data/fastlane/lib/fastlane/actions/xcode_select.rb +1 -1
  45. data/fastlane/lib/fastlane/actions/xcodebuild.rb +8 -2
  46. data/fastlane/lib/fastlane/actions/xcodes.rb +152 -0
  47. data/fastlane/lib/fastlane/actions/xcov.rb +5 -0
  48. data/fastlane/lib/fastlane/actions/xcversion.rb +17 -7
  49. data/fastlane/lib/fastlane/cli_tools_distributor.rb +5 -0
  50. data/fastlane/lib/fastlane/commands_generator.rb +2 -1
  51. data/fastlane/lib/fastlane/documentation/docs_generator.rb +17 -12
  52. data/fastlane/lib/fastlane/fast_file.rb +18 -5
  53. data/fastlane/lib/fastlane/features.rb +3 -0
  54. data/fastlane/lib/fastlane/helper/xcodebuild_formatter_helper.rb +9 -0
  55. data/fastlane/lib/fastlane/helper/xcodes_helper.rb +28 -0
  56. data/fastlane/lib/fastlane/helper/xcversion_helper.rb +0 -9
  57. data/fastlane/lib/fastlane/lane_manager.rb +1 -1
  58. data/fastlane/lib/fastlane/plugins/template/%gem_name%.gemspec.erb +1 -1
  59. data/fastlane/lib/fastlane/plugins/template/.rubocop.yml +5 -1
  60. data/fastlane/lib/fastlane/setup/setup_ios.rb +1 -1
  61. data/fastlane/lib/fastlane/swift_fastlane_api_generator.rb +1 -1
  62. data/fastlane/lib/fastlane/swift_lane_manager.rb +11 -3
  63. data/fastlane/lib/fastlane/swift_runner_upgrader.rb +54 -1
  64. data/fastlane/lib/fastlane/tools.rb +18 -1
  65. data/fastlane/lib/fastlane/version.rb +1 -1
  66. data/fastlane/swift/Actions.swift +1 -1
  67. data/fastlane/swift/Appfile.swift +2 -2
  68. data/fastlane/swift/ArgumentProcessor.swift +1 -1
  69. data/fastlane/swift/Atomic.swift +150 -0
  70. data/fastlane/swift/ControlCommand.swift +1 -1
  71. data/fastlane/swift/Deliverfile.swift +2 -2
  72. data/fastlane/swift/DeliverfileProtocol.swift +8 -4
  73. data/fastlane/swift/Fastlane.swift +570 -239
  74. data/fastlane/swift/FastlaneSwiftRunner/FastlaneSwiftRunner.xcodeproj/project.pbxproj +30 -20
  75. data/fastlane/swift/FastlaneSwiftRunner/FastlaneSwiftRunner.xcodeproj/xcshareddata/xcschemes/FastlaneRunner.xcscheme +1 -1
  76. data/fastlane/swift/Gymfile.swift +2 -2
  77. data/fastlane/swift/GymfileProtocol.swift +20 -8
  78. data/fastlane/swift/LaneFileProtocol.swift +2 -2
  79. data/fastlane/swift/MainProcess.swift +3 -3
  80. data/fastlane/swift/Matchfile.swift +2 -2
  81. data/fastlane/swift/MatchfileProtocol.swift +21 -5
  82. data/fastlane/swift/OptionalConfigValue.swift +1 -1
  83. data/fastlane/swift/Plugins.swift +1 -1
  84. data/fastlane/swift/Precheckfile.swift +2 -2
  85. data/fastlane/swift/PrecheckfileProtocol.swift +3 -3
  86. data/fastlane/swift/RubyCommand.swift +1 -1
  87. data/fastlane/swift/RubyCommandable.swift +1 -1
  88. data/fastlane/swift/Runner.swift +13 -9
  89. data/fastlane/swift/RunnerArgument.swift +1 -1
  90. data/fastlane/swift/Scanfile.swift +2 -2
  91. data/fastlane/swift/ScanfileProtocol.swift +31 -11
  92. data/fastlane/swift/Screengrabfile.swift +2 -2
  93. data/fastlane/swift/ScreengrabfileProtocol.swift +3 -3
  94. data/fastlane/swift/Snapshotfile.swift +2 -2
  95. data/fastlane/swift/SnapshotfileProtocol.swift +12 -8
  96. data/fastlane/swift/SocketClient.swift +9 -5
  97. data/fastlane/swift/SocketClientDelegateProtocol.swift +2 -2
  98. data/fastlane/swift/SocketResponse.swift +1 -1
  99. data/fastlane/swift/formatting/Brewfile.lock.json +46 -23
  100. data/fastlane/swift/main.swift +1 -1
  101. data/fastlane/swift/upgrade_manifest.json +1 -1
  102. data/fastlane_core/README.md +1 -0
  103. data/fastlane_core/lib/fastlane_core/cert_checker.rb +79 -17
  104. data/fastlane_core/lib/fastlane_core/device_manager.rb +5 -1
  105. data/fastlane_core/lib/fastlane_core/ipa_file_analyser.rb +10 -5
  106. data/fastlane_core/lib/fastlane_core/itunes_transporter.rb +409 -26
  107. data/fastlane_core/lib/fastlane_core/keychain_importer.rb +1 -0
  108. data/fastlane_core/lib/fastlane_core/project.rb +19 -2
  109. data/fastlane_core/lib/fastlane_core/ui/fastlane_runner.rb +7 -0
  110. data/fastlane_core/lib/fastlane_core/ui/implementations/shell.rb +4 -2
  111. data/frameit/lib/frameit/device.rb +1 -1
  112. data/frameit/lib/frameit/device_types.rb +9 -0
  113. data/frameit/lib/frameit/editor.rb +16 -18
  114. data/frameit/lib/frameit/frame_downloader.rb +1 -1
  115. data/frameit/lib/frameit/trim_box.rb +6 -0
  116. data/gym/lib/gym/generators/build_command_generator.rb +70 -23
  117. data/gym/lib/gym/options.rb +30 -5
  118. data/match/lib/match/change_password.rb +2 -0
  119. data/match/lib/match/commands_generator.rb +2 -1
  120. data/match/lib/match/encryption/openssl.rb +1 -1
  121. data/match/lib/match/encryption.rb +3 -0
  122. data/match/lib/match/generator.rb +1 -0
  123. data/match/lib/match/importer.rb +10 -1
  124. data/match/lib/match/migrate.rb +4 -3
  125. data/match/lib/match/module.rb +54 -2
  126. data/match/lib/match/nuke.rb +114 -47
  127. data/match/lib/match/options.rb +22 -1
  128. data/match/lib/match/runner.rb +25 -6
  129. data/match/lib/match/setup.rb +1 -1
  130. data/match/lib/match/spaceship_ensure.rb +5 -2
  131. data/match/lib/match/storage/gitlab/client.rb +102 -0
  132. data/match/lib/match/storage/gitlab/secure_file.rb +65 -0
  133. data/match/lib/match/storage/gitlab_secure_files.rb +182 -0
  134. data/match/lib/match/storage/google_cloud_storage.rb +7 -6
  135. data/match/lib/match/storage/s3_storage.rb +3 -3
  136. data/match/lib/match/storage.rb +4 -0
  137. data/match/lib/match/table_printer.rb +2 -1
  138. data/match/lib/match/utils.rb +15 -2
  139. data/pem/lib/pem/manager.rb +30 -7
  140. data/pem/lib/pem/options.rb +9 -0
  141. data/pilot/lib/pilot/build_manager.rb +34 -14
  142. data/pilot/lib/pilot/options.rb +6 -1
  143. data/scan/lib/scan/detect_values.rb +6 -0
  144. data/scan/lib/scan/error_handler.rb +9 -0
  145. data/scan/lib/scan/options.rb +49 -9
  146. data/scan/lib/scan/runner.rb +171 -25
  147. data/scan/lib/scan/test_command_generator.rb +65 -5
  148. data/sigh/lib/sigh/download_all.rb +14 -2
  149. data/sigh/lib/sigh/module.rb +3 -1
  150. data/sigh/lib/sigh/options.rb +5 -0
  151. data/sigh/lib/sigh/runner.rb +12 -2
  152. data/snapshot/lib/assets/SnapshotHelper.swift +3 -3
  153. data/snapshot/lib/snapshot/latest_os_version.rb +2 -5
  154. data/snapshot/lib/snapshot/options.rb +24 -8
  155. data/snapshot/lib/snapshot/reports_generator.rb +1 -0
  156. data/snapshot/lib/snapshot/simulator_launchers/simulator_launcher_base.rb +10 -3
  157. data/snapshot/lib/snapshot/test_command_generator.rb +37 -2
  158. data/spaceship/lib/spaceship/client.rb +71 -40
  159. data/spaceship/lib/spaceship/commands_generator.rb +1 -1
  160. data/spaceship/lib/spaceship/connect_api/api_client.rb +10 -5
  161. data/spaceship/lib/spaceship/connect_api/models/actor.rb +26 -0
  162. data/spaceship/lib/spaceship/connect_api/models/app.rb +52 -6
  163. data/spaceship/lib/spaceship/connect_api/models/app_info.rb +1 -0
  164. data/spaceship/lib/spaceship/connect_api/models/app_info_localization.rb +5 -0
  165. data/spaceship/lib/spaceship/connect_api/models/app_screenshot_set.rb +7 -0
  166. data/spaceship/lib/spaceship/connect_api/models/app_store_version.rb +1 -1
  167. data/spaceship/lib/spaceship/connect_api/models/app_store_version_localization.rb +27 -10
  168. data/spaceship/lib/spaceship/connect_api/models/build.rb +4 -2
  169. data/spaceship/lib/spaceship/connect_api/models/build_bundle.rb +68 -0
  170. data/spaceship/lib/spaceship/connect_api/models/build_bundle_file_sizes.rb +34 -0
  171. data/spaceship/lib/spaceship/connect_api/models/build_delivery.rb +2 -1
  172. data/spaceship/lib/spaceship/connect_api/models/certificate.rb +4 -0
  173. data/spaceship/lib/spaceship/connect_api/models/device.rb +47 -4
  174. data/spaceship/lib/spaceship/connect_api/models/profile.rb +4 -0
  175. data/spaceship/lib/spaceship/connect_api/models/resolution_center_message.rb +29 -0
  176. data/spaceship/lib/spaceship/connect_api/models/resolution_center_thread.rb +67 -0
  177. data/spaceship/lib/spaceship/connect_api/models/review_rejection.rb +19 -0
  178. data/spaceship/lib/spaceship/connect_api/models/review_submission.rb +86 -0
  179. data/spaceship/lib/spaceship/connect_api/models/review_submission_item.rb +40 -0
  180. data/spaceship/lib/spaceship/connect_api/models/user.rb +5 -0
  181. data/spaceship/lib/spaceship/connect_api/provisioning/provisioning.rb +19 -0
  182. data/spaceship/lib/spaceship/connect_api/response.rb +23 -6
  183. data/spaceship/lib/spaceship/connect_api/testflight/testflight.rb +33 -2
  184. data/spaceship/lib/spaceship/connect_api/token.rb +5 -2
  185. data/spaceship/lib/spaceship/connect_api/tunes/tunes.rb +124 -8
  186. data/spaceship/lib/spaceship/connect_api.rb +9 -0
  187. data/spaceship/lib/spaceship/errors.rb +34 -0
  188. data/spaceship/lib/spaceship/globals.rb +9 -0
  189. data/spaceship/lib/spaceship/hashcash.rb +52 -0
  190. data/spaceship/lib/spaceship/portal/certificate.rb +4 -3
  191. data/spaceship/lib/spaceship/spaceauth_runner.rb +1 -1
  192. data/spaceship/lib/spaceship/tunes/app_ratings.rb +6 -6
  193. data/spaceship/lib/spaceship/tunes/iap_families.rb +1 -1
  194. data/spaceship/lib/spaceship/tunes/tunes.rb +0 -1
  195. data/spaceship/lib/spaceship/tunes/tunes_client.rb +79 -21
  196. data/spaceship/lib/spaceship/two_step_or_factor_client.rb +11 -3
  197. data/spaceship/lib/spaceship.rb +1 -0
  198. data/supply/lib/supply/client.rb +2 -7
  199. data/supply/lib/supply/options.rb +8 -0
  200. data/supply/lib/supply/uploader.rb +6 -2
  201. data/trainer/lib/assets/junit.xml.erb +28 -0
  202. data/trainer/lib/trainer/commands_generator.rb +51 -0
  203. data/trainer/lib/trainer/junit_generator.rb +31 -0
  204. data/trainer/lib/trainer/module.rb +10 -0
  205. data/trainer/lib/trainer/options.rb +66 -0
  206. data/trainer/lib/trainer/test_parser.rb +398 -0
  207. data/trainer/lib/trainer/xcresult.rb +403 -0
  208. data/trainer/lib/trainer.rb +7 -0
  209. metadata +49 -24
  210. data/spaceship/lib/spaceship/connect_api/testflight/.testflight.rb.swp +0 -0
  211. data/spaceship/lib/spaceship/tunes/user_detail.rb +0 -15
@@ -1,4 +1,5 @@
1
1
  require 'fastlane_core/configuration/config_item'
2
+ require 'fastlane/helper/xcodebuild_formatter_helper'
2
3
  require 'credentials_manager/appfile_config'
3
4
  require_relative 'module'
4
5
 
@@ -60,7 +61,7 @@ module Scan
60
61
  optional: true,
61
62
  is_string: true,
62
63
  env_name: "SCAN_DEVICE",
63
- description: "The name of the simulator type you want to run tests on (e.g. 'iPhone 6')",
64
+ description: "The name of the simulator type you want to run tests on (e.g. 'iPhone 6' or 'iPhone SE (2nd generation) (14.5)')",
64
65
  conflicting_options: [:devices],
65
66
  conflict_block: proc do |value|
66
67
  UI.user_error!("You can't use 'device' and 'devices' options in one run")
@@ -70,7 +71,7 @@ module Scan
70
71
  is_string: false,
71
72
  env_name: "SCAN_DEVICES",
72
73
  type: Array,
73
- description: "Array of devices to run the tests on (e.g. ['iPhone 6', 'iPad Air'])",
74
+ description: "Array of devices to run the tests on (e.g. ['iPhone 6', 'iPad Air', 'iPhone SE (2nd generation) (14.5)'])",
74
75
  conflicting_options: [:device],
75
76
  conflict_block: proc do |value|
76
77
  UI.user_error!("You can't use 'device' and 'devices' options in one run")
@@ -214,11 +215,7 @@ module Scan
214
215
  description: "Should the HTML report be opened when tests are completed?",
215
216
  is_string: false,
216
217
  default_value: false),
217
- FastlaneCore::ConfigItem.new(key: :disable_xcpretty,
218
- env_name: "SCAN_DISABLE_XCPRETTY",
219
- description: "Disable xcpretty formatting of build, similar to `output_style='raw'` but this will also skip the test results table",
220
- type: Boolean,
221
- optional: true),
218
+
222
219
  FastlaneCore::ConfigItem.new(key: :output_directory,
223
220
  short_option: "-o",
224
221
  env_name: "SCAN_OUTPUT_DIRECTORY",
@@ -227,6 +224,7 @@ module Scan
227
224
  code_gen_default_value: "./test_output",
228
225
  default_value: File.join(containing, "test_output"),
229
226
  default_value_dynamic: true),
227
+
230
228
  FastlaneCore::ConfigItem.new(key: :output_style,
231
229
  short_option: "-b",
232
230
  env_name: "SCAN_OUTPUT_STYLE",
@@ -263,9 +261,35 @@ module Scan
263
261
  description: "Suppress the output of xcodebuild to stdout. Output is still saved in buildlog_path",
264
262
  optional: true,
265
263
  type: Boolean),
264
+
265
+ FastlaneCore::ConfigItem.new(key: :xcodebuild_formatter,
266
+ env_names: ["SCAN_XCODEBUILD_FORMATTER", "FASTLANE_XCODEBUILD_FORMATTER"],
267
+ description: "xcodebuild formatter to use (ex: 'xcbeautify', 'xcbeautify --quieter', 'xcpretty', 'xcpretty -test'). Use empty string (ex: '') to disable any formatter (More information: https://docs.fastlane.tools/best-practices/xcodebuild-formatters/)",
268
+ type: String,
269
+ default_value: Fastlane::Helper::XcodebuildFormatterHelper.xcbeautify_installed? ? 'xcbeautify' : 'xcpretty',
270
+ default_value_dynamic: true),
271
+ FastlaneCore::ConfigItem.new(key: :output_remove_retry_attempts,
272
+ env_name: "SCAN_OUTPUT_REMOVE_RETRY_ATTEMPS",
273
+ description: "Remove retry attempts from test results table and the JUnit report (if not using xcpretty)",
274
+ type: Boolean,
275
+ default_value: false),
276
+
277
+ # xcpretty
278
+ FastlaneCore::ConfigItem.new(key: :disable_xcpretty,
279
+ env_name: "SCAN_DISABLE_XCPRETTY",
280
+ deprecated: "Use `output_style: 'raw'` instead",
281
+ description: "Disable xcpretty formatting of build, similar to `output_style='raw'` but this will also skip the test results table",
282
+ type: Boolean,
283
+ optional: true),
266
284
  FastlaneCore::ConfigItem.new(key: :formatter,
267
285
  short_option: "-n",
268
286
  env_name: "SCAN_FORMATTER",
287
+ deprecated: "Use 'xcpretty_formatter' instead",
288
+ description: "A custom xcpretty formatter to use",
289
+ optional: true),
290
+ FastlaneCore::ConfigItem.new(key: :xcpretty_formatter,
291
+ short_option: "-N",
292
+ env_name: "SCAN_XCPRETTY_FORMATTER",
269
293
  description: "A custom xcpretty formatter to use",
270
294
  optional: true),
271
295
  FastlaneCore::ConfigItem.new(key: :xcpretty_args,
@@ -273,6 +297,7 @@ module Scan
273
297
  description: "Pass in xcpretty additional command line arguments (e.g. '--test --no-color' or '--tap --no-utf')",
274
298
  type: String,
275
299
  optional: true),
300
+
276
301
  FastlaneCore::ConfigItem.new(key: :derived_data_path,
277
302
  short_option: "-j",
278
303
  env_name: "SCAN_DERIVED_DATA_PATH",
@@ -290,6 +315,11 @@ module Scan
290
315
  env_name: "SCAN_OUTPUT_XCTESTRUN",
291
316
  description: "Should provide additional copy of .xctestrun file (settings.xctestrun) and place in output path?",
292
317
  default_value: false),
318
+ FastlaneCore::ConfigItem.new(key: :result_bundle_path,
319
+ env_name: "SCAN_RESULT_BUNDLE_PATH",
320
+ description: "Custom path for the result bundle, overrides result_bundle",
321
+ type: String,
322
+ optional: true),
293
323
  FastlaneCore::ConfigItem.new(key: :result_bundle,
294
324
  short_option: "-z",
295
325
  env_name: "SCAN_RESULT_BUNDLE",
@@ -303,6 +333,11 @@ module Scan
303
333
  default_value: false),
304
334
 
305
335
  # concurrency
336
+ FastlaneCore::ConfigItem.new(key: :parallel_testing,
337
+ type: Boolean,
338
+ env_name: "SCAN_PARALLEL_TESTING",
339
+ description: "Optionally override the per-target setting in the scheme for running tests in parallel. Equivalent to -parallel-testing-enabled",
340
+ optional: true),
306
341
  FastlaneCore::ConfigItem.new(key: :concurrent_workers,
307
342
  type: Integer,
308
343
  env_name: "SCAN_CONCURRENT_WORKERS",
@@ -490,9 +525,14 @@ module Scan
490
525
  default_value: false),
491
526
  FastlaneCore::ConfigItem.new(key: :number_of_retries,
492
527
  env_name: 'SCAN_NUMBER_OF_RETRIES',
493
- description: "The number of times a test can fail before scan should stop retrying",
528
+ description: "The number of times a test can fail",
494
529
  type: Integer,
495
- default_value: 0)
530
+ default_value: 0),
531
+ FastlaneCore::ConfigItem.new(key: :fail_build,
532
+ env_name: "SCAN_FAIL_BUILD",
533
+ description: "Should this step stop the build if the tests fail? Set this to false if you're using trainer",
534
+ type: Boolean,
535
+ default_value: true)
496
536
 
497
537
  ]
498
538
  end
@@ -20,7 +20,8 @@ module Scan
20
20
  end
21
21
 
22
22
  def run
23
- handle_results(test_app)
23
+ @xcresults_before_run = find_xcresults_in_derived_data
24
+ return handle_results(test_app)
24
25
  end
25
26
 
26
27
  def test_app
@@ -51,11 +52,18 @@ module Scan
51
52
  end
52
53
  end
53
54
 
54
- execute(retries: Scan.config[:number_of_retries])
55
+ retries = Scan.config[:number_of_retries]
56
+ execute(retries: retries)
55
57
  end
56
58
 
57
59
  def execute(retries: 0)
58
- Scan.cache[:retry_attempt] = Scan.config[:number_of_retries] - retries
60
+ # Set retries to 0 if Xcode 13 because TestCommandGenerator will set '-retry-tests-on-failure -test-iterations'
61
+ if Helper.xcode_at_least?(13)
62
+ retries = 0
63
+ Scan.cache[:retry_attempt] = 0
64
+ else
65
+ Scan.cache[:retry_attempt] = Scan.config[:number_of_retries] - retries
66
+ end
59
67
 
60
68
  command = @test_command_generator.generate
61
69
 
@@ -99,7 +107,7 @@ module Scan
99
107
  tests = retryable_tests(error_output)
100
108
 
101
109
  if tests.empty?
102
- UI.crash!("Failed to find failed tests to retry (could not parse error output)")
110
+ UI.build_failure!("Failed to find failed tests to retry (could not parse error output)")
103
111
  end
104
112
 
105
113
  Scan.config[:only_testing] = tests
@@ -126,7 +134,7 @@ module Scan
126
134
 
127
135
  test_cases = suite.split(":\n").fetch(1, []).split("\n").each
128
136
  .select { |line| line.match?(/^\s+/) }
129
- .map { |line| line.strip.gsub(".", "/").gsub("()", "") }
137
+ .map { |line| line.strip.gsub(/[\s\.]/, "/").gsub(/[\-\[\]\(\)]/, "") }
130
138
  .map { |line| suite_name + "/" + line }
131
139
 
132
140
  retryable_tests += test_cases
@@ -135,47 +143,185 @@ module Scan
135
143
  return retryable_tests.uniq
136
144
  end
137
145
 
138
- def handle_results(tests_exit_status)
139
- if Scan.config[:disable_xcpretty]
140
- unless tests_exit_status == 0
141
- UI.test_failure!("Test execution failed. Exit status: #{tests_exit_status}")
146
+ def find_filename(type)
147
+ index = Scan.config[:output_types].split(',').index(type)
148
+ return nil if index.nil?
149
+ return (Scan.config[:output_files] || "").split(',')[index]
150
+ end
151
+
152
+ def output_html?
153
+ return Scan.config[:output_types].split(',').include?('html')
154
+ end
155
+
156
+ def output_junit?
157
+ return Scan.config[:output_types].split(',').include?('junit')
158
+ end
159
+
160
+ def output_json_compilation_database?
161
+ return Scan.config[:output_types].split(',').include?('json-compilation-database')
162
+ end
163
+
164
+ def output_html_filename
165
+ return find_filename('html')
166
+ end
167
+
168
+ def output_junit_filename
169
+ return find_filename('junit')
170
+ end
171
+
172
+ def output_json_compilation_database_filename
173
+ return find_filename('json-compilation-database')
174
+ end
175
+
176
+ def find_xcresults_in_derived_data
177
+ derived_data_path = Scan.config[:derived_data_path]
178
+ return [] if derived_data_path.nil? # Swift packages might not have derived data
179
+
180
+ xcresults_path = File.join(derived_data_path, "Logs", "Test", "*.xcresult")
181
+ return Dir[xcresults_path]
182
+ end
183
+
184
+ def trainer_test_results
185
+ require "trainer"
186
+
187
+ results = {
188
+ number_of_tests: 0,
189
+ number_of_failures: 0,
190
+ number_of_retries: 0,
191
+ number_of_skipped: 0,
192
+ number_of_tests_excluding_retries: 0,
193
+ number_of_failures_excluding_retries: 0
194
+ }
195
+
196
+ result_bundle_path = Scan.cache[:result_bundle_path]
197
+
198
+ # Looks for xcresult file in derived data if not specifically set
199
+ if result_bundle_path.nil?
200
+ xcresults = find_xcresults_in_derived_data
201
+ new_xcresults = xcresults - @xcresults_before_run
202
+
203
+ if new_xcresults.size != 1
204
+ UI.build_failure!("Cannot find .xcresult in derived data which is needed to determine test results. This is an issue within scan. File an issue on GitHub or try setting option `result_bundle: true`")
142
205
  end
143
- return
206
+
207
+ result_bundle_path = new_xcresults.first
208
+ Scan.cache[:result_bundle_path] = result_bundle_path
144
209
  end
145
210
 
146
- result = TestResultParser.new.parse_result(test_results)
147
- SlackPoster.new.run(result)
211
+ output_path = Scan.config[:output_directory] || Dir.mktmpdir
212
+ output_path = File.absolute_path(output_path)
148
213
 
149
- if result[:failures] > 0
150
- failures_str = result[:failures].to_s.red
214
+ UI.build_failure!("A -resultBundlePath is needed to parse the test results. This should not have happened. Please file an issue.") unless result_bundle_path
215
+
216
+ params = {
217
+ path: result_bundle_path,
218
+ output_remove_retry_attempts: Scan.config[:output_remove_retry_attempts],
219
+ silent: !FastlaneCore::Globals.verbose?
220
+ }
221
+
222
+ formatter = Scan.config[:xcodebuild_formatter].chomp
223
+ show_output_types_tip = false
224
+ if output_html? && formatter != 'xcpretty'
225
+ UI.important("Skipping HTML... only available with `xcodebuild_formatter: 'xcpretty'` right now")
226
+ show_output_types_tip = true
227
+ end
228
+
229
+ if output_json_compilation_database? && formatter != 'xcpretty'
230
+ UI.important("Skipping JSON Compilation Database... only available with `xcodebuild_formatter: 'xcpretty'` right now")
231
+ show_output_types_tip = true
232
+ end
233
+
234
+ if show_output_types_tip
235
+ UI.important("Your 'xcodebuild_formatter' doesn't support these 'output_types'. Change your 'output_types' to prevent these warnings from showing...")
236
+ end
237
+
238
+ if output_junit?
239
+ if formatter == 'xcpretty'
240
+ UI.verbose("Generating junit report with xcpretty")
241
+ else
242
+ UI.verbose("Generating junit report with trainer")
243
+ params[:output_filename] = output_junit_filename || "report.junit"
244
+ params[:output_directory] = output_path
245
+ end
246
+ end
247
+
248
+ resulting_paths = Trainer::TestParser.auto_convert(params)
249
+ resulting_paths.each do |path, data|
250
+ results[:number_of_tests] += data[:number_of_tests]
251
+ results[:number_of_failures] += data[:number_of_failures]
252
+ results[:number_of_tests_excluding_retries] += data[:number_of_tests_excluding_retries]
253
+ results[:number_of_failures_excluding_retries] += data[:number_of_failures_excluding_retries]
254
+ results[:number_of_skipped] += data[:number_of_skipped] || 0
255
+ results[:number_of_retries] += data[:number_of_retries]
256
+ end
257
+
258
+ return results
259
+ end
260
+
261
+ def handle_results(tests_exit_status)
262
+ copy_simulator_logs
263
+ zip_build_products
264
+ copy_xctestrun
265
+
266
+ return nil if Scan.config[:build_for_testing]
267
+
268
+ results = trainer_test_results
269
+
270
+ number_of_retries = results[:number_of_retries]
271
+ number_of_skipped = results[:number_of_skipped]
272
+ number_of_tests = results[:number_of_tests_excluding_retries]
273
+ number_of_failures = results[:number_of_failures_excluding_retries]
274
+
275
+ SlackPoster.new.run({
276
+ tests: number_of_tests,
277
+ failures: number_of_failures
278
+ })
279
+
280
+ if number_of_failures > 0
281
+ failures_str = number_of_failures.to_s.red
151
282
  else
152
- failures_str = result[:failures].to_s.green
283
+ failures_str = number_of_failures.to_s.green
153
284
  end
154
285
 
286
+ retries_str = case number_of_retries
287
+ when 0
288
+ ""
289
+ when 1
290
+ " (and 1 retry)"
291
+ else
292
+ " (and #{number_of_retries} retries)"
293
+ end
294
+
155
295
  puts(Terminal::Table.new({
156
296
  title: "Test Results",
157
297
  rows: [
158
- ["Number of tests", result[:tests]],
298
+ ["Number of tests", "#{number_of_tests}#{retries_str}"],
299
+ number_of_skipped > 0 ? ["Number of tests skipped", number_of_skipped] : nil,
159
300
  ["Number of failures", failures_str]
160
- ]
301
+ ].compact
161
302
  }))
162
303
  puts("")
163
304
 
164
- copy_simulator_logs
165
- zip_build_products
166
- copy_xctestrun
167
-
168
- if result[:failures] > 0
305
+ if number_of_failures > 0
169
306
  open_report
170
307
 
171
- UI.test_failure!("Tests have failed")
308
+ if Scan.config[:fail_build]
309
+ UI.test_failure!("Tests have failed")
310
+ else
311
+ UI.error("Tests have failed")
312
+ end
172
313
  end
173
314
 
174
315
  unless tests_exit_status == 0
175
- UI.test_failure!("Test execution failed. Exit status: #{tests_exit_status}")
316
+ if Scan.config[:fail_build]
317
+ UI.test_failure!("Test execution failed. Exit status: #{tests_exit_status}")
318
+ else
319
+ UI.error("Test execution failed. Exit status: #{tests_exit_status}")
320
+ end
176
321
  end
177
322
 
178
323
  open_report
324
+ return results
179
325
  end
180
326
 
181
327
  def open_report
@@ -226,7 +372,7 @@ module Scan
226
372
  FileUtils.cp(xctestrun_file, output_path)
227
373
  UI.message("Successfully copied xctestrun file: #{output_path}")
228
374
  else
229
- UI.user_error!("Could not find .xctextrun file to copy")
375
+ UI.user_error!("Could not find .xctestrun file to copy")
230
376
  end
231
377
  end
232
378
 
@@ -53,8 +53,14 @@ module Scan
53
53
  if config[:use_system_scm] && !options.include?("-scmProvider system")
54
54
  options << "-scmProvider system"
55
55
  end
56
- options << "-resultBundlePath '#{result_bundle_path}'" if config[:result_bundle]
56
+ if config[:result_bundle_path]
57
+ options << "-resultBundlePath '#{config[:result_bundle_path].shellescape}'"
58
+ Scan.cache[:result_bundle_path] = config[:result_bundle_path]
59
+ elsif config[:result_bundle]
60
+ options << "-resultBundlePath '#{result_bundle_path(true)}'"
61
+ end
57
62
  if FastlaneCore::Helper.xcode_at_least?(10)
63
+ options << "-parallel-testing-enabled #{config[:parallel_testing] ? 'YES' : 'NO'}" unless config[:parallel_testing].nil?
58
64
  options << "-parallel-testing-worker-count #{config[:concurrent_workers]}" if config[:concurrent_workers]
59
65
  options << "-maximum-concurrent-test-simulator-destinations #{config[:max_concurrent_simulators]}" if config[:max_concurrent_simulators]
60
66
  options << "-disable-concurrent-testing" if config[:disable_concurrent_testing]
@@ -73,6 +79,14 @@ module Scan
73
79
  options << "-xctestrun '#{config[:xctestrun]}'" if config[:xctestrun]
74
80
  options << config[:xcargs] if config[:xcargs]
75
81
 
82
+ # Number of retries does not equal xcodebuild's -test-iterations number
83
+ # It needs include 1 iteration by default
84
+ number_of_retries = config[:number_of_retries] + 1
85
+ if number_of_retries > 1 && FastlaneCore::Helper.xcode_at_least?(13)
86
+ options << "-retry-tests-on-failure"
87
+ options << "-test-iterations #{number_of_retries}"
88
+ end
89
+
76
90
  # detect_values will ensure that these values are present as Arrays if
77
91
  # they are present at all
78
92
  options += config[:only_testing].map { |test_id| "-only-testing:#{test_id.shellescape}" } if config[:only_testing]
@@ -107,12 +121,56 @@ module Scan
107
121
  def pipe
108
122
  pipe = ["| tee '#{xcodebuild_log_path}'"]
109
123
 
124
+ # disable_xcpretty is now deprecated and directs to use output_style of raw
110
125
  if Scan.config[:disable_xcpretty] || Scan.config[:output_style] == 'raw'
111
126
  return pipe
112
127
  end
113
128
 
129
+ formatter = Scan.config[:xcodebuild_formatter].chomp
130
+ options = legacy_xcpretty_options
131
+
132
+ if formatter == ''
133
+ UI.verbose("Not using an xcodebuild formatter")
134
+ elsif !options.empty?
135
+ UI.important("Detected legacy xcpretty being used so formatting wth xcpretty")
136
+ UI.important("Option(s) used: #{options.join(', ')}")
137
+ pipe << pipe_xcpretty
138
+ elsif formatter == 'xcpretty'
139
+ pipe << pipe_xcpretty
140
+ elsif formatter == 'xcbeautify'
141
+ pipe << pipe_xcbeautify
142
+ else
143
+ pipe << "| #{formatter}"
144
+ end
145
+
146
+ return pipe
147
+ end
148
+
149
+ def pipe_xcbeautify
150
+ formatter = ['| xcbeautify']
151
+
152
+ if FastlaneCore::Helper.colors_disabled?
153
+ formatter << '--disable-colored-output'
154
+ end
155
+
156
+ return formatter.join(' ')
157
+ end
158
+
159
+ def legacy_xcpretty_options
160
+ options = []
161
+
162
+ options << "formatter" if Scan.config[:formatter]
163
+ options << "xcpretty_formatter" if Scan.config[:xcpretty_formatter]
164
+ options << "output_style" if Scan.config[:output_style]
165
+ options << "output_types" if (Scan.config[:output_types] || "").include?("json-compilation-database")
166
+ options << "custom_report_file_name" if Scan.config[:custom_report_file_name]
167
+
168
+ return options
169
+ end
170
+
171
+ def pipe_xcpretty
114
172
  formatter = []
115
- if (custom_formatter = Scan.config[:formatter])
173
+ if (custom_formatter = Scan.config[:xcpretty_formatter] || Scan.config[:formatter])
116
174
  if custom_formatter.end_with?(".rb")
117
175
  formatter << "-f '#{custom_formatter}'"
118
176
  else
@@ -143,7 +201,7 @@ module Scan
143
201
  Scan.config[:xcpretty_args])
144
202
  reporter_options = @reporter_options_generator.generate_reporter_options
145
203
  reporter_xcpretty_args = @reporter_options_generator.generate_xcpretty_args_options
146
- return pipe << "| xcpretty #{formatter.join(' ')} #{reporter_options.join(' ')} #{reporter_xcpretty_args}"
204
+ return "| xcpretty #{formatter.join(' ')} #{reporter_options.join(' ')} #{reporter_xcpretty_args}"
147
205
  end
148
206
 
149
207
  # Store the raw file
@@ -183,11 +241,13 @@ module Scan
183
241
  end
184
242
 
185
243
  # The path to the result bundle
186
- def result_bundle_path
244
+ def result_bundle_path(use_output_directory)
245
+ root_dir = use_output_directory ? Scan.config[:output_directory] : Dir.mktmpdir
246
+
187
247
  retry_count = Scan.cache[:retry_attempt] || 0
188
248
  attempt = retry_count > 0 ? "-#{retry_count}" : ""
189
249
  ext = FastlaneCore::Helper.xcode_version.to_i >= 11 ? '.xcresult' : '.test_result'
190
- path = File.join(Scan.config[:output_directory], Scan.config[:scheme]) + attempt + ext
250
+ path = File.join([root_dir, Scan.config[:scheme]].compact) + attempt + ext
191
251
 
192
252
  Scan.cache[:result_bundle_path] = path
193
253
 
@@ -40,12 +40,26 @@ module Sigh
40
40
  Spaceship::ConnectAPI::Profile::ProfileType::MAC_APP_DEVELOPMENT,
41
41
  Spaceship::ConnectAPI::Profile::ProfileType::MAC_APP_DIRECT
42
42
  ]
43
+
44
+ # As of 2022-06-25, only available with Apple ID auth
45
+ if Spaceship::ConnectAPI.token
46
+ UI.important("Skipping #{Spaceship::ConnectAPI::Profile::ProfileType::MAC_APP_INHOUSE}... only available with Apple ID auth")
47
+ else
48
+ profile_types << Spaceship::ConnectAPI::Profile::ProfileType::MAC_APP_INHOUSE
49
+ end
43
50
  when 'catalyst'
44
51
  profile_types = [
45
52
  Spaceship::ConnectAPI::Profile::ProfileType::MAC_CATALYST_APP_STORE,
46
53
  Spaceship::ConnectAPI::Profile::ProfileType::MAC_CATALYST_APP_DEVELOPMENT,
47
54
  Spaceship::ConnectAPI::Profile::ProfileType::MAC_CATALYST_APP_DIRECT
48
55
  ]
56
+
57
+ # As of 2022-06-25, only available with Apple ID auth
58
+ if Spaceship::ConnectAPI.token
59
+ UI.important("Skipping #{Spaceship::ConnectAPI::Profile::ProfileType::MAC_CATALYST_APP_INHOUSE}... only available with Apple ID auth")
60
+ else
61
+ profile_types << Spaceship::ConnectAPI::Profile::ProfileType::MAC_CATALYST_APP_INHOUSE
62
+ end
49
63
  when 'tvos'
50
64
  profile_types = [
51
65
  Spaceship::ConnectAPI::Profile::ProfileType::TVOS_APP_STORE,
@@ -55,8 +69,6 @@ module Sigh
55
69
  ]
56
70
  end
57
71
 
58
- # Filtering on 'profileType' seems to be undocumented as of 2020-07-30
59
- # but works on both web session and official API
60
72
  profiles = Spaceship::ConnectAPI::Profile.all(filter: { profileType: profile_types.join(",") }, includes: "bundleId")
61
73
  download_profiles(profiles)
62
74
  end
@@ -24,7 +24,9 @@ module Sigh
24
24
  Spaceship::ConnectAPI::Profile::ProfileType::TVOS_APP_ADHOC
25
25
  "AdHoc"
26
26
  when Spaceship::ConnectAPI::Profile::ProfileType::IOS_APP_INHOUSE,
27
- Spaceship::ConnectAPI::Profile::ProfileType::TVOS_APP_INHOUSE
27
+ Spaceship::ConnectAPI::Profile::ProfileType::TVOS_APP_INHOUSE,
28
+ Spaceship::ConnectAPI::Profile::ProfileType::MAC_APP_INHOUSE,
29
+ Spaceship::ConnectAPI::Profile::ProfileType::MAC_CATALYST_APP_INHOUSE
28
30
  "InHouse"
29
31
  when Spaceship::ConnectAPI::Profile::ProfileType::MAC_APP_DIRECT,
30
32
  Spaceship::ConnectAPI::Profile::ProfileType::MAC_CATALYST_APP_DIRECT
@@ -47,6 +47,11 @@ module Sigh
47
47
  is_string: false,
48
48
  short_option: "-f",
49
49
  default_value: false),
50
+ FastlaneCore::ConfigItem.new(key: :include_mac_in_profiles,
51
+ env_name: "SIGH_INCLUDE_MAC_IN_PROFILES",
52
+ description: "Include Apple Silicon Mac devices in provisioning profiles for iOS/iPadOS apps",
53
+ is_string: false,
54
+ default_value: false),
50
55
  FastlaneCore::ConfigItem.new(key: :app_identifier,
51
56
  short_option: "-a",
52
57
  env_name: "SIGH_APP_IDENTIFIER",
@@ -82,10 +82,12 @@ module Sigh
82
82
  @profile_type = Spaceship::ConnectAPI::Profile::ProfileType::TVOS_APP_DEVELOPMENT if Sigh.config[:development]
83
83
  when "macos"
84
84
  @profile_type = Spaceship::ConnectAPI::Profile::ProfileType::MAC_APP_STORE
85
+ @profile_type = Spaceship::ConnectAPI::Profile::ProfileType::MAC_APP_INHOUSE if Spaceship::ConnectAPI.client.in_house?
85
86
  @profile_type = Spaceship::ConnectAPI::Profile::ProfileType::MAC_APP_DEVELOPMENT if Sigh.config[:development]
86
87
  @profile_type = Spaceship::ConnectAPI::Profile::ProfileType::MAC_APP_DIRECT if Sigh.config[:developer_id]
87
88
  when "catalyst"
88
89
  @profile_type = Spaceship::ConnectAPI::Profile::ProfileType::MAC_CATALYST_APP_STORE
90
+ @profile_type = Spaceship::ConnectAPI::Profile::ProfileType::MAC_CATALYST_APP_INHOUSE if Spaceship::ConnectAPI.client.in_house?
89
91
  @profile_type = Spaceship::ConnectAPI::Profile::ProfileType::MAC_CATALYST_APP_DEVELOPMENT if Sigh.config[:development]
90
92
  @profile_type = Spaceship::ConnectAPI::Profile::ProfileType::MAC_CATALYST_APP_DIRECT if Sigh.config[:developer_id]
91
93
  end
@@ -251,7 +253,13 @@ module Sigh
251
253
  ]
252
254
  elsif profile_type == Spaceship::ConnectAPI::Profile::ProfileType::MAC_APP_DIRECT || profile_type == Spaceship::ConnectAPI::Profile::ProfileType::MAC_CATALYST_APP_DIRECT
253
255
  types = [
254
- Spaceship::ConnectAPI::Certificate::CertificateType::DEVELOPER_ID_APPLICATION
256
+ Spaceship::ConnectAPI::Certificate::CertificateType::DEVELOPER_ID_APPLICATION,
257
+ Spaceship::ConnectAPI::Certificate::CertificateType::DEVELOPER_ID_APPLICATION_G2
258
+ ]
259
+ elsif profile_type == Spaceship::ConnectAPI::Profile::ProfileType::MAC_APP_INHOUSE || profile_type == Spaceship::ConnectAPI::Profile::ProfileType::MAC_CATALYST_APP_INHOUSE
260
+ # Enterprise accounts don't have access to Apple Distribution certificates
261
+ types = [
262
+ Spaceship::ConnectAPI::Certificate::CertificateType::MAC_APP_DISTRIBUTION
255
263
  ]
256
264
  else
257
265
  types = [
@@ -281,7 +289,9 @@ module Sigh
281
289
  when 'macos', 'catalyst'
282
290
  [Spaceship::ConnectAPI::Device::DeviceClass::MAC]
283
291
  end
284
-
292
+ if Sigh.config[:platform].to_s == 'ios' && Sigh.config[:include_mac_in_profiles]
293
+ device_classes += [Spaceship::ConnectAPI::Device::DeviceClass::APPLE_SILICON_MAC]
294
+ end
285
295
  if Spaceship::ConnectAPI.token
286
296
  return Spaceship::ConnectAPI::Device.all.select do |device|
287
297
  device_classes.include?(device.device_class)
@@ -165,7 +165,7 @@ open class Snapshot: NSObject {
165
165
  }
166
166
 
167
167
  let screenshot = XCUIScreen.main.screenshot()
168
- #if os(iOS)
168
+ #if os(iOS) && !targetEnvironment(macCatalyst)
169
169
  let image = XCUIDevice.shared.orientation.isLandscape ? fixLandscapeOrientation(image: screenshot.image) : screenshot.image
170
170
  #else
171
171
  let image = screenshot.image
@@ -181,7 +181,7 @@ open class Snapshot: NSObject {
181
181
 
182
182
  let path = screenshotsDir.appendingPathComponent("\(simulator)-\(name).png")
183
183
  #if swift(<5.0)
184
- UIImagePNGRepresentation(image)?.write(to: path, options: .atomic)
184
+ try UIImagePNGRepresentation(image)?.write(to: path, options: .atomic)
185
185
  #else
186
186
  try image.pngData()?.write(to: path, options: .atomic)
187
187
  #endif
@@ -306,4 +306,4 @@ private extension CGFloat {
306
306
 
307
307
  // Please don't remove the lines below
308
308
  // They are used to detect outdated configuration files
309
- // SnapshotHelperVersion [1.27]
309
+ // SnapshotHelperVersion [1.29]
@@ -16,12 +16,9 @@ module Snapshot
16
16
  def self.version_for_os(os)
17
17
  # We do all this, because we would get all kind of crap output generated by xcodebuild
18
18
  # so we need to ignore stderror
19
- output = ''
20
- Open3.popen3('xcodebuild -version -sdk') do |stdin, stdout, stderr, wait_thr|
21
- output = stdout.read
22
- end
19
+ stdout, _stderr, _status = Open3.capture3('xcodebuild -version -sdk')
23
20
 
24
- matched = output.match(/#{os} ([\d\.]+) \(.*/)
21
+ matched = stdout.match(/#{os} ([\d\.]+) \(.*/)
25
22
  if matched.nil?
26
23
  FastlaneCore::UI.user_error!("Could not determine installed #{os} SDK version. Try running the _xcodebuild_ command manually to ensure it works.")
27
24
  elsif matched.length > 1