fastlane 2.174.0 → 2.179.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (138) hide show
  1. checksums.yaml +4 -4
  2. data/LICENSE +1 -1
  3. data/README.md +93 -80
  4. data/cert/lib/cert/options.rb +3 -2
  5. data/cert/lib/cert/runner.rb +5 -1
  6. data/deliver/lib/deliver/app_screenshot.rb +6 -2
  7. data/deliver/lib/deliver/download_screenshots.rb +1 -2
  8. data/deliver/lib/deliver/options.rb +3 -2
  9. data/deliver/lib/deliver/runner.rb +12 -4
  10. data/deliver/lib/deliver/setup.rb +0 -1
  11. data/deliver/lib/deliver/upload_metadata.rb +5 -4
  12. data/deliver/lib/deliver/upload_screenshots.rb +12 -11
  13. data/fastlane/lib/fastlane/actions/adb.rb +1 -1
  14. data/fastlane/lib/fastlane/actions/app_store_build_number.rb +8 -3
  15. data/fastlane/lib/fastlane/actions/app_store_connect_api_key.rb +7 -4
  16. data/fastlane/lib/fastlane/actions/appaloosa.rb +7 -2
  17. data/fastlane/lib/fastlane/actions/backup_file.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/commit_github_file.rb +11 -1
  21. data/fastlane/lib/fastlane/actions/create_xcframework.rb +5 -0
  22. data/fastlane/lib/fastlane/actions/docs/capture_android_screenshots.md +1 -1
  23. data/fastlane/lib/fastlane/actions/docs/frame_screenshots.md +1 -1
  24. data/fastlane/lib/fastlane/actions/docs/sync_code_signing.md +8 -2
  25. data/fastlane/lib/fastlane/actions/docs/upload_to_play_store.md +2 -1
  26. data/fastlane/lib/fastlane/actions/download_dsyms.rb +5 -15
  27. data/fastlane/lib/fastlane/actions/get_github_release.rb +11 -1
  28. data/fastlane/lib/fastlane/actions/get_provisioning_profile.rb +4 -0
  29. data/fastlane/lib/fastlane/actions/get_version_number.rb +17 -10
  30. data/fastlane/lib/fastlane/actions/git_branch.rb +4 -10
  31. data/fastlane/lib/fastlane/actions/git_commit.rb +1 -1
  32. data/fastlane/lib/fastlane/actions/git_tag_exists.rb +4 -0
  33. data/fastlane/lib/fastlane/actions/github_api.rb +2 -1
  34. data/fastlane/lib/fastlane/actions/increment_build_number.rb +8 -1
  35. data/fastlane/lib/fastlane/actions/install_provisioning_profile.rb +4 -0
  36. data/fastlane/lib/fastlane/actions/jazzy.rb +10 -1
  37. data/fastlane/lib/fastlane/actions/latest_testflight_build_number.rb +3 -2
  38. data/fastlane/lib/fastlane/actions/match_nuke.rb +59 -0
  39. data/fastlane/lib/fastlane/actions/push_to_git_remote.rb +0 -1
  40. data/fastlane/lib/fastlane/actions/register_device.rb +3 -3
  41. data/fastlane/lib/fastlane/actions/register_devices.rb +3 -3
  42. data/fastlane/lib/fastlane/actions/restore_file.rb +1 -1
  43. data/fastlane/lib/fastlane/actions/set_changelog.rb +3 -3
  44. data/fastlane/lib/fastlane/actions/spaceship_logs.rb +1 -1
  45. data/fastlane/lib/fastlane/actions/swiftlint.rb +1 -1
  46. data/fastlane/lib/fastlane/actions/update_code_signing_settings.rb +1 -1
  47. data/fastlane/lib/fastlane/actions/update_project_provisioning.rb +1 -2
  48. data/fastlane/lib/fastlane/actions/upload_symbols_to_crashlytics.rb +4 -5
  49. data/fastlane/lib/fastlane/actions/upload_to_testflight.rb +5 -1
  50. data/fastlane/lib/fastlane/documentation/actions_list.rb +2 -2
  51. data/fastlane/lib/fastlane/erb_template_helper.rb +7 -1
  52. data/fastlane/lib/fastlane/fast_file.rb +9 -5
  53. data/fastlane/lib/fastlane/helper/adb_helper.rb +1 -1
  54. data/fastlane/lib/fastlane/helper/gem_helper.rb +2 -2
  55. data/fastlane/lib/fastlane/helper/git_helper.rb +11 -7
  56. data/fastlane/lib/fastlane/plugins/plugin_fetcher.rb +1 -2
  57. data/fastlane/lib/fastlane/plugins/plugin_info_collector.rb +1 -2
  58. data/fastlane/lib/fastlane/plugins/plugin_manager.rb +1 -2
  59. data/fastlane/lib/fastlane/swift_fastlane_function.rb +4 -0
  60. data/fastlane/lib/fastlane/version.rb +1 -1
  61. data/fastlane/swift/Deliverfile.swift +1 -1
  62. data/fastlane/swift/DeliverfileProtocol.swift +3 -3
  63. data/fastlane/swift/Fastlane.swift +491 -315
  64. data/fastlane/swift/Gymfile.swift +1 -1
  65. data/fastlane/swift/GymfileProtocol.swift +1 -1
  66. data/fastlane/swift/Matchfile.swift +1 -1
  67. data/fastlane/swift/MatchfileProtocol.swift +1 -1
  68. data/fastlane/swift/Precheckfile.swift +1 -1
  69. data/fastlane/swift/PrecheckfileProtocol.swift +3 -3
  70. data/fastlane/swift/Scanfile.swift +1 -1
  71. data/fastlane/swift/ScanfileProtocol.swift +9 -1
  72. data/fastlane/swift/Screengrabfile.swift +1 -1
  73. data/fastlane/swift/ScreengrabfileProtocol.swift +1 -1
  74. data/fastlane/swift/Snapshotfile.swift +1 -1
  75. data/fastlane/swift/SnapshotfileProtocol.swift +1 -1
  76. data/fastlane/swift/formatting/Brewfile.lock.json +13 -11
  77. data/fastlane_core/lib/fastlane_core.rb +1 -0
  78. data/fastlane_core/lib/fastlane_core/command_executor.rb +3 -9
  79. data/fastlane_core/lib/fastlane_core/configuration/commander_generator.rb +1 -1
  80. data/fastlane_core/lib/fastlane_core/configuration/config_item.rb +23 -0
  81. data/fastlane_core/lib/fastlane_core/configuration/configuration.rb +6 -6
  82. data/fastlane_core/lib/fastlane_core/helper.rb +50 -6
  83. data/fastlane_core/lib/fastlane_core/ipa_upload_package_builder.rb +3 -2
  84. data/fastlane_core/lib/fastlane_core/itunes_transporter.rb +14 -8
  85. data/fastlane_core/lib/fastlane_core/keychain_importer.rb +1 -1
  86. data/fastlane_core/lib/fastlane_core/pkg_upload_package_builder.rb +3 -2
  87. data/fastlane_core/lib/fastlane_core/project.rb +3 -14
  88. data/{deliver/lib/deliver → fastlane_core/lib/fastlane_core}/queue_worker.rb +2 -2
  89. data/fastlane_core/lib/fastlane_core/ui/interface.rb +1 -1
  90. data/fastlane_core/lib/fastlane_core/update_checker/update_checker.rb +2 -2
  91. data/gym/lib/gym/.runner.rb.swp +0 -0
  92. data/gym/lib/gym/generators/.package_command_generator_xcode7.rb.swp +0 -0
  93. data/gym/lib/gym/generators/package_command_generator.rb +4 -0
  94. data/gym/lib/gym/generators/package_command_generator_xcode7.rb +13 -8
  95. data/gym/lib/gym/runner.rb +11 -4
  96. data/match/lib/match/change_password.rb +3 -3
  97. data/match/lib/match/encryption/interface.rb +1 -1
  98. data/match/lib/match/encryption/openssl.rb +2 -2
  99. data/match/lib/match/importer.rb +1 -1
  100. data/match/lib/match/migrate.rb +1 -1
  101. data/match/lib/match/module.rb +1 -0
  102. data/match/lib/match/nuke.rb +6 -1
  103. data/match/lib/match/options.rb +2 -2
  104. data/match/lib/match/runner.rb +1 -1
  105. data/match/lib/match/storage/google_cloud_storage.rb +1 -1
  106. data/match/lib/match/storage/s3_storage.rb +1 -1
  107. data/pilot/lib/pilot/build_manager.rb +25 -8
  108. data/pilot/lib/pilot/manager.rb +5 -1
  109. data/pilot/lib/pilot/options.rb +6 -5
  110. data/precheck/lib/precheck/options.rb +3 -2
  111. data/precheck/lib/precheck/runner.rb +6 -2
  112. data/scan/lib/scan/detect_values.rb +4 -1
  113. data/scan/lib/scan/options.rb +10 -0
  114. data/scan/lib/scan/runner.rb +27 -0
  115. data/screengrab/lib/screengrab/android_environment.rb +8 -6
  116. data/screengrab/lib/screengrab/runner.rb +2 -3
  117. data/sigh/lib/sigh/download_all.rb +1 -1
  118. data/sigh/lib/sigh/options.rb +3 -2
  119. data/sigh/lib/sigh/runner.rb +5 -1
  120. data/snapshot/lib/snapshot/simulator_launchers/simulator_launcher_base.rb +2 -1
  121. data/spaceship/README.md +2 -2
  122. data/spaceship/lib/spaceship/client.rb +18 -17
  123. data/spaceship/lib/spaceship/connect_api/api_client.rb +24 -6
  124. data/spaceship/lib/spaceship/connect_api/models/app.rb +1 -1
  125. data/spaceship/lib/spaceship/connect_api/models/app_preview_set.rb +5 -0
  126. data/spaceship/lib/spaceship/connect_api/models/app_screenshot_set.rb +5 -0
  127. data/spaceship/lib/spaceship/connect_api/models/app_store_version_localization.rb +6 -0
  128. data/spaceship/lib/spaceship/connect_api/models/beta_group.rb +5 -0
  129. data/spaceship/lib/spaceship/connect_api/models/build.rb +5 -0
  130. data/spaceship/lib/spaceship/connect_api/models/build_beta_detail.rb +4 -0
  131. data/spaceship/lib/spaceship/connect_api/models/user_invitation.rb +13 -0
  132. data/spaceship/lib/spaceship/connect_api/testflight/testflight.rb +13 -0
  133. data/spaceship/lib/spaceship/connect_api/token.rb +2 -2
  134. data/spaceship/lib/spaceship/connect_api/tunes/tunes.rb +15 -0
  135. data/spaceship/lib/spaceship/playground.rb +2 -2
  136. data/spaceship/lib/spaceship/tunes/tunes_client.rb +2 -2
  137. data/spaceship/lib/spaceship/two_step_or_factor_client.rb +41 -28
  138. metadata +41 -22
@@ -11,7 +11,7 @@ module Pilot
11
11
 
12
12
  [
13
13
  FastlaneCore::ConfigItem.new(key: :api_key_path,
14
- env_name: "PILOT_API_KEY_PATH",
14
+ env_names: ["PILOT_API_KEY_PATH", "APP_STORE_CONNECT_API_KEY_PATH"],
15
15
  description: "Path to your App Store Connect API Key JSON file (https://docs.fastlane.tools/app-store-connect-api/#using-fastlane-api-key-json-file)",
16
16
  optional: true,
17
17
  conflicting_options: [:username],
@@ -19,7 +19,7 @@ module Pilot
19
19
  UI.user_error!("Couldn't find API key JSON file at path '#{value}'") unless File.exist?(value)
20
20
  end),
21
21
  FastlaneCore::ConfigItem.new(key: :api_key,
22
- env_name: "PILOT_API_KEY",
22
+ env_names: ["PILOT_API_KEY", "APP_STORE_CONNECT_API_KEY"],
23
23
  description: "Your App Store Connect API Key information (https://docs.fastlane.tools/app-store-connect-api/#use-return-value-and-pass-in-as-an-option)",
24
24
  type: Hash,
25
25
  optional: true,
@@ -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,
@@ -88,7 +89,7 @@ module Pilot
88
89
  type: Boolean,
89
90
  env_name: "DEMO_ACCOUNT_REQUIRED",
90
91
  description: "Do you need a demo account when Apple does review?",
91
- default_value: false),
92
+ optional: true),
92
93
  FastlaneCore::ConfigItem.new(key: :beta_app_review_info,
93
94
  type: Hash,
94
95
  env_name: "PILOT_BETA_APP_REVIEW_INFO",
@@ -182,8 +183,8 @@ module Pilot
182
183
  FastlaneCore::ConfigItem.new(key: :notify_external_testers,
183
184
  is_string: false,
184
185
  env_name: "PILOT_NOTIFY_EXTERNAL_TESTERS",
185
- description: "Should notify external testers?",
186
- default_value: true),
186
+ description: "Should notify external testers? (Not setting a value will use App Store Connect's default which is to notify)",
187
+ optional: true),
187
188
  FastlaneCore::ConfigItem.new(key: :app_version,
188
189
  env_name: "PILOT_APP_VERSION",
189
190
  description: "The version number of the application build to distribute. If the version number is not specified, then the most recent build uploaded to TestFlight will be distributed. If specified, the most recent build for the version number will be distributed",
@@ -26,7 +26,7 @@ module Precheck
26
26
 
27
27
  [
28
28
  FastlaneCore::ConfigItem.new(key: :api_key_path,
29
- env_name: "PRECHECK_API_KEY_PATH",
29
+ env_names: ["PRECHECK_API_KEY_PATH", "APP_STORE_CONNECT_API_KEY_PATH"],
30
30
  description: "Path to your App Store Connect API Key JSON file (https://docs.fastlane.tools/app-store-connect-api/#using-fastlane-api-key-json-file)",
31
31
  optional: true,
32
32
  conflicting_options: [:username],
@@ -34,7 +34,7 @@ module Precheck
34
34
  UI.user_error!("Couldn't find API key JSON file at path '#{value}'") unless File.exist?(value)
35
35
  end),
36
36
  FastlaneCore::ConfigItem.new(key: :api_key,
37
- env_name: "PRECHECK_API_KEY",
37
+ env_names: ["PRECHECK_API_KEY", "APP_STORE_CONNECT_API_KEY"],
38
38
  description: "Your App Store Connect API Key information (https://docs.fastlane.tools/app-store-connect-api/#use-return-value-and-pass-in-as-an-option)",
39
39
  type: Hash,
40
40
  optional: true,
@@ -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,
@@ -26,12 +26,16 @@ module Precheck
26
26
  # There is also a check in Deliver::Runner for this.
27
27
  # Please remove check in Deliver when the API support IAPs.
28
28
  if Precheck.config[:include_in_app_purchases]
29
- UI.user_error!("Precheck cannot check In-app purchases with the App Store Connect API Key (yet). Exclude In-app purchases from precheck or use Apple ID login")
29
+ UI.user_error!("Precheck cannot check In-app purchases with the App Store Connect API Key (yet). Exclude In-app purchases from precheck, disable the precheck step in your build step, or use Apple ID login")
30
30
  end
31
31
 
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]}'")
@@ -72,7 +76,7 @@ module Precheck
72
76
  end
73
77
 
74
78
  def api_token
75
- @api_token ||= Spaceship::ConnectAPI::Token.create(Precheck.config[:api_key]) if Precheck.config[:api_key]
79
+ @api_token ||= Spaceship::ConnectAPI::Token.create(**Precheck.config[:api_key]) if Precheck.config[:api_key]
76
80
  @api_token ||= Spaceship::ConnectAPI::Token.from_json_file(Precheck.config[:api_key_path]) if Precheck.config[:api_key_path]
77
81
  return @api_token
78
82
  end
@@ -162,7 +162,10 @@ module Scan
162
162
  filter_simulators(simulators, :equal, version).tap(&potential_emptiness_error).select(&selector)
163
163
  end
164
164
  ).tap do |array|
165
- UI.error("Ignoring '#{device_string}', couldn’t find matching simulator") if array.empty?
165
+ if array.empty?
166
+ UI.test_failure!("No device found with name '#{device_string}'") if Scan.config[:ensure_devices_found]
167
+ UI.error("Ignoring '#{device_string}', couldn’t find matching simulator")
168
+ end
166
169
  end
167
170
  end
168
171
 
@@ -69,6 +69,11 @@ module Scan
69
69
  default_value: false,
70
70
  type: Boolean,
71
71
  optional: true),
72
+ FastlaneCore::ConfigItem.new(key: :ensure_devices_found,
73
+ description: "Should fail if devices not found",
74
+ default_value: false,
75
+ type: Boolean,
76
+ optional: true),
72
77
 
73
78
  # simulator management
74
79
  FastlaneCore::ConfigItem.new(key: :force_quit_simulator,
@@ -269,6 +274,11 @@ module Scan
269
274
  optional: true,
270
275
  is_string: false,
271
276
  default_value: false),
277
+ FastlaneCore::ConfigItem.new(key: :output_xctestrun,
278
+ type: Boolean,
279
+ env_name: "SCAN_OUTPUT_XCTESTRUN",
280
+ description: "Should provide additional copy of .xctestrun file (settings.xctestrun) and place in output path?",
281
+ default_value: false),
272
282
  FastlaneCore::ConfigItem.new(key: :result_bundle,
273
283
  short_option: "-z",
274
284
  env_name: "SCAN_RESULT_BUNDLE",
@@ -110,6 +110,7 @@ module Scan
110
110
 
111
111
  copy_simulator_logs
112
112
  zip_build_products
113
+ copy_xctestrun
113
114
 
114
115
  if result[:failures] > 0
115
116
  open_report
@@ -150,6 +151,32 @@ module Scan
150
151
  UI.message("Successfully zipped build products: #{output_path}")
151
152
  end
152
153
 
154
+ def copy_xctestrun
155
+ return unless Scan.config[:output_xctestrun]
156
+
157
+ # Gets :derived_data_path/Build/Products directory for coping .xctestrun file
158
+ derived_data_path = Scan.config[:derived_data_path]
159
+ path = File.join(derived_data_path, "Build", "Products")
160
+
161
+ # Gets absolute path of output directory
162
+ output_directory = File.absolute_path(Scan.config[:output_directory])
163
+ output_path = File.join(output_directory, "settings.xctestrun")
164
+
165
+ # Caching path for action to put into lane_context
166
+ Scan.cache[:output_xctestrun] = output_path
167
+
168
+ # Copy .xctestrun file and moves it to output directory
169
+ UI.message("Copying .xctestrun file")
170
+ xctestrun_file = Dir.glob("#{path}/*.xctestrun").first
171
+
172
+ if xctestrun_file
173
+ FileUtils.cp(xctestrun_file, output_path)
174
+ UI.message("Successfully copied xctestrun file: #{output_path}")
175
+ else
176
+ UI.user_error!("Could not find .xctextrun file to copy")
177
+ end
178
+ end
179
+
153
180
  def test_results
154
181
  temp_junit_report = Scan.cache[:temp_junit_report]
155
182
  return File.read(temp_junit_report) if temp_junit_report && File.file?(temp_junit_report)
@@ -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)
@@ -73,14 +73,16 @@ module Screengrab
73
73
  def find_adb(platform_tools_path)
74
74
  return FastlaneCore::CommandExecutor.which('adb') unless platform_tools_path
75
75
 
76
- adb_path = File.join(platform_tools_path, 'adb')
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
 
80
81
  def find_aapt(build_tools_path)
81
82
  return FastlaneCore::CommandExecutor.which('aapt') unless build_tools_path
82
83
 
83
- aapt_path = File.join(build_tools_path, 'aapt')
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
 
@@ -308,7 +308,7 @@ module Screengrab
308
308
  if out =~ /Permission denied/
309
309
  dir = File.dirname(path)
310
310
  base = File.basename(path)
311
- run_adb_command("-s #{device_serial} shell run-as #{@config[:app_package_name]} 'tar -cC #{dir} #{base}' | tar -xvC #{tempdir}",
311
+ run_adb_command("-s #{device_serial} shell run-as #{@config[:app_package_name]} \"tar -cC #{dir} #{base}\" | tar -xv -f- -C #{tempdir}",
312
312
  print_all: false,
313
313
  print_command: true)
314
314
  end
@@ -392,13 +392,12 @@ module Screengrab
392
392
  end
393
393
 
394
394
  def run_adb_command(command, print_all: false, print_command: false, raise_errors: true)
395
- adb_path = @android_env.adb_path.chomp("adb")
396
395
  adb_host = @config[:adb_host]
397
396
  host = adb_host.nil? ? '' : "-H #{adb_host} "
398
397
  output = ''
399
398
  begin
400
399
  errout = nil
401
- cmdout = @executor.execute(command: adb_path + "adb " + host + command,
400
+ cmdout = @executor.execute(command: @android_env.adb_path + " " + host + command,
402
401
  print_all: print_all,
403
402
  print_command: print_command,
404
403
  error: raise_errors ? nil : proc { |out, status| errout = out }) || ''
@@ -60,7 +60,7 @@ module Sigh
60
60
  end
61
61
 
62
62
  def api_token
63
- api_token ||= Spaceship::ConnectAPI::Token.create(Sigh.config[:api_key]) if Sigh.config[:api_key]
63
+ api_token ||= Spaceship::ConnectAPI::Token.create(**Sigh.config[:api_key]) if Sigh.config[:api_key]
64
64
  api_token ||= Spaceship::ConnectAPI::Token.from_json_file(Sigh.config[:api_key_path]) if Sigh.config[:api_key_path]
65
65
  return api_token
66
66
  end
@@ -57,7 +57,7 @@ module Sigh
57
57
 
58
58
  # App Store Connect API
59
59
  FastlaneCore::ConfigItem.new(key: :api_key_path,
60
- env_name: "SIGH_API_KEY_PATH",
60
+ env_names: ["SIGH_API_KEY_PATH", "APP_STORE_CONNECT_API_KEY_PATH"],
61
61
  description: "Path to your App Store Connect API Key JSON file (https://docs.fastlane.tools/app-store-connect-api/#using-fastlane-api-key-json-file)",
62
62
  optional: true,
63
63
  conflicting_options: [:api_key],
@@ -65,7 +65,7 @@ module Sigh
65
65
  UI.user_error!("Couldn't find API key JSON file at path '#{value}'") unless File.exist?(value)
66
66
  end),
67
67
  FastlaneCore::ConfigItem.new(key: :api_key,
68
- env_name: "SIGH_API_KEY",
68
+ env_names: ["SIGH_API_KEY", "APP_STORE_CONNECT_API_KEY"],
69
69
  description: "Your App Store Connect API Key information (https://docs.fastlane.tools/app-store-connect-api/#use-return-value-and-pass-in-as-an-option)",
70
70
  type: Hash,
71
71
  optional: true,
@@ -77,6 +77,7 @@ module Sigh
77
77
  short_option: "-u",
78
78
  env_name: "SIGH_USERNAME",
79
79
  description: "Your Apple ID Username",
80
+ optional: true,
80
81
  default_value: user,
81
82
  default_value_dynamic: true),
82
83
  FastlaneCore::ConfigItem.new(key: :team_id,
@@ -21,6 +21,10 @@ module Sigh
21
21
  UI.message("Creating authorization token for App Store Connect API")
22
22
  Spaceship::ConnectAPI.token = api_token
23
23
  else
24
+ # Username is now optional since addition of App Store Connect API Key
25
+ # Force asking for username to prompt user if not already set
26
+ Sigh.config.fetch(:username, force_ask: true)
27
+
24
28
  # Team selection passed though FASTLANE_ITC_TEAM_ID and FASTLANE_ITC_TEAM_NAME environment variables
25
29
  # Prompts select team if multiple teams and none specified
26
30
  UI.message("Starting login with user '#{Sigh.config[:username]}'")
@@ -60,7 +64,7 @@ module Sigh
60
64
  end
61
65
 
62
66
  def api_token
63
- @api_token ||= Spaceship::ConnectAPI::Token.create(Sigh.config[:api_key]) if Sigh.config[:api_key]
67
+ @api_token ||= Spaceship::ConnectAPI::Token.create(**Sigh.config[:api_key]) if Sigh.config[:api_key]
64
68
  @api_token ||= Spaceship::ConnectAPI::Token.from_json_file(Sigh.config[:api_key_path]) if Sigh.config[:api_key_path]
65
69
  return @api_token
66
70
  end
@@ -69,7 +69,8 @@ module Snapshot
69
69
  unless launcher_config.dark_mode.nil?
70
70
  interface_style(type, launcher_config.dark_mode)
71
71
  end
72
- elsif launcher_config.reinstall_app
72
+ end
73
+ if launcher_config.reinstall_app && !launcher_config.erase_simulator
73
74
  # no need to reinstall if device has been erased
74
75
  uninstall_app(type)
75
76
  end
data/spaceship/README.md CHANGED
@@ -83,7 +83,7 @@ Using spaceship, the execution time of [_sigh_](https://docs.fastlane.tools/acti
83
83
 
84
84
  _spaceship_ is part of _fastlane_:
85
85
 
86
- sudo gem install fastlane
86
+ gem install fastlane
87
87
 
88
88
  # Usage
89
89
 
@@ -93,7 +93,7 @@ To try _spaceship_, just run `fastlane spaceship`. It will automatically start t
93
93
 
94
94
  ![assets/docs/Playground.png](assets/docs/Playground.png)
95
95
 
96
- This requires you to install `pry` using `sudo gem install pry`. `pry` is not installed by default, as most [_fastlane_](https://fastlane.tools) users won't need the `spaceship playground`. You can add the `pry` dependency to your `Gemfile`.
96
+ This requires you to install `pry` using `gem install pry`. `pry` is not installed by default, as most [_fastlane_](https://fastlane.tools) users won't need the `spaceship playground`. You can add the `pry` dependency to your `Gemfile`.
97
97
 
98
98
  ## Apple Developer Portal API
99
99
 
@@ -134,7 +134,7 @@ module Spaceship
134
134
  if teams.count > 1
135
135
  puts("The current user is in #{teams.count} teams. Pass a team ID or call `select_team` to choose a team. Using the first one for now.")
136
136
  end
137
- @current_team_id ||= teams[0]['contentProvider']['contentProviderId']
137
+ @current_team_id ||= user_details_data['sessionToken']['contentProviderId']
138
138
  end
139
139
 
140
140
  # Set a new team ID which will be used from now on
@@ -171,6 +171,9 @@ module Spaceship
171
171
 
172
172
  handle_itc_response(response.body)
173
173
 
174
+ # clear user_details_data cache, as session switch will have changed sessionToken attribute
175
+ @_cached_user_details = nil
176
+
174
177
  @current_team_id = team_id
175
178
  end
176
179
 
@@ -880,10 +883,7 @@ module Spaceship
880
883
  response = @client.send(method, url_or_path, params, headers, &block)
881
884
  log_response(method, url_or_path, response, headers, &block)
882
885
 
883
- resp_hash = response.to_hash
884
- if resp_hash[:status] == 401
885
- handle_401(response)
886
- end
886
+ handle_error(response)
887
887
 
888
888
  if response.body.to_s.include?("<title>302 Found</title>")
889
889
  raise AppleTimeoutError.new, "Apple 302 detected - this might be temporary server error, check https://developer.apple.com/system-status/ to see if there is a known downtime"
@@ -893,22 +893,23 @@ module Spaceship
893
893
  raise BadGatewayError.new, "Apple 502 detected - this might be temporary server error, try again later"
894
894
  end
895
895
 
896
- if resp_hash[:status] == 403
897
- msg = "Access forbidden"
898
- logger.warn(msg)
899
- raise AccessForbiddenError.new, msg
900
- elsif resp_hash[:status] == 429
901
- raise TooManyRequestsError, resp_hash
902
- end
903
-
904
896
  return response
905
897
  end
906
898
  end
907
899
 
908
- def handle_401(response)
909
- msg = "Auth lost"
910
- logger.warn(msg)
911
- raise UnauthorizedAccessError.new, "Unauthorized Access"
900
+ def handle_error(response)
901
+ case response.status
902
+ when 401
903
+ msg = "Auth lost"
904
+ logger.warn(msg)
905
+ raise UnauthorizedAccessError.new, "Unauthorized Access"
906
+ when 403
907
+ msg = "Access forbidden"
908
+ logger.warn(msg)
909
+ raise AccessForbiddenError.new, msg
910
+ when 429
911
+ raise TooManyRequestsError, response.to_hash
912
+ end
912
913
  end
913
914
 
914
915
  def send_request_auto_paginate(method, url_or_path, params, headers, &block)
@@ -150,6 +150,12 @@ module Spaceship
150
150
 
151
151
  protected
152
152
 
153
+ class TimeoutRetryError < StandardError
154
+ def initialize(msg)
155
+ super
156
+ end
157
+ end
158
+
153
159
  def with_asc_retry(tries = 5, &_block)
154
160
  tries = 1 if Object.const_defined?("SpecHelper")
155
161
 
@@ -159,7 +165,7 @@ module Spaceship
159
165
 
160
166
  if [500, 504].include?(status)
161
167
  msg = "Timeout received! Retrying after 3 seconds (remaining: #{tries})..."
162
- raise msg
168
+ raise TimeoutRetryError, msg
163
169
  end
164
170
 
165
171
  return response
@@ -167,7 +173,7 @@ module Spaceship
167
173
  # Catch unathorized access and re-raising
168
174
  # There is no need to try again
169
175
  raise error
170
- rescue => error
176
+ rescue TimeoutRetryError => error
171
177
  tries -= 1
172
178
  puts(error) if Spaceship::Globals.verbose?
173
179
  if tries.zero?
@@ -190,7 +196,7 @@ module Spaceship
190
196
 
191
197
  raise UnexpectedResponse, response.body['error'] if response.body['error']
192
198
 
193
- raise UnexpectedResponse, handle_errors(response) if response.body['errors']
199
+ raise UnexpectedResponse, format_errors(response) if response.body['errors']
194
200
 
195
201
  raise UnexpectedResponse, "Temporary App Store Connect error: #{response.body}" if response.body['statusCode'] == 'ERROR'
196
202
 
@@ -199,11 +205,23 @@ module Spaceship
199
205
  return Spaceship::ConnectAPI::Response.new(body: response.body, status: response.status, headers: response.headers, client: self)
200
206
  end
201
207
 
202
- def handle_401(response)
203
- raise UnauthorizedAccessError, handle_errors(response) if response && (response.body || {})['errors']
208
+ # Overridden from Spaceship::Client
209
+ def handle_error(response)
210
+ case response.status.to_i
211
+ when 401
212
+ raise UnauthorizedAccessError, format_errors(response) if response && (response.body || {})['errors']
213
+ when 403
214
+ error = (response.body['errors'] || []).first || {}
215
+ error_code = error['code']
216
+ if error_code == "FORBIDDEN.REQUIRED_AGREEMENTS_MISSING_OR_EXPIRED"
217
+ raise ProgramLicenseAgreementUpdated, format_errors(response) if response && (response.body || {})['errors']
218
+ else
219
+ raise AccessForbiddenError, format_errors(response) if response && (response.body || {})['errors']
220
+ end
221
+ end
204
222
  end
205
223
 
206
- def handle_errors(response)
224
+ def format_errors(response)
207
225
  # Example error format
208
226
  # {
209
227
  # "errors":[