fastlane 2.178.0 → 2.182.0

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.
Files changed (148) hide show
  1. checksums.yaml +4 -4
  2. data/LICENSE +1 -1
  3. data/README.md +97 -84
  4. data/cert/lib/cert/commands_generator.rb +2 -1
  5. data/cert/lib/cert/options.rb +1 -0
  6. data/cert/lib/cert/runner.rb +4 -0
  7. data/deliver/lib/deliver/commands_generator.rb +2 -1
  8. data/deliver/lib/deliver/download_screenshots.rb +1 -2
  9. data/deliver/lib/deliver/languages.rb +1 -1
  10. data/deliver/lib/deliver/options.rb +3 -2
  11. data/deliver/lib/deliver/runner.rb +4 -0
  12. data/deliver/lib/deliver/setup.rb +0 -1
  13. data/deliver/lib/deliver/upload_metadata.rb +2 -1
  14. data/fastlane/lib/fastlane/actions/actions_helper.rb +2 -2
  15. data/fastlane/lib/fastlane/actions/app_store_build_number.rb +5 -0
  16. data/fastlane/lib/fastlane/actions/app_store_connect_api_key.rb +3 -3
  17. data/fastlane/lib/fastlane/actions/backup_xcarchive.rb +1 -1
  18. data/fastlane/lib/fastlane/actions/build_app.rb +4 -0
  19. data/fastlane/lib/fastlane/actions/check_app_store_metadata.rb +4 -0
  20. data/fastlane/lib/fastlane/actions/clipboard.rb +3 -6
  21. data/fastlane/lib/fastlane/actions/docs/capture_ios_screenshots.md +1 -1
  22. data/fastlane/lib/fastlane/actions/docs/frame_screenshots.md +18 -1
  23. data/fastlane/lib/fastlane/actions/docs/upload_to_play_store.md +2 -1
  24. data/fastlane/lib/fastlane/actions/ensure_env_vars.rb +2 -6
  25. data/fastlane/lib/fastlane/actions/get_provisioning_profile.rb +4 -0
  26. data/fastlane/lib/fastlane/actions/get_version_number.rb +17 -10
  27. data/fastlane/lib/fastlane/actions/git_branch.rb +4 -10
  28. data/fastlane/lib/fastlane/actions/git_commit.rb +3 -1
  29. data/fastlane/lib/fastlane/actions/git_submodule_update.rb +16 -8
  30. data/fastlane/lib/fastlane/actions/git_tag_exists.rb +4 -0
  31. data/fastlane/lib/fastlane/actions/import_from_git.rb +5 -5
  32. data/fastlane/lib/fastlane/actions/install_provisioning_profile.rb +4 -0
  33. data/fastlane/lib/fastlane/actions/jira.rb +61 -14
  34. data/fastlane/lib/fastlane/actions/latest_testflight_build_number.rb +1 -0
  35. data/fastlane/lib/fastlane/actions/match_nuke.rb +59 -0
  36. data/fastlane/lib/fastlane/actions/notarize.rb +98 -51
  37. data/fastlane/lib/fastlane/actions/slack.rb +155 -133
  38. data/fastlane/lib/fastlane/actions/sourcedocs.rb +164 -0
  39. data/fastlane/lib/fastlane/actions/spaceship_logs.rb +1 -1
  40. data/fastlane/lib/fastlane/actions/update_project_provisioning.rb +1 -2
  41. data/fastlane/lib/fastlane/actions/upload_symbols_to_crashlytics.rb +4 -2
  42. data/fastlane/lib/fastlane/cli_tools_distributor.rb +1 -1
  43. data/fastlane/lib/fastlane/commands_generator.rb +2 -1
  44. data/fastlane/lib/fastlane/fast_file.rb +10 -2
  45. data/fastlane/lib/fastlane/fastlane_require.rb +7 -1
  46. data/fastlane/lib/fastlane/helper/git_helper.rb +19 -7
  47. data/fastlane/lib/fastlane/lane_manager.rb +3 -2
  48. data/fastlane/lib/fastlane/notification/slack.rb +56 -0
  49. data/fastlane/lib/fastlane/plugins/plugin_fetcher.rb +1 -2
  50. data/fastlane/lib/fastlane/plugins/plugin_info.rb +2 -2
  51. data/fastlane/lib/fastlane/plugins/plugin_info_collector.rb +1 -2
  52. data/fastlane/lib/fastlane/plugins/plugin_manager.rb +1 -2
  53. data/fastlane/lib/fastlane/plugins/template/%gem_name%.gemspec.erb +7 -6
  54. data/fastlane/lib/fastlane/plugins/template/.rubocop.yml +30 -35
  55. data/fastlane/lib/fastlane/plugins/template/spec/spec_helper.rb.erb +1 -1
  56. data/fastlane/lib/fastlane/setup/setup.rb +23 -10
  57. data/fastlane/lib/fastlane/swift_fastlane_function.rb +39 -14
  58. data/fastlane/lib/fastlane/swift_runner_upgrader.rb +2 -0
  59. data/fastlane/lib/fastlane/version.rb +2 -2
  60. data/fastlane/swift/Deliverfile.swift +1 -1
  61. data/fastlane/swift/DeliverfileProtocol.swift +3 -3
  62. data/fastlane/swift/Fastlane.swift +6852 -3824
  63. data/fastlane/swift/FastlaneSwiftRunner/FastlaneSwiftRunner.xcodeproj/project.pbxproj +4 -0
  64. data/fastlane/swift/Gymfile.swift +1 -1
  65. data/fastlane/swift/GymfileProtocol.swift +1 -1
  66. data/fastlane/swift/LaneFileProtocol.swift +9 -3
  67. data/fastlane/swift/Matchfile.swift +1 -1
  68. data/fastlane/swift/MatchfileProtocol.swift +1 -1
  69. data/fastlane/swift/OptionalConfigValue.swift +131 -0
  70. data/fastlane/swift/Precheckfile.swift +1 -1
  71. data/fastlane/swift/PrecheckfileProtocol.swift +3 -3
  72. data/fastlane/swift/RubyCommand.swift +1 -1
  73. data/fastlane/swift/Scanfile.swift +1 -1
  74. data/fastlane/swift/ScanfileProtocol.swift +5 -1
  75. data/fastlane/swift/Screengrabfile.swift +1 -1
  76. data/fastlane/swift/ScreengrabfileProtocol.swift +1 -1
  77. data/fastlane/swift/Snapshotfile.swift +1 -1
  78. data/fastlane/swift/SnapshotfileProtocol.swift +5 -1
  79. data/fastlane/swift/SocketClient.swift +2 -1
  80. data/fastlane/swift/SocketResponse.swift +4 -2
  81. data/fastlane/swift/formatting/Brewfile.lock.json +18 -16
  82. data/fastlane/swift/upgrade_manifest.json +1 -1
  83. data/fastlane_core/lib/fastlane_core.rb +22 -21
  84. data/fastlane_core/lib/fastlane_core/build_watcher.rb +50 -9
  85. data/fastlane_core/lib/fastlane_core/clipboard.rb +20 -0
  86. data/fastlane_core/lib/fastlane_core/configuration/configuration.rb +5 -3
  87. data/fastlane_core/lib/fastlane_core/helper.rb +28 -5
  88. data/fastlane_core/lib/fastlane_core/languages.rb +2 -2
  89. data/fastlane_core/lib/fastlane_core/queue_worker.rb +2 -2
  90. data/fastlane_core/lib/fastlane_core/swag.rb +1 -1
  91. data/fastlane_core/lib/fastlane_core/ui/help.erb +35 -0
  92. data/fastlane_core/lib/fastlane_core/ui/help_formatter.rb +16 -0
  93. data/fastlane_core/lib/fastlane_core/ui/implementations/shell.rb +12 -1
  94. data/frameit/lib/frameit/commands_generator.rb +2 -1
  95. data/gym/lib/gym/commands_generator.rb +2 -1
  96. data/gym/lib/gym/generators/package_command_generator.rb +4 -0
  97. data/gym/lib/gym/generators/package_command_generator_xcode7.rb +13 -8
  98. data/gym/lib/gym/runner.rb +15 -4
  99. data/match/lib/match/change_password.rb +3 -3
  100. data/match/lib/match/commands_generator.rb +2 -1
  101. data/match/lib/match/encryption/interface.rb +1 -1
  102. data/match/lib/match/encryption/openssl.rb +2 -2
  103. data/match/lib/match/module.rb +1 -0
  104. data/pem/lib/pem/commands_generator.rb +2 -1
  105. data/pilot/lib/pilot/commands_generator.rb +2 -1
  106. data/pilot/lib/pilot/manager.rb +4 -0
  107. data/pilot/lib/pilot/options.rb +3 -2
  108. data/pilot/lib/pilot/tester_exporter.rb +0 -1
  109. data/pilot/lib/pilot/tester_manager.rb +0 -1
  110. data/precheck/lib/precheck/commands_generator.rb +2 -1
  111. data/precheck/lib/precheck/options.rb +1 -0
  112. data/precheck/lib/precheck/runner.rb +4 -0
  113. data/produce/lib/produce/commands_generator.rb +2 -1
  114. data/scan/lib/scan/commands_generator.rb +2 -1
  115. data/scan/lib/scan/options.rb +10 -5
  116. data/scan/lib/scan/runner.rb +54 -1
  117. data/scan/lib/scan/test_command_generator.rb +10 -8
  118. data/screengrab/lib/screengrab/android_environment.rb +6 -4
  119. data/screengrab/lib/screengrab/commands_generator.rb +2 -1
  120. data/screengrab/lib/screengrab/runner.rb +1 -1
  121. data/sigh/lib/sigh/commands_generator.rb +2 -1
  122. data/sigh/lib/sigh/options.rb +1 -0
  123. data/sigh/lib/sigh/runner.rb +4 -0
  124. data/snapshot/lib/assets/SnapfileTemplate +1 -1
  125. data/snapshot/lib/assets/SnapshotHelper.swift +1 -1
  126. data/snapshot/lib/snapshot/commands_generator.rb +3 -1
  127. data/snapshot/lib/snapshot/options.rb +5 -0
  128. data/snapshot/lib/snapshot/reports_generator.rb +4 -0
  129. data/snapshot/lib/snapshot/simulator_launchers/launcher_configuration.rb +2 -0
  130. data/snapshot/lib/snapshot/simulator_launchers/simulator_launcher.rb +1 -1
  131. data/snapshot/lib/snapshot/simulator_launchers/simulator_launcher_base.rb +8 -4
  132. data/spaceship/README.md +2 -12
  133. data/spaceship/lib/spaceship/base.rb +2 -2
  134. data/spaceship/lib/spaceship/commands_generator.rb +4 -2
  135. data/spaceship/lib/spaceship/connect_api/models/app_screenshot.rb +1 -1
  136. data/spaceship/lib/spaceship/connect_api/models/profile.rb +6 -0
  137. data/spaceship/lib/spaceship/connect_api/provisioning/provisioning.rb +6 -2
  138. data/spaceship/lib/spaceship/connect_api/token.rb +7 -1
  139. data/spaceship/lib/spaceship/spaceauth_runner.rb +19 -9
  140. data/spaceship/lib/spaceship/tunes/members.rb +1 -1
  141. data/spaceship/lib/spaceship/ui.rb +2 -2
  142. data/supply/lib/supply/client.rb +3 -1
  143. data/supply/lib/supply/commands_generator.rb +2 -1
  144. data/supply/lib/supply/options.rb +2 -2
  145. data/supply/lib/supply/uploader.rb +1 -0
  146. metadata +53 -64
  147. data/gym/lib/gym/.runner.rb.swp +0 -0
  148. data/pilot/lib/pilot/tester_util.rb +0 -0
@@ -243,12 +243,16 @@ module Gym
243
243
  # Moves over the binary and dsym file to the output directory
244
244
  # @return (String) The path to the resulting pkg file
245
245
  def move_pkg
246
- FileUtils.mv(PackageCommandGenerator.pkg_path, File.expand_path(Gym.config[:output_directory]), force: true)
247
- pkg_path = File.expand_path(File.join(Gym.config[:output_directory], File.basename(PackageCommandGenerator.pkg_path)))
246
+ binary_path = File.expand_path(File.join(Gym.config[:output_directory], File.basename(PackageCommandGenerator.binary_path)))
247
+ if File.exist?(binary_path)
248
+ UI.important(" Removing #{File.basename(binary_path)}") if FastlaneCore::Globals.verbose?
249
+ FileUtils.rm_rf(binary_path)
250
+ end
251
+ FileUtils.mv(PackageCommandGenerator.binary_path, File.expand_path(Gym.config[:output_directory]), force: true)
248
252
 
249
253
  UI.success("Successfully exported and signed the pkg file:")
250
- UI.message(pkg_path)
251
- pkg_path
254
+ UI.message(binary_path)
255
+ binary_path
252
256
  end
253
257
 
254
258
  # copys framework from temp folder:
@@ -274,6 +278,13 @@ module Gym
274
278
  exe_name = Gym.project.build_settings(key: "EXECUTABLE_NAME")
275
279
  app_path = File.join(BuildCommandGenerator.archive_path, "Products/Applications/#{exe_name}.app")
276
280
 
281
+ unless File.exist?(app_path)
282
+ # Apparently the `EXECUTABLE_NAME` is not correct. This can happen when building a workspace which has a project
283
+ # earlier in the build order that has a different `EXECUTABLE_NAME` than the app. Try to find the last `.app` as
284
+ # a fallback for this situation.
285
+ app_path = Dir[File.join(BuildCommandGenerator.archive_path, "Products", "Applications", "*.app")].last
286
+ end
287
+
277
288
  UI.crash!("Couldn't find application in '#{BuildCommandGenerator.archive_path}'") unless File.exist?(app_path)
278
289
 
279
290
  joined_app_path = File.join(Gym.config[:output_directory], File.basename(app_path))
@@ -16,7 +16,7 @@ module Match
16
16
 
17
17
  ensure_ui_interactive
18
18
 
19
- to = FastlaneCore::Helper.ask_password(message: "New passphrase for Git Repo: ", confirm: true)
19
+ new_password = FastlaneCore::Helper.ask_password(message: "New passphrase for Git Repo: ", confirm: true)
20
20
 
21
21
  # Choose the right storage and encryption implementations
22
22
  storage = Storage.for_mode(params[:storage_mode], {
@@ -37,10 +37,10 @@ module Match
37
37
  encryption.decrypt_files
38
38
 
39
39
  encryption.clear_password
40
- encryption.store_password(to)
40
+ encryption.store_password(new_password)
41
41
 
42
42
  message = "[fastlane] Changed passphrase"
43
- files_to_commit = encryption.encrypt_files
43
+ files_to_commit = encryption.encrypt_files(password: new_password)
44
44
  storage.save_changes!(files_to_commit: files_to_commit, custom_message: message)
45
45
  end
46
46
 
@@ -1,6 +1,7 @@
1
1
  require 'commander'
2
2
 
3
3
  require 'fastlane_core/configuration/configuration'
4
+ require 'fastlane_core/ui/help_formatter'
4
5
 
5
6
  require_relative 'nuke'
6
7
  require_relative 'change_password'
@@ -32,7 +33,7 @@ module Match
32
33
  program :help, 'Author', 'Felix Krause <match@krausefx.com>'
33
34
  program :help, 'Website', 'https://fastlane.tools'
34
35
  program :help, 'Documentation', 'https://docs.fastlane.tools/actions/match/'
35
- program :help_formatter, :compact
36
+ program :help_formatter, FastlaneCore::HelpFormatter
36
37
 
37
38
  global_option('--verbose') { FastlaneCore::Globals.verbose = true }
38
39
  global_option('--env STRING[,STRING2]', String, 'Add environment(s) to use with `dotenv`')
@@ -3,7 +3,7 @@ module Match
3
3
  class Interface
4
4
  # Call this method to trigger the actual
5
5
  # encryption
6
- def encrypt_files
6
+ def encrypt_files(password: nil)
7
7
  not_implemented(__method__)
8
8
  end
9
9
 
@@ -28,9 +28,9 @@ module Match
28
28
  self.working_directory = working_directory
29
29
  end
30
30
 
31
- def encrypt_files
31
+ def encrypt_files(password: nil)
32
32
  files = []
33
- password = fetch_password!
33
+ password ||= fetch_password!
34
34
  iterate(self.working_directory) do |current|
35
35
  files << current
36
36
  encrypt_specific_file(path: current, password: password)
@@ -21,6 +21,7 @@ module Match
21
21
  end
22
22
 
23
23
  def self.cert_type_sym(type)
24
+ type = type.to_s
24
25
  return :mac_installer_distribution if type == "mac_installer_distribution"
25
26
  return :developer_id_installer if type == "developer_id_installer"
26
27
  return :developer_id_application if type == "developer_id"
@@ -2,6 +2,7 @@ require 'commander'
2
2
 
3
3
  require 'fastlane/version'
4
4
  require 'fastlane_core/configuration/configuration'
5
+ require 'fastlane_core/ui/help_formatter'
5
6
  require_relative 'options'
6
7
  require_relative 'manager'
7
8
 
@@ -22,7 +23,7 @@ module PEM
22
23
  program :help, 'Author', 'Felix Krause <pem@krausefx.com>'
23
24
  program :help, 'Website', 'https://fastlane.tools'
24
25
  program :help, 'Documentation', 'https://docs.fastlane.tools/actions/pem/'
25
- program :help_formatter, :compact
26
+ program :help_formatter, FastlaneCore::HelpFormatter
26
27
 
27
28
  global_option('--verbose') { FastlaneCore::Globals.verbose = true }
28
29
  global_option('--env STRING[,STRING2]', String, 'Add environment(s) to use with `dotenv`')
@@ -1,6 +1,7 @@
1
1
  require "commander"
2
2
 
3
3
  require 'fastlane_core/configuration/configuration'
4
+ require 'fastlane_core/ui/help_formatter'
4
5
  require_relative 'module'
5
6
  require_relative 'tester_importer'
6
7
  require_relative 'tester_exporter'
@@ -51,7 +52,7 @@ module Pilot
51
52
  program :help, "Author", "Felix Krause <pilot@krausefx.com>"
52
53
  program :help, "Website", "https://fastlane.tools"
53
54
  program :help, "Documentation", "https://docs.fastlane.tools/actions/pilot/"
54
- program :help_formatter, :compact
55
+ program :help_formatter, FastlaneCore::HelpFormatter
55
56
 
56
57
  global_option("--verbose") { FastlaneCore::Globals.verbose = true }
57
58
 
@@ -23,6 +23,10 @@ module Pilot
23
23
  else
24
24
  config[:username] ||= CredentialsManager::AppfileConfig.try_fetch_value(:apple_id)
25
25
 
26
+ # Username is now optional since addition of App Store Connect API Key
27
+ # Force asking for username to prompt user if not already set
28
+ config.fetch(:username, force_ask: true)
29
+
26
30
  UI.message("Login to App Store Connect (#{config[:username]})")
27
31
  Spaceship::ConnectAPI.login(config[:username], use_portal: false, use_tunes: true, tunes_team_id: config[:team_id], team_name: config[:team_name])
28
32
  UI.message("Login successful")
@@ -31,6 +31,7 @@ module Pilot
31
31
  short_option: "-u",
32
32
  env_name: "PILOT_USERNAME",
33
33
  description: "Your Apple ID Username",
34
+ optional: true,
34
35
  default_value: user,
35
36
  default_value_dynamic: true),
36
37
  FastlaneCore::ConfigItem.new(key: :app_identifier,
@@ -268,12 +269,12 @@ module Pilot
268
269
  verify_block: proc do |value|
269
270
  ENV["FASTLANE_TEAM_ID"] = value.to_s
270
271
  end),
271
- # rubocop:disable Metrics/LineLength
272
+ # rubocop:disable Layout/LineLength
272
273
  FastlaneCore::ConfigItem.new(key: :itc_provider,
273
274
  env_name: "PILOT_ITC_PROVIDER",
274
275
  description: "The provider short name to be used with the iTMSTransporter to identify your team. This value will override the automatically detected provider short name. To get provider short name run `pathToXcode.app/Contents/Applications/Application\\ Loader.app/Contents/itms/bin/iTMSTransporter -m provider -u 'USERNAME' -p 'PASSWORD' -account_type itunes_connect -v off`. The short names of providers should be listed in the second column",
275
276
  optional: true),
276
- # rubocop:enable Metrics/LineLength
277
+ # rubocop:enable Layout/LineLength
277
278
 
278
279
  # waiting and uploaded build
279
280
  FastlaneCore::ConfigItem.new(key: :wait_processing_interval,
@@ -1,5 +1,4 @@
1
1
  require 'spaceship/tunes/application'
2
- require_relative 'tester_util'
3
2
  require_relative 'module'
4
3
  require_relative 'manager'
5
4
 
@@ -1,7 +1,6 @@
1
1
  require 'terminal-table'
2
2
 
3
3
  require_relative 'manager'
4
- require_relative 'tester_util'
5
4
 
6
5
  module Pilot
7
6
  class TesterManager < Manager
@@ -4,6 +4,7 @@ require "fastlane_core/configuration/commander_generator"
4
4
  require "fastlane_core/configuration/configuration"
5
5
  require "fastlane_core/helper"
6
6
  require "fastlane/version"
7
+ require 'fastlane_core/ui/help_formatter'
7
8
 
8
9
  require_relative 'module'
9
10
  require_relative 'options'
@@ -26,7 +27,7 @@ module Precheck
26
27
  program :help, "Author", "Joshua Liebowitz <taquitos@gmail.com>, @taquitos"
27
28
  program :help, "Website", "https://fastlane.tools"
28
29
  program :help, "Documentation", "https://docs.fastlane.tools/actions/precheck/"
29
- program :help_formatter, :compact
30
+ program :help_formatter, FastlaneCore::HelpFormatter
30
31
 
31
32
  global_option("--verbose") { FastlaneCore::Globals.verbose = true }
32
33
 
@@ -52,6 +52,7 @@ module Precheck
52
52
  short_option: "-u",
53
53
  env_name: "PRECHECK_USERNAME",
54
54
  description: "Your Apple ID Username",
55
+ optional: true,
55
56
  default_value: user,
56
57
  default_value_dynamic: true),
57
58
  FastlaneCore::ConfigItem.new(key: :team_id,
@@ -32,6 +32,10 @@ module Precheck
32
32
  UI.message("Creating authorization token for App Store Connect API")
33
33
  Spaceship::ConnectAPI.token = api_token
34
34
  elsif Spaceship::Tunes.client.nil?
35
+ # Username is now optional since addition of App Store Connect API Key
36
+ # Force asking for username to prompt user if not already set
37
+ Precheck.config.fetch(:username, force_ask: true)
38
+
35
39
  # Team selection passed though FASTLANE_ITC_TEAM_ID and FASTLANE_ITC_TEAM_NAME environment variables
36
40
  # Prompts select team if multiple teams and none specified
37
41
  UI.message("Starting login with user '#{Precheck.config[:username]}'")
@@ -1,6 +1,7 @@
1
1
  require 'commander'
2
2
 
3
3
  require 'fastlane/version'
4
+ require 'fastlane_core/ui/help_formatter'
4
5
  require 'fastlane_core/configuration/config_item'
5
6
  require_relative 'module'
6
7
  require_relative 'manager'
@@ -23,7 +24,7 @@ module Produce
23
24
  program :help, 'Author', 'Felix Krause <produce@krausefx.com>'
24
25
  program :help, 'Website', 'https://fastlane.tools'
25
26
  program :help, 'Documentation', 'https://docs.fastlane.tools/actions/produce/'
26
- program :help_formatter, :compact
27
+ program :help_formatter, FastlaneCore::HelpFormatter
27
28
 
28
29
  global_option('--verbose') { FastlaneCore::Globals.verbose = true }
29
30
  global_option('--env STRING[,STRING2]', String, 'Add environment(s) to use with `dotenv`')
@@ -1,6 +1,7 @@
1
1
  require 'commander'
2
2
 
3
3
  require 'fastlane_core/configuration/configuration'
4
+ require 'fastlane_core/ui/help_formatter'
4
5
  require_relative 'module'
5
6
  require_relative 'manager'
6
7
  require_relative 'options'
@@ -28,7 +29,7 @@ module Scan
28
29
  program :help, "Author", "Felix Krause <scan@krausefx.com>"
29
30
  program :help, "Website", "https://fastlane.tools"
30
31
  program :help, "Documentation", "https://docs.fastlane.tools/actions/scan/"
31
- program :help_formatter, :compact
32
+ program :help_formatter, FastlaneCore::HelpFormatter
32
33
 
33
34
  global_option("--verbose") { FastlaneCore::Globals.verbose = true }
34
35
 
@@ -472,11 +472,16 @@ module Scan
472
472
  type: Boolean,
473
473
  default_value: false),
474
474
  FastlaneCore::ConfigItem.new(key: :use_system_scm,
475
- env_name: "SCAN_USE_SYSTEM_SCM",
476
- description: "Lets xcodebuild use system's scm configuration",
477
- optional: true,
478
- type: Boolean,
479
- default_value: false)
475
+ env_name: "SCAN_USE_SYSTEM_SCM",
476
+ description: "Lets xcodebuild use system's scm configuration",
477
+ optional: true,
478
+ type: Boolean,
479
+ default_value: false),
480
+ FastlaneCore::ConfigItem.new(key: :number_of_retries,
481
+ env_name: 'SCAN_NUMBER_OF_RETRIES',
482
+ description: "The number of times a test can fail before scan should stop retrying",
483
+ type: Integer,
484
+ default_value: 0)
480
485
 
481
486
  ]
482
487
  end
@@ -51,7 +51,14 @@ module Scan
51
51
  end
52
52
  end
53
53
 
54
+ execute(retries: Scan.config[:number_of_retries])
55
+ end
56
+
57
+ def execute(retries: 0)
58
+ Scan.cache[:retry_attempt] = Scan.config[:number_of_retries] - retries
59
+
54
60
  command = @test_command_generator.generate
61
+
55
62
  prefix_hash = [
56
63
  {
57
64
  prefix: "Running Tests: ",
@@ -71,7 +78,12 @@ module Scan
71
78
  error: proc do |error_output|
72
79
  begin
73
80
  exit_status = $?.exitstatus
74
- ErrorHandler.handle_build_error(error_output, @test_command_generator.xcodebuild_log_path)
81
+ if retries > 0
82
+ # If there are retries remaining, run the tests again
83
+ return retry_execute(retries: retries, error_output: error_output)
84
+ else
85
+ ErrorHandler.handle_build_error(error_output, @test_command_generator.xcodebuild_log_path)
86
+ end
75
87
  rescue => ex
76
88
  SlackPoster.new.run({
77
89
  build_errors: 1
@@ -79,9 +91,50 @@ module Scan
79
91
  raise ex
80
92
  end
81
93
  end)
94
+
82
95
  exit_status
83
96
  end
84
97
 
98
+ def retry_execute(retries:, error_output: "")
99
+ tests = retryable_tests(error_output)
100
+
101
+ if tests.empty?
102
+ UI.crash!("Failed to find failed tests to retry (could not parse error output)")
103
+ end
104
+
105
+ Scan.config[:only_testing] = tests
106
+ UI.important("Retrying tests: #{Scan.config[:only_testing].join(', ')}")
107
+
108
+ retries -= 1
109
+ UI.important("Number of retries remaining: #{retries}")
110
+
111
+ return execute(retries: retries)
112
+ end
113
+
114
+ def retryable_tests(input)
115
+ input = Helper.strip_ansi_colors(input)
116
+
117
+ retryable_tests = []
118
+
119
+ failing_tests = input.split("Failing tests:\n").fetch(1, [])
120
+ .split("\n\n").first
121
+
122
+ suites = failing_tests.split(/(?=\n\s+[\w\s]+:\n)/)
123
+
124
+ suites.each do |suite|
125
+ suite_name = suite.match(/\s*([\w\s]+):/).captures.first
126
+
127
+ test_cases = suite.split(":\n").fetch(1, []).split("\n").each
128
+ .select { |line| line.match?(/^\s+/) }
129
+ .map { |line| line.strip.gsub(".", "/").gsub("()", "") }
130
+ .map { |line| suite_name + "/" + line }
131
+
132
+ retryable_tests += test_cases
133
+ end
134
+
135
+ return retryable_tests.uniq
136
+ end
137
+
85
138
  def handle_results(tests_exit_status)
86
139
  if Scan.config[:disable_xcpretty]
87
140
  unless tests_exit_status == 0
@@ -162,16 +162,18 @@ module Scan
162
162
  Scan.cache[:build_path]
163
163
  end
164
164
 
165
+ # The path to the result bundle
165
166
  def result_bundle_path
166
- unless Scan.cache[:result_bundle_path]
167
- ext = FastlaneCore::Helper.xcode_version.to_i >= 11 ? '.xcresult' : '.test_result'
168
- path = File.join(Scan.config[:output_directory], Scan.config[:scheme]) + ext
169
- if File.directory?(path)
170
- FileUtils.remove_dir(path)
171
- end
172
- Scan.cache[:result_bundle_path] = path
167
+ retry_count = Scan.cache[:retry_attempt] || 0
168
+ attempt = retry_count > 0 ? "-#{retry_count}" : ""
169
+ ext = FastlaneCore::Helper.xcode_version.to_i >= 11 ? '.xcresult' : '.test_result'
170
+ path = File.join(Scan.config[:output_directory], Scan.config[:scheme]) + attempt + ext
171
+ if File.directory?(path)
172
+ FileUtils.remove_dir(path)
173
173
  end
174
- return Scan.cache[:result_bundle_path]
174
+ Scan.cache[:result_bundle_path] = path
175
+
176
+ return path
175
177
  end
176
178
  end
177
179
  end
@@ -34,22 +34,22 @@ module Screengrab
34
34
  def find_platform_tools(android_home)
35
35
  return nil unless android_home
36
36
 
37
- platform_tools_path = File.join(android_home, 'platform-tools')
37
+ platform_tools_path = Helper.localize_file_path(File.join(android_home, 'platform-tools'))
38
38
  File.directory?(platform_tools_path) ? platform_tools_path : nil
39
39
  end
40
40
 
41
41
  def find_build_tools(android_home, build_tools_version)
42
42
  return nil unless android_home
43
43
 
44
- build_tools_dir = File.join(android_home, 'build-tools')
44
+ build_tools_dir = Helper.localize_file_path(File.join(android_home, 'build-tools'))
45
45
 
46
46
  return nil unless build_tools_dir && File.directory?(build_tools_dir)
47
47
 
48
- return File.join(build_tools_dir, build_tools_version) if build_tools_version
48
+ return Helper.localize_file_path(File.join(build_tools_dir, build_tools_version)) if build_tools_version
49
49
 
50
50
  version = select_build_tools_version(build_tools_dir)
51
51
 
52
- return version ? File.join(build_tools_dir, version) : nil
52
+ return version ? Helper.localize_file_path(File.join(build_tools_dir, version)) : nil
53
53
  end
54
54
 
55
55
  def select_build_tools_version(build_tools_dir)
@@ -74,6 +74,7 @@ module Screengrab
74
74
  return FastlaneCore::CommandExecutor.which('adb') unless platform_tools_path
75
75
 
76
76
  adb_path = Helper.get_executable_path(File.join(platform_tools_path, 'adb'))
77
+ adb_path = Helper.localize_file_path(adb_path)
77
78
  return executable_command?(adb_path) ? adb_path : nil
78
79
  end
79
80
 
@@ -81,6 +82,7 @@ module Screengrab
81
82
  return FastlaneCore::CommandExecutor.which('aapt') unless build_tools_path
82
83
 
83
84
  aapt_path = Helper.get_executable_path(File.join(build_tools_path, 'aapt'))
85
+ aapt_path = Helper.localize_file_path(aapt_path)
84
86
  return executable_command?(aapt_path) ? aapt_path : nil
85
87
  end
86
88
 
@@ -1,6 +1,7 @@
1
1
  require 'commander'
2
2
 
3
3
  require 'fastlane/version'
4
+ require 'fastlane_core/ui/help_formatter'
4
5
  require 'fastlane_core/fastlane_folder'
5
6
  require 'fastlane_core/configuration/configuration'
6
7
  require_relative 'android_environment'
@@ -26,7 +27,7 @@ module Screengrab
26
27
  program :help, 'Authors', 'Andrea Falcone <asfalcone@google.com>, Michael Furtak <mfurtak@google.com>'
27
28
  program :help, 'Website', 'https://fastlane.tools'
28
29
  program :help, 'Documentation', 'https://docs.fastlane.tools/actions/screengrab/'
29
- program :help_formatter, :compact
30
+ program :help_formatter, FastlaneCore::HelpFormatter
30
31
 
31
32
  global_option('--verbose', 'Shows a more verbose output') { FastlaneCore::Globals.verbose = true }
32
33