fastlane 2.147.0 → 2.150.0.rc1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (141) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +82 -82
  3. data/cert/lib/cert/commands_generator.rb +1 -0
  4. data/credentials_manager/lib/credentials_manager/cli.rb +2 -0
  5. data/deliver/lib/deliver.rb +0 -1
  6. data/deliver/lib/deliver/app_screenshot.rb +28 -27
  7. data/deliver/lib/deliver/commands_generator.rb +1 -0
  8. data/deliver/lib/deliver/html_generator.rb +2 -2
  9. data/deliver/lib/deliver/options.rb +6 -11
  10. data/deliver/lib/deliver/runner.rb +7 -4
  11. data/deliver/lib/deliver/setup.rb +5 -30
  12. data/deliver/lib/deliver/submit_for_review.rb +124 -83
  13. data/deliver/lib/deliver/upload_metadata.rb +284 -143
  14. data/deliver/lib/deliver/upload_price_tier.rb +15 -8
  15. data/deliver/lib/deliver/upload_screenshots.rb +86 -37
  16. data/fastlane/lib/assets/s3_html_template.erb +1 -1
  17. data/fastlane/lib/fastlane/actions/crashlytics.rb +0 -4
  18. data/fastlane/lib/fastlane/actions/docs/build_app.md +1 -1
  19. data/fastlane/lib/fastlane/actions/docs/capture_android_screenshots.md +42 -2
  20. data/fastlane/lib/fastlane/actions/docs/capture_ios_screenshots.md +1 -1
  21. data/fastlane/lib/fastlane/actions/docs/sync_code_signing.md +2 -2
  22. data/fastlane/lib/fastlane/actions/docs/upload_to_app_store.md.erb +3 -11
  23. data/fastlane/lib/fastlane/actions/docs/upload_to_play_store.md +15 -2
  24. data/fastlane/lib/fastlane/actions/download_dsyms.rb +7 -1
  25. data/fastlane/lib/fastlane/actions/get_managed_play_store_publishing_rights.rb +1 -1
  26. data/fastlane/lib/fastlane/actions/google_play_track_release_names.rb +74 -0
  27. data/fastlane/lib/fastlane/actions/hipchat.rb +1 -1
  28. data/fastlane/lib/fastlane/actions/push_to_git_remote.rb +1 -1
  29. data/fastlane/lib/fastlane/actions/slack.rb +2 -2
  30. data/fastlane/lib/fastlane/actions/slather.rb +8 -1
  31. data/fastlane/lib/fastlane/actions/spm.rb +7 -0
  32. data/fastlane/lib/fastlane/actions/swiftlint.rb +14 -0
  33. data/fastlane/lib/fastlane/actions/sync_code_signing.rb +1 -1
  34. data/fastlane/lib/fastlane/actions/upload_symbols_to_crashlytics.rb +3 -34
  35. data/fastlane/lib/fastlane/actions/xcodebuild.rb +4 -4
  36. data/fastlane/lib/fastlane/cli_tools_distributor.rb +28 -6
  37. data/fastlane/lib/fastlane/commands_generator.rb +1 -1
  38. data/fastlane/lib/fastlane/documentation/actions_list.rb +1 -1
  39. data/fastlane/lib/fastlane/lane.rb +3 -3
  40. data/fastlane/lib/fastlane/lane_manager.rb +0 -10
  41. data/fastlane/lib/fastlane/plugins/plugin_manager.rb +3 -3
  42. data/fastlane/lib/fastlane/plugins/template/.github/workflows/test.yml +29 -0
  43. data/fastlane/lib/fastlane/swift_fastlane_function.rb +22 -5
  44. data/fastlane/lib/fastlane/swift_lane_manager.rb +0 -8
  45. data/fastlane/lib/fastlane/version.rb +1 -1
  46. data/fastlane/swift/ControlCommand.swift +1 -0
  47. data/fastlane/swift/Deliverfile.swift +1 -1
  48. data/fastlane/swift/Fastlane.swift +140 -30
  49. data/fastlane/swift/FastlaneSwiftRunner/FastlaneSwiftRunner.xcodeproj/xcshareddata/xcschemes/FastlaneRunner.xcscheme +3 -9
  50. data/fastlane/swift/Gymfile.swift +1 -1
  51. data/fastlane/swift/GymfileProtocol.swift +1 -1
  52. data/fastlane/swift/Matchfile.swift +1 -1
  53. data/fastlane/swift/MatchfileProtocol.swift +5 -1
  54. data/fastlane/swift/Precheckfile.swift +1 -1
  55. data/fastlane/swift/RubyCommand.swift +29 -6
  56. data/fastlane/swift/RubyCommandable.swift +1 -0
  57. data/fastlane/swift/Runner.swift +85 -13
  58. data/fastlane/swift/Scanfile.swift +1 -1
  59. data/fastlane/swift/ScanfileProtocol.swift +10 -2
  60. data/fastlane/swift/Screengrabfile.swift +1 -1
  61. data/fastlane/swift/Snapshotfile.swift +1 -1
  62. data/fastlane/swift/SnapshotfileProtocol.swift +17 -1
  63. data/fastlane/swift/SocketClient.swift +76 -45
  64. data/fastlane/swift/SocketClientDelegateProtocol.swift +1 -1
  65. data/fastlane/swift/SocketResponse.swift +1 -0
  66. data/fastlane_core/lib/fastlane_core/configuration/config_item.rb +1 -3
  67. data/fastlane_core/lib/fastlane_core/pkg_file_analyser.rb +7 -0
  68. data/frameit/lib/frameit/commands_generator.rb +1 -0
  69. data/frameit/lib/frameit/device_types.rb +100 -100
  70. data/gym/lib/gym/generators/package_command_generator.rb +4 -0
  71. data/gym/lib/gym/generators/package_command_generator_xcode7.rb +4 -0
  72. data/gym/lib/gym/options.rb +1 -1
  73. data/gym/lib/gym/runner.rb +14 -0
  74. data/match/lib/match/commands_generator.rb +1 -0
  75. data/match/lib/match/generator.rb +2 -1
  76. data/match/lib/match/nuke.rb +21 -16
  77. data/match/lib/match/options.rb +18 -1
  78. data/match/lib/match/storage/git_storage.rb +4 -0
  79. data/match/lib/match/storage/google_cloud_storage.rb +4 -0
  80. data/match/lib/match/storage/interface.rb +4 -0
  81. data/match/lib/match/storage/s3_storage.rb +4 -0
  82. data/pem/lib/pem/commands_generator.rb +1 -0
  83. data/pilot/lib/pilot/build_manager.rb +23 -7
  84. data/pilot/lib/pilot/options.rb +5 -0
  85. data/produce/lib/produce/commands_generator.rb +1 -0
  86. data/produce/lib/produce/itunes_connect.rb +20 -20
  87. data/produce/lib/produce/options.rb +3 -3
  88. data/scan/lib/scan/detect_values.rb +3 -0
  89. data/scan/lib/scan/options.rb +20 -2
  90. data/scan/lib/scan/test_command_generator.rb +6 -1
  91. data/scan/lib/scan/test_result_parser.rb +9 -2
  92. data/screengrab/lib/screengrab/runner.rb +10 -9
  93. data/sigh/lib/assets/resign.sh +7 -7
  94. data/sigh/lib/sigh/commands_generator.rb +1 -0
  95. data/sigh/lib/sigh/options.rb +7 -1
  96. data/sigh/lib/sigh/runner.rb +2 -1
  97. data/snapshot/lib/assets/SnapshotHelper.swift +16 -37
  98. data/snapshot/lib/assets/SnapshotHelperXcode8.swift +3 -3
  99. data/snapshot/lib/snapshot/detect_values.rb +15 -0
  100. data/snapshot/lib/snapshot/options.rb +31 -0
  101. data/snapshot/lib/snapshot/reports_generator.rb +8 -1
  102. data/snapshot/lib/snapshot/simulator_launchers/simulator_launcher_base.rb +3 -1
  103. data/snapshot/lib/snapshot/test_command_generator.rb +8 -3
  104. data/snapshot/lib/snapshot/test_command_generator_base.rb +7 -1
  105. data/spaceship/lib/spaceship/.DS_Store +0 -0
  106. data/spaceship/lib/spaceship/client.rb +9 -1
  107. data/spaceship/lib/spaceship/commands_generator.rb +1 -0
  108. data/spaceship/lib/spaceship/connect_api.rb +21 -2
  109. data/spaceship/lib/spaceship/connect_api/client.rb +47 -11
  110. data/spaceship/lib/spaceship/connect_api/model.rb +1 -1
  111. data/spaceship/lib/spaceship/connect_api/models/age_rating_declaration.rb +109 -0
  112. data/spaceship/lib/spaceship/connect_api/models/app.rb +113 -3
  113. data/spaceship/lib/spaceship/connect_api/models/app_category.rb +94 -0
  114. data/spaceship/lib/spaceship/connect_api/models/app_info.rb +74 -0
  115. data/spaceship/lib/spaceship/connect_api/models/app_info_localization.rb +38 -0
  116. data/spaceship/lib/spaceship/connect_api/models/app_price.rb +22 -0
  117. data/spaceship/lib/spaceship/connect_api/models/app_price_tier.rb +12 -0
  118. data/spaceship/lib/spaceship/connect_api/models/app_review_attachment.rb +81 -0
  119. data/spaceship/lib/spaceship/connect_api/models/app_screenshot.rb +117 -0
  120. data/spaceship/lib/spaceship/connect_api/models/app_screenshot_set.rb +101 -0
  121. data/spaceship/lib/spaceship/connect_api/models/app_store_review_detail.rb +51 -0
  122. data/spaceship/lib/spaceship/connect_api/models/app_store_version.rb +182 -0
  123. data/spaceship/lib/spaceship/connect_api/models/app_store_version_localization.rb +70 -0
  124. data/spaceship/lib/spaceship/connect_api/models/app_store_version_phased_release.rb +36 -0
  125. data/spaceship/lib/spaceship/connect_api/models/app_store_version_submission.rb +26 -0
  126. data/spaceship/lib/spaceship/connect_api/models/build.rb +8 -0
  127. data/spaceship/lib/spaceship/connect_api/models/idfa_declaration.rb +40 -0
  128. data/spaceship/lib/spaceship/connect_api/models/reset_ratings_request.rb +26 -0
  129. data/spaceship/lib/spaceship/connect_api/testflight/testflight.rb +10 -3
  130. data/spaceship/lib/spaceship/connect_api/tunes/client.rb +33 -0
  131. data/spaceship/lib/spaceship/connect_api/tunes/tunes.rb +703 -0
  132. data/spaceship/lib/spaceship/errors.rb +3 -0
  133. data/spaceship/lib/spaceship/spaceauth_runner.rb +2 -2
  134. data/supply/lib/supply/client.rb +19 -0
  135. data/supply/lib/supply/commands_generator.rb +1 -0
  136. data/supply/lib/supply/options.rb +9 -0
  137. data/supply/lib/supply/reader.rb +16 -0
  138. data/supply/lib/supply/uploader.rb +4 -0
  139. metadata +52 -47
  140. data/deliver/lib/deliver/upload_assets.rb +0 -27
  141. data/supply/lib/supply/.client.rb.swp +0 -0
@@ -26,6 +26,7 @@ module Sigh
26
26
  program :help_formatter, :compact
27
27
 
28
28
  global_option('--verbose') { FastlaneCore::Globals.verbose = true }
29
+ global_option('--env STRING[,STRING2]', String, 'Add environment(s) to use with `dotenv`')
29
30
 
30
31
  command :renew do |c|
31
32
  c.syntax = 'fastlane sigh renew'
@@ -153,7 +153,13 @@ module Sigh
153
153
  env_name: "SIGH_PROVISIONING_PROFILE_TEMPLATE_NAME",
154
154
  description: "The name of provisioning profile template. If the developer account has provisioning profile templates (aka: custom entitlements), the template name can be found by inspecting the Entitlements drop-down while creating/editing a provisioning profile (e.g. \"Apple Pay Pass Suppression Development\")",
155
155
  optional: true,
156
- default_value: nil)
156
+ default_value: nil),
157
+ FastlaneCore::ConfigItem.new(key: :fail_on_name_taken,
158
+ env_name: "SIGH_FAIL_ON_NAME_TAKEN",
159
+ description: "Should the command fail if it was about to create a duplicate of an existing provisioning profile. It can happen due to issues on Apple Developer Portal, when profile to be recreated was not properly deleted first",
160
+ optional: true,
161
+ is_string: false,
162
+ default_value: false)
157
163
  ]
158
164
  end
159
165
  end
@@ -125,7 +125,8 @@ module Sigh
125
125
  name = Sigh.config[:provisioning_name] || [bundle_id, profile_type.pretty_type].join(' ')
126
126
 
127
127
  unless Sigh.config[:skip_fetch_profiles]
128
- if Spaceship.provisioning_profile.all.find { |p| p.name == name }
128
+ if Spaceship.provisioning_profile.all(mac: Sigh.config[:platform].to_s == 'macos').find { |p| p.name == name }
129
+ UI.user_error!("The name '#{name}' is already taken, and fail_on_name_taken is true") if Sigh.config[:fail_on_name_taken]
129
130
  UI.error("The name '#{name}' is already taken, using another one.")
130
131
  name += " #{Time.now.to_i}"
131
132
  end
@@ -38,22 +38,13 @@ func snapshot(_ name: String, timeWaitingForIdle timeout: TimeInterval = 20) {
38
38
  }
39
39
 
40
40
  enum SnapshotError: Error, CustomDebugStringConvertible {
41
- case cannotDetectUser
42
- case cannotFindHomeDirectory
43
41
  case cannotFindSimulatorHomeDirectory
44
- case cannotAccessSimulatorHomeDirectory(String)
45
42
  case cannotRunOnPhysicalDevice
46
43
 
47
44
  var debugDescription: String {
48
45
  switch self {
49
- case .cannotDetectUser:
50
- return "Couldn't find Snapshot configuration files - can't detect current user "
51
- case .cannotFindHomeDirectory:
52
- return "Couldn't find Snapshot configuration files - can't detect `Users` dir"
53
46
  case .cannotFindSimulatorHomeDirectory:
54
47
  return "Couldn't find simulator home location. Please, check SIMULATOR_HOST_HOME env variable."
55
- case .cannotAccessSimulatorHomeDirectory(let simulatorHostHome):
56
- return "Can't prepare environment. Simulator home location is inaccessible. Does \(simulatorHostHome) exist?"
57
48
  case .cannotRunOnPhysicalDevice:
58
49
  return "Can't use Snapshot on a physical device."
59
50
  }
@@ -75,7 +66,7 @@ open class Snapshot: NSObject {
75
66
  Snapshot.waitForAnimations = waitForAnimations
76
67
 
77
68
  do {
78
- let cacheDir = try pathPrefix()
69
+ let cacheDir = try getCacheDirectory()
79
70
  Snapshot.cacheDirectory = cacheDir
80
71
  setLanguage(app)
81
72
  setLocale(app)
@@ -206,40 +197,28 @@ open class Snapshot: NSObject {
206
197
  _ = XCTWaiter.wait(for: [networkLoadingIndicatorDisappeared], timeout: timeout)
207
198
  }
208
199
 
209
- class func pathPrefix() throws -> URL? {
210
- let homeDir: URL
200
+ class func getCacheDirectory() throws -> URL {
201
+ let cachePath = "Library/Caches/tools.fastlane"
211
202
  // on OSX config is stored in /Users/<username>/Library
212
203
  // and on iOS/tvOS/WatchOS it's in simulator's home dir
213
204
  #if os(OSX)
214
- guard let user = ProcessInfo().environment["USER"] else {
215
- throw SnapshotError.cannotDetectUser
205
+ let homeDir = URL(fileURLWithPath: NSHomeDirectory())
206
+ return homeDir.appendingPathComponent(cachePath)
207
+ #elseif arch(i386) || arch(x86_64)
208
+ guard let simulatorHostHome = ProcessInfo().environment["SIMULATOR_HOST_HOME"] else {
209
+ throw SnapshotError.cannotFindSimulatorHomeDirectory
216
210
  }
217
-
218
- guard let usersDir = FileManager.default.urls(for: .userDirectory, in: .localDomainMask).first else {
219
- throw SnapshotError.cannotFindHomeDirectory
220
- }
221
-
222
- homeDir = usersDir.appendingPathComponent(user)
211
+ let homeDir = URL(fileURLWithPath: simulatorHostHome)
212
+ return homeDir.appendingPathComponent(cachePath)
223
213
  #else
224
- #if arch(i386) || arch(x86_64)
225
- guard let simulatorHostHome = ProcessInfo().environment["SIMULATOR_HOST_HOME"] else {
226
- throw SnapshotError.cannotFindSimulatorHomeDirectory
227
- }
228
- guard let homeDirUrl = URL(string: simulatorHostHome) else {
229
- throw SnapshotError.cannotAccessSimulatorHomeDirectory(simulatorHostHome)
230
- }
231
- homeDir = URL(fileURLWithPath: homeDirUrl.path)
232
- #else
233
- throw SnapshotError.cannotRunOnPhysicalDevice
234
- #endif
214
+ throw SnapshotError.cannotRunOnPhysicalDevice
235
215
  #endif
236
- return homeDir.appendingPathComponent("Library/Caches/tools.fastlane")
237
216
  }
238
217
  }
239
218
 
240
219
  private extension XCUIElementAttributes {
241
220
  var isNetworkLoadingIndicator: Bool {
242
- if hasWhiteListedIdentifier { return false }
221
+ if hasAllowListedIdentifier { return false }
243
222
 
244
223
  let hasOldLoadingIndicatorSize = frame.size == CGSize(width: 10, height: 20)
245
224
  let hasNewLoadingIndicatorSize = frame.size.width.isBetween(46, and: 47) && frame.size.height.isBetween(2, and: 3)
@@ -247,10 +226,10 @@ private extension XCUIElementAttributes {
247
226
  return hasOldLoadingIndicatorSize || hasNewLoadingIndicatorSize
248
227
  }
249
228
 
250
- var hasWhiteListedIdentifier: Bool {
251
- let whiteListedIdentifiers = ["GeofenceLocationTrackingOn", "StandardLocationTrackingOn"]
229
+ var hasAllowListedIdentifier: Bool {
230
+ let allowListedIdentifiers = ["GeofenceLocationTrackingOn", "StandardLocationTrackingOn"]
252
231
 
253
- return whiteListedIdentifiers.contains(identifier)
232
+ return allowListedIdentifiers.contains(identifier)
254
233
  }
255
234
 
256
235
  func isStatusBar(_ deviceWidth: CGFloat) -> Bool {
@@ -300,4 +279,4 @@ private extension CGFloat {
300
279
 
301
280
  // Please don't remove the lines below
302
281
  // They are used to detect outdated configuration files
303
- // SnapshotHelperVersion [1.21]
282
+ // SnapshotHelperVersion [1.23]
@@ -159,8 +159,8 @@ open class Snapshot: NSObject {
159
159
 
160
160
  extension XCUIElement {
161
161
  var isLoadingIndicator: Bool {
162
- let whiteListedLoaders = ["GeofenceLocationTrackingOn", "StandardLocationTrackingOn"]
163
- if whiteListedLoaders.contains(self.identifier) {
162
+ let allowListedLoaders = ["GeofenceLocationTrackingOn", "StandardLocationTrackingOn"]
163
+ if allowListedLoaders.contains(self.identifier) {
164
164
  return false
165
165
  }
166
166
  return self.frame.size == CGSize(width: 10, height: 20)
@@ -169,4 +169,4 @@ extension XCUIElement {
169
169
 
170
170
  // Please don't remove the lines below
171
171
  // They are used to detect outdated configuration files
172
- // SnapshotHelperXcode8Version [1.4]
172
+ // SnapshotHelperXcode8Version [1.5]
@@ -30,6 +30,9 @@ module Snapshot
30
30
 
31
31
  Snapshot.project.select_scheme(preferred_to_include: "UITests")
32
32
 
33
+ coerce_to_array_of_strings(:only_testing)
34
+ coerce_to_array_of_strings(:skip_testing)
35
+
33
36
  # Devices
34
37
  if config[:devices].nil? && !Snapshot.project.mac?
35
38
  config[:devices] = []
@@ -67,5 +70,17 @@ module Snapshot
67
70
  config[:devices] = ["Mac"]
68
71
  end
69
72
  end
73
+
74
+ def self.coerce_to_array_of_strings(config_key)
75
+ config_value = Snapshot.config[config_key]
76
+
77
+ return if config_value.nil?
78
+
79
+ # splitting on comma allows us to support comma-separated lists of values
80
+ # from the command line, even though the ConfigItem is not defined as an
81
+ # Array type
82
+ config_value = config_value.split(',') unless config_value.kind_of?(Array)
83
+ Snapshot.config[config_key] = config_value.map(&:to_s)
84
+ end
70
85
  end
71
86
  end
@@ -5,6 +5,11 @@ require_relative 'module'
5
5
 
6
6
  module Snapshot
7
7
  class Options
8
+ def self.verify_type(item_name, acceptable_types, value)
9
+ type_ok = [Array, String].any? { |type| value.kind_of?(type) }
10
+ UI.user_error!("'#{item_name}' should be of type #{acceptable_types.join(' or ')} but found: #{value.class.name}") unless type_ok
11
+ end
12
+
8
13
  def self.available_options
9
14
  output_directory = (File.directory?("fastlane") ? "fastlane/screenshots" : "screenshots")
10
15
 
@@ -147,6 +152,11 @@ module Snapshot
147
152
  description: "A list of videos that should be added to the simulator before running the application",
148
153
  type: Array,
149
154
  optional: true),
155
+ FastlaneCore::ConfigItem.new(key: :html_template,
156
+ env_name: 'SNAPSHOT_HTML_TEMPLATE',
157
+ short_option: "-e",
158
+ description: "A path to screenshots.html template",
159
+ optional: true),
150
160
 
151
161
  # Everything around building
152
162
  FastlaneCore::ConfigItem.new(key: :buildlog_path,
@@ -242,6 +252,27 @@ module Snapshot
242
252
  env_name: "SNAPSHOT_TESTPLAN",
243
253
  description: "The testplan associated with the scheme that should be used for testing",
244
254
  is_string: true,
255
+ optional: true),
256
+ FastlaneCore::ConfigItem.new(key: :only_testing,
257
+ env_name: "SNAPSHOT_ONLY_TESTING",
258
+ description: "Array of strings matching Test Bundle/Test Suite/Test Cases to run",
259
+ optional: true,
260
+ is_string: false,
261
+ verify_block: proc do |value|
262
+ verify_type('only_testing', [Array, String], value)
263
+ end),
264
+ FastlaneCore::ConfigItem.new(key: :skip_testing,
265
+ env_name: "SNAPSHOT_SKIP_TESTING",
266
+ description: "Array of strings matching Test Bundle/Test Suite/Test Cases to skip",
267
+ optional: true,
268
+ is_string: false,
269
+ verify_block: proc do |value|
270
+ verify_type('skip_testing', [Array, String], value)
271
+ end),
272
+ FastlaneCore::ConfigItem.new(key: :disable_xcpretty,
273
+ env_name: "SNAPSHOT_DISABLE_XCPRETTY",
274
+ description: "Disable xcpretty formatting of build",
275
+ type: Boolean,
245
276
  optional: true)
246
277
  ]
247
278
  end
@@ -5,6 +5,14 @@ module Snapshot
5
5
  require 'erb'
6
6
  require 'fastimage'
7
7
 
8
+ def html_path
9
+ if Snapshot.config[:html_template]
10
+ Snapshot.config[:html_template]
11
+ else
12
+ File.join(Snapshot::ROOT, "lib", "snapshot/page.html.erb")
13
+ end
14
+ end
15
+
8
16
  def generate
9
17
  UI.message("Generating HTML Report")
10
18
 
@@ -36,7 +44,6 @@ module Snapshot
36
44
  end
37
45
  end
38
46
 
39
- html_path = File.join(Snapshot::ROOT, "lib", "snapshot/page.html.erb")
40
47
  html = ERB.new(File.read(html_path)).result(binding) # https://web.archive.org/web/20160430190141/www.rrn.dk/rubys-erb-templating-system
41
48
 
42
49
  export_path = "#{screens_path}/screenshots.html"
@@ -59,7 +59,9 @@ module Snapshot
59
59
 
60
60
  device_types.each do |type|
61
61
  if launcher_config.erase_simulator || launcher_config.localize_simulator || !launcher_config.dark_mode.nil?
62
- erase_simulator(type)
62
+ if launcher_config.erase_simulator
63
+ erase_simulator(type)
64
+ end
63
65
  if launcher_config.localize_simulator
64
66
  localize_simulator(type, language, locale)
65
67
  end
@@ -16,20 +16,25 @@ module Snapshot
16
16
  parts += build_settings
17
17
  parts += actions
18
18
  parts += suffix
19
- parts += pipe(language: language, locale: locale, log_path: log_path)
19
+ parts += pipe(log_path: log_path)
20
20
 
21
21
  return parts
22
22
  end
23
23
 
24
- def pipe(language: nil, locale: nil, log_path: nil)
24
+ def pipe(log_path: nil)
25
25
  tee_command = ['tee']
26
26
  tee_command << '-a' if log_path && File.exist?(log_path)
27
27
  tee_command << log_path.shellescape if log_path
28
28
 
29
+ pipe = ["| #{tee_command.join(' ')}"]
30
+ if Snapshot.config[:disable_xcpretty]
31
+ return pipe
32
+ end
33
+
29
34
  xcpretty = "xcpretty #{Snapshot.config[:xcpretty_args]}"
30
35
  xcpretty << "--no-color" if Helper.colors_disabled?
31
36
 
32
- return ["| #{tee_command.join(' ')} | #{xcpretty}"]
37
+ return pipe << "| #{xcpretty}"
33
38
  end
34
39
 
35
40
  def destination(devices)
@@ -30,6 +30,11 @@ module Snapshot
30
30
  options << "-testPlan '#{config[:testplan]}'" if config[:testplan]
31
31
  end
32
32
  options << config[:xcargs] if config[:xcargs]
33
+
34
+ # detect_values will ensure that these values are present as Arrays if
35
+ # they are present at all
36
+ options += config[:only_testing].map { |test_id| "-only-testing:#{test_id.shellescape}" } if config[:only_testing]
37
+ options += config[:skip_testing].map { |test_id| "-skip-testing:#{test_id.shellescape}" } if config[:skip_testing]
33
38
  return options
34
39
  end
35
40
 
@@ -91,7 +96,8 @@ module Snapshot
91
96
  language_key = locale || language
92
97
 
93
98
  unless Snapshot.cache[:result_bundle_path][language_key]
94
- path = File.join(Snapshot.config[:output_directory], "test_output", language_key, Snapshot.config[:scheme]) + ".test_result"
99
+ ext = FastlaneCore::Helper.xcode_at_least?(11) ? '.xcresult' : '.test_result'
100
+ path = File.join(Snapshot.config[:output_directory], "test_output", language_key, Snapshot.config[:scheme]) + ext
95
101
  if File.directory?(path)
96
102
  FileUtils.remove_dir(path)
97
103
  end
@@ -54,6 +54,7 @@ module Spaceship
54
54
  GatewayTimeoutError = Spaceship::GatewayTimeoutError
55
55
  InternalServerError = Spaceship::InternalServerError
56
56
  BadGatewayError = Spaceship::BadGatewayError
57
+ AccessForbiddenError = Spaceship::AccessForbiddenError
57
58
 
58
59
  def self.hostname
59
60
  raise "You must implement self.hostname"
@@ -628,7 +629,8 @@ module Spaceship
628
629
  Faraday::TimeoutError,
629
630
  BadGatewayError,
630
631
  AppleTimeoutError,
631
- GatewayTimeoutError => ex
632
+ GatewayTimeoutError,
633
+ AccessForbiddenError => ex
632
634
  tries -= 1
633
635
  unless tries.zero?
634
636
  msg = "Timeout received: '#{ex.class}', '#{ex.message}'. Retrying after 3 seconds (remaining: #{tries})..."
@@ -865,6 +867,12 @@ module Spaceship
865
867
  raise BadGatewayError.new, "Apple 502 detected - this might be temporary server error, try again later"
866
868
  end
867
869
 
870
+ if resp_hash[:status] == 403
871
+ msg = "Access forbidden"
872
+ logger.warn(msg)
873
+ raise AccessForbiddenError.new, msg
874
+ end
875
+
868
876
  return response
869
877
  end
870
878
  end
@@ -25,6 +25,7 @@ module Spaceship
25
25
 
26
26
  global_option('-u', '--user USERNAME', 'Specify the Apple ID you want to log in with')
27
27
  global_option('--verbose') { FastlaneCore::Globals.verbose = true }
28
+ global_option('--env STRING[,STRING2]', String, 'Add environment(s) to use with `dotenv`')
28
29
 
29
30
  command :playground do |c|
30
31
  c.syntax = 'fastlane spaceship playground'
@@ -5,6 +5,7 @@ require 'spaceship/connect_api/token'
5
5
  require 'spaceship/connect_api/provisioning/provisioning'
6
6
  require 'spaceship/connect_api/testflight/testflight'
7
7
  require 'spaceship/connect_api/users/users'
8
+ require 'spaceship/connect_api/tunes/tunes'
8
9
 
9
10
  require 'spaceship/connect_api/models/bundle_id_capability'
10
11
  require 'spaceship/connect_api/models/bundle_id'
@@ -30,11 +31,29 @@ require 'spaceship/connect_api/models/build_delivery'
30
31
  require 'spaceship/connect_api/models/build_beta_detail'
31
32
  require 'spaceship/connect_api/models/pre_release_version'
32
33
 
34
+ require 'spaceship/connect_api/models/age_rating_declaration'
35
+ require 'spaceship/connect_api/models/app_category'
36
+ require 'spaceship/connect_api/models/app_info'
37
+ require 'spaceship/connect_api/models/app_info_localization'
38
+ require 'spaceship/connect_api/models/app_price'
39
+ require 'spaceship/connect_api/models/app_price_tier'
40
+ require 'spaceship/connect_api/models/app_review_attachment'
41
+ require 'spaceship/connect_api/models/app_store_review_detail'
42
+ require 'spaceship/connect_api/models/app_store_version_submission'
43
+ require 'spaceship/connect_api/models/app_screenshot_set'
44
+ require 'spaceship/connect_api/models/app_screenshot'
45
+ require 'spaceship/connect_api/models/app_store_version_localization'
46
+ require 'spaceship/connect_api/models/app_store_version_phased_release'
47
+ require 'spaceship/connect_api/models/app_store_version'
48
+ require 'spaceship/connect_api/models/idfa_declaration'
49
+ require 'spaceship/connect_api/models/reset_ratings_request'
50
+
33
51
  module Spaceship
34
52
  class ConnectAPI
35
53
  extend Spaceship::ConnectAPI::Provisioning
36
54
  extend Spaceship::ConnectAPI::TestFlight
37
55
  extend Spaceship::ConnectAPI::Users
56
+ extend Spaceship::ConnectAPI::Tunes
38
57
 
39
58
  @token = nil
40
59
 
@@ -63,9 +82,9 @@ module Spaceship
63
82
 
64
83
  # Map from fastlane input and Spaceship::TestFlight platform values
65
84
  case platform.to_sym
66
- when :appletvos
85
+ when :appletvos, :tvos
67
86
  return Spaceship::ConnectAPI::Platform::TV_OS
68
- when :osx
87
+ when :osx, :macos
69
88
  return Spaceship::ConnectAPI::Platform::MAC_OS
70
89
  when :ios
71
90
  return Spaceship::ConnectAPI::Platform::IOS
@@ -141,21 +141,57 @@ module Spaceship
141
141
  def handle_errors(response)
142
142
  # Example error format
143
143
  # {
144
- # "errors" : [ {
145
- # "id" : "ce8c391e-f858-411b-a14b-5aa26e0915f2",
146
- # "status" : "400",
147
- # "code" : "PARAMETER_ERROR.INVALID",
148
- # "title" : "A parameter has an invalid value",
149
- # "detail" : "'uploadedDate3' is not a valid field name",
150
- # "source" : {
151
- # "parameter" : "sort"
144
+ # "errors":[
145
+ # {
146
+ # "id":"cbfd8674-4802-4857-bfe8-444e1ea36e32",
147
+ # "status":"409",
148
+ # "code":"STATE_ERROR",
149
+ # "title":"The request cannot be fulfilled because of the state of another resource.",
150
+ # "detail":"Submit for review errors found.",
151
+ # "meta":{
152
+ # "associatedErrors":{
153
+ # "/v1/appScreenshots/":[
154
+ # {
155
+ # "id":"23d1734f-b81f-411a-98e4-6d3e763d54ed",
156
+ # "status":"409",
157
+ # "code":"STATE_ERROR.SCREENSHOT_REQUIRED.APP_WATCH_SERIES_4",
158
+ # "title":"App screenshot missing (APP_WATCH_SERIES_4)."
159
+ # },
160
+ # {
161
+ # "id":"db993030-0a93-48e9-9fd7-7e5676633431",
162
+ # "status":"409",
163
+ # "code":"STATE_ERROR.SCREENSHOT_REQUIRED.APP_WATCH_SERIES_4",
164
+ # "title":"App screenshot missing (APP_WATCH_SERIES_4)."
165
+ # }
166
+ # ],
167
+ # "/v1/builds/d710b6fa-5235-4fe4-b791-2b80d6818db0":[
168
+ # {
169
+ # "id":"e421fe6f-0e3b-464b-89dc-ba437e7bb77d",
170
+ # "status":"409",
171
+ # "code":"ENTITY_ERROR.ATTRIBUTE.REQUIRED",
172
+ # "title":"The provided entity is missing a required attribute",
173
+ # "detail":"You must provide a value for the attribute 'usesNonExemptEncryption' with this request",
174
+ # "source":{
175
+ # "pointer":"/data/attributes/usesNonExemptEncryption"
176
+ # }
177
+ # }
178
+ # ]
179
+ # }
180
+ # }
152
181
  # }
153
- # } ]
182
+ # ]
154
183
  # }
155
184
 
156
185
  return response.body['errors'].map do |error|
157
- "#{error['title']} - #{error['detail']}"
158
- end.join(" ")
186
+ messages = [[error['title'], error['detail']].compact.join(" - ")]
187
+
188
+ meta = error["meta"] || {}
189
+ associated_errors = meta["associatedErrors"] || {}
190
+
191
+ messages + associated_errors.values.flatten.map do |associated_error|
192
+ [[associated_error["title"], associated_error["detail"]].compact.join(" - ")]
193
+ end
194
+ end.flatten.join("\n")
159
195
  end
160
196
 
161
197
  private