fastlane 2.148.0 → 2.150.0.rc2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (108) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +86 -86
  3. data/deliver/lib/deliver.rb +0 -1
  4. data/deliver/lib/deliver/app_screenshot.rb +28 -27
  5. data/deliver/lib/deliver/options.rb +6 -11
  6. data/deliver/lib/deliver/runner.rb +7 -21
  7. data/deliver/lib/deliver/setup.rb +5 -30
  8. data/deliver/lib/deliver/submit_for_review.rb +155 -90
  9. data/deliver/lib/deliver/upload_metadata.rb +355 -143
  10. data/deliver/lib/deliver/upload_price_tier.rb +22 -8
  11. data/deliver/lib/deliver/upload_screenshots.rb +112 -37
  12. data/fastlane/lib/assets/s3_html_template.erb +1 -1
  13. data/fastlane/lib/fastlane/actions/docs/capture_android_screenshots.md +42 -2
  14. data/fastlane/lib/fastlane/actions/docs/capture_ios_screenshots.md +1 -1
  15. data/fastlane/lib/fastlane/actions/docs/upload_to_app_store.md.erb +77 -96
  16. data/fastlane/lib/fastlane/actions/docs/upload_to_play_store.md +3 -2
  17. data/fastlane/lib/fastlane/actions/download_dsyms.rb +7 -1
  18. data/fastlane/lib/fastlane/actions/google_play_track_release_names.rb +74 -0
  19. data/fastlane/lib/fastlane/actions/hipchat.rb +1 -1
  20. data/fastlane/lib/fastlane/actions/set_changelog.rb +23 -20
  21. data/fastlane/lib/fastlane/actions/slack.rb +2 -2
  22. data/fastlane/lib/fastlane/actions/slather.rb +8 -1
  23. data/fastlane/lib/fastlane/actions/spm.rb +7 -0
  24. data/fastlane/lib/fastlane/actions/upload_symbols_to_crashlytics.rb +2 -33
  25. data/fastlane/lib/fastlane/documentation/actions_list.rb +1 -1
  26. data/fastlane/lib/fastlane/lane.rb +3 -3
  27. data/fastlane/lib/fastlane/plugins/plugin_manager.rb +1 -1
  28. data/fastlane/lib/fastlane/plugins/template/.github/workflows/test.yml +29 -0
  29. data/fastlane/lib/fastlane/swift_fastlane_function.rb +22 -5
  30. data/fastlane/lib/fastlane/version.rb +1 -1
  31. data/fastlane/swift/ControlCommand.swift +1 -0
  32. data/fastlane/swift/Deliverfile.swift +1 -1
  33. data/fastlane/swift/Fastlane.swift +79 -22
  34. data/fastlane/swift/FastlaneSwiftRunner/FastlaneSwiftRunner.xcodeproj/xcshareddata/xcschemes/FastlaneRunner.xcscheme +3 -9
  35. data/fastlane/swift/Gymfile.swift +1 -1
  36. data/fastlane/swift/GymfileProtocol.swift +1 -1
  37. data/fastlane/swift/LaneFileProtocol.swift +2 -5
  38. data/fastlane/swift/Matchfile.swift +1 -1
  39. data/fastlane/swift/MatchfileProtocol.swift +1 -1
  40. data/fastlane/swift/Precheckfile.swift +1 -1
  41. data/fastlane/swift/RubyCommand.swift +29 -6
  42. data/fastlane/swift/RubyCommandable.swift +1 -0
  43. data/fastlane/swift/Runner.swift +85 -13
  44. data/fastlane/swift/Scanfile.swift +1 -1
  45. data/fastlane/swift/ScanfileProtocol.swift +2 -2
  46. data/fastlane/swift/Screengrabfile.swift +1 -1
  47. data/fastlane/swift/Snapshotfile.swift +1 -1
  48. data/fastlane/swift/SnapshotfileProtocol.swift +9 -1
  49. data/fastlane/swift/SocketClient.swift +76 -45
  50. data/fastlane/swift/SocketClientDelegateProtocol.swift +1 -1
  51. data/fastlane/swift/SocketResponse.swift +1 -0
  52. data/fastlane_core/lib/fastlane_core/configuration/config_item.rb +1 -3
  53. data/fastlane_core/lib/fastlane_core/pkg_file_analyser.rb +7 -0
  54. data/frameit/lib/frameit/device_types.rb +100 -100
  55. data/gym/lib/gym/options.rb +1 -1
  56. data/match/lib/match/nuke.rb +21 -16
  57. data/match/lib/match/storage/git_storage.rb +4 -0
  58. data/match/lib/match/storage/google_cloud_storage.rb +4 -0
  59. data/match/lib/match/storage/interface.rb +4 -0
  60. data/match/lib/match/storage/s3_storage.rb +4 -0
  61. data/produce/lib/produce/itunes_connect.rb +32 -21
  62. data/produce/lib/produce/options.rb +3 -3
  63. data/scan/lib/scan/options.rb +1 -1
  64. data/scan/lib/scan/test_result_parser.rb +9 -2
  65. data/sigh/lib/assets/resign.sh +7 -7
  66. data/snapshot/lib/assets/SnapshotHelper.swift +5 -5
  67. data/snapshot/lib/assets/SnapshotHelperXcode8.swift +3 -3
  68. data/snapshot/lib/snapshot/options.rb +11 -1
  69. data/snapshot/lib/snapshot/reports_generator.rb +8 -1
  70. data/snapshot/lib/snapshot/test_command_generator.rb +8 -3
  71. data/spaceship/lib/spaceship/.DS_Store +0 -0
  72. data/spaceship/lib/spaceship/client.rb +13 -4
  73. data/spaceship/lib/spaceship/connect_api.rb +25 -2
  74. data/spaceship/lib/spaceship/connect_api/client.rb +97 -31
  75. data/spaceship/lib/spaceship/connect_api/file_uploader.rb +66 -0
  76. data/spaceship/lib/spaceship/connect_api/model.rb +1 -1
  77. data/spaceship/lib/spaceship/connect_api/models/age_rating_declaration.rb +113 -0
  78. data/spaceship/lib/spaceship/connect_api/models/app.rb +117 -3
  79. data/spaceship/lib/spaceship/connect_api/models/app_category.rb +94 -0
  80. data/spaceship/lib/spaceship/connect_api/models/app_info.rb +66 -0
  81. data/spaceship/lib/spaceship/connect_api/models/app_info_localization.rb +38 -0
  82. data/spaceship/lib/spaceship/connect_api/models/app_preview.rb +77 -0
  83. data/spaceship/lib/spaceship/connect_api/models/app_preview_set.rb +71 -0
  84. data/spaceship/lib/spaceship/connect_api/models/app_price.rb +22 -0
  85. data/spaceship/lib/spaceship/connect_api/models/app_price_tier.rb +12 -0
  86. data/spaceship/lib/spaceship/connect_api/models/app_review_attachment.rb +81 -0
  87. data/spaceship/lib/spaceship/connect_api/models/app_screenshot.rb +97 -0
  88. data/spaceship/lib/spaceship/connect_api/models/app_screenshot_set.rb +101 -0
  89. data/spaceship/lib/spaceship/connect_api/models/app_store_review_detail.rb +51 -0
  90. data/spaceship/lib/spaceship/connect_api/models/app_store_version.rb +182 -0
  91. data/spaceship/lib/spaceship/connect_api/models/app_store_version_localization.rb +86 -0
  92. data/spaceship/lib/spaceship/connect_api/models/app_store_version_phased_release.rb +36 -0
  93. data/spaceship/lib/spaceship/connect_api/models/app_store_version_submission.rb +26 -0
  94. data/spaceship/lib/spaceship/connect_api/models/build.rb +4 -0
  95. data/spaceship/lib/spaceship/connect_api/models/idfa_declaration.rb +40 -0
  96. data/spaceship/lib/spaceship/connect_api/models/reset_ratings_request.rb +26 -0
  97. data/spaceship/lib/spaceship/connect_api/models/territory.rb +27 -0
  98. data/spaceship/lib/spaceship/connect_api/testflight/testflight.rb +10 -3
  99. data/spaceship/lib/spaceship/connect_api/tunes/client.rb +33 -0
  100. data/spaceship/lib/spaceship/connect_api/tunes/tunes.rb +832 -0
  101. data/spaceship/lib/spaceship/errors.rb +3 -0
  102. data/spaceship/lib/spaceship/spaceauth_runner.rb +2 -2
  103. data/supply/lib/supply/client.rb +19 -0
  104. data/supply/lib/supply/reader.rb +16 -0
  105. metadata +50 -42
  106. data/deliver/lib/deliver/upload_assets.rb +0 -27
  107. data/snapshot/lib/snapshot/.options.rb.swp +0 -0
  108. data/snapshot/lib/snapshot/.test_command_generator_base.rb.swp +0 -0
@@ -54,7 +54,7 @@ module Produce
54
54
  optional: true,
55
55
  default_value: "ios",
56
56
  verify_block: proc do |value|
57
- UI.user_error!("The platform can only be ios or osx") unless %('ios', 'osx').include?(value)
57
+ UI.user_error!("The platform can only be ios or osx") unless %('ios', 'osx', 'tvos').include?(value)
58
58
  end),
59
59
  FastlaneCore::ConfigItem.new(key: :platforms,
60
60
  short_option: "-J",
@@ -64,13 +64,13 @@ module Produce
64
64
  optional: true,
65
65
  type: Array,
66
66
  verify_block: proc do |values|
67
- types = %w(ios osx)
67
+ types = %w(ios osx tvos)
68
68
  UI.user_error!("The platform can only be #{types}") unless (values - types).empty?
69
69
  end),
70
70
  FastlaneCore::ConfigItem.new(key: :language,
71
71
  short_option: "-m",
72
72
  env_name: "PRODUCE_LANGUAGE",
73
- description: "Primary Language (e.g. 'English', 'German')",
73
+ description: "Primary Language (e.g. 'en-US', 'fr-FR')",
74
74
  default_value: "English",
75
75
  verify_block: proc do |language|
76
76
  end),
@@ -398,7 +398,7 @@ module Scan
398
398
  FastlaneCore::ConfigItem.new(key: :slack_icon_url,
399
399
  env_name: "SCAN_SLACK_ICON_URL",
400
400
  description: "Overrides the webhook's image property if slack_use_webhook_configured_username_and_icon is false",
401
- default_value: "https://s3-eu-west-1.amazonaws.com/fastlane.tools/fastlane.png",
401
+ default_value: "https://fastlane.tools/assets/img/fastlane_icon.png",
402
402
  is_string: true,
403
403
  optional: true),
404
404
  FastlaneCore::ConfigItem.new(key: :skip_slack,
@@ -3,6 +3,13 @@ require_relative 'module'
3
3
  module Scan
4
4
  class TestResultParser
5
5
  def parse_result(output)
6
+ unless output
7
+ return {
8
+ tests: 0,
9
+ failures: 0
10
+ }
11
+ end
12
+
6
13
  # e.g. ...<testsuites tests='2' failures='1'>...
7
14
  matched = output.scan(/<testsuites\b(?=[^<>]*\s+tests='(\d+)')(?=[^<>]*\s+failures='(\d+)')[^<>]+>/)
8
15
 
@@ -10,13 +17,13 @@ module Scan
10
17
  tests = matched[0][0].to_i
11
18
  failures = matched[0][1].to_i
12
19
 
13
- return {
20
+ {
14
21
  tests: tests,
15
22
  failures: failures
16
23
  }
17
24
  else
18
25
  UI.error("Couldn't parse the number of tests from the output")
19
- return {
26
+ {
20
27
  tests: 0,
21
28
  failures: 0
22
29
  }
@@ -620,7 +620,7 @@ function resign {
620
620
  # Start with using what comes in provisioning profile entitlements before patching
621
621
  cp -f "$PROFILE_ENTITLEMENTS" "$PATCHED_ENTITLEMENTS"
622
622
 
623
- log "Removing blacklisted keys from patched profile"
623
+ log "Removing denylisted keys from patched profile"
624
624
  # See https://github.com/facebook/buck/issues/798 and https://github.com/facebook/buck/pull/802/files
625
625
 
626
626
  # Update in https://github.com/facebook/buck/commit/99c0fbc3ab5ecf04d186913374f660683deccdef
@@ -628,7 +628,7 @@ function resign {
628
628
 
629
629
  # Buck changes referenced above are not self-explanatory and do not seem exhaustive or up-to-date
630
630
  # Comments below explain the rules applied to each key in order to make realignment with future Xcode export logic easier
631
- BLACKLISTED_KEYS=(\
631
+ DENYLISTED_KEYS=(\
632
632
  # PP list identifiers inconsistent with app-defined ones and this key does not seem to appear in IPA entitlements, so ignore it
633
633
  "com.apple.developer.icloud-container-development-container-identifiers" \
634
634
  # This key has an invalid generic value in PP (actual value is set by Xcode during export), see dedicated processing a few blocks below
@@ -637,7 +637,7 @@ function resign {
637
637
  "com.apple.developer.icloud-container-identifiers" \
638
638
  # PP enable all available services and not app-defined ones, must use App entitlements value
639
639
  "com.apple.developer.icloud-services" \
640
- # Was already blacklisted in previous version, but has someone ever seen this key in a PP?
640
+ # Was already denylisted in previous version, but has someone ever seen this key in a PP?
641
641
  "com.apple.developer.restricted-resource-mode" \
642
642
  # If actually used by the App, this value will be set in its entitlements
643
643
  "com.apple.developer.nfc.readersession.formats" \
@@ -675,15 +675,15 @@ function resign {
675
675
  "com.apple.developer.default-data-protection" \
676
676
  # PP seem to list the same groups as the App, but use App entitlements value to be sure
677
677
  "com.apple.security.application-groups" \
678
- # Was already blacklisted in previous version, seems to be an artifact from an old Xcode release
678
+ # Was already denylisted in previous version, seems to be an artifact from an old Xcode release
679
679
  "com.apple.developer.maps" \
680
680
  # If actually used by the App, this value will be set in its entitlements
681
681
  "com.apple.external-accessory.wireless-configuration"
682
682
  )
683
683
 
684
- # Blacklisted keys must not be included into new profile, so remove them from patched profile
685
- for KEY in "${BLACKLISTED_KEYS[@]}"; do
686
- log "Removing blacklisted key: $KEY"
684
+ # Denylisted keys must not be included into new profile, so remove them from patched profile
685
+ for KEY in "${DENYLISTED_KEYS[@]}"; do
686
+ log "Removing denylisted key: $KEY"
687
687
  PlistBuddy -c "Delete $KEY" "$PATCHED_ENTITLEMENTS" 2>/dev/null
688
688
  done
689
689
 
@@ -218,7 +218,7 @@ open class Snapshot: NSObject {
218
218
 
219
219
  private extension XCUIElementAttributes {
220
220
  var isNetworkLoadingIndicator: Bool {
221
- if hasWhiteListedIdentifier { return false }
221
+ if hasAllowListedIdentifier { return false }
222
222
 
223
223
  let hasOldLoadingIndicatorSize = frame.size == CGSize(width: 10, height: 20)
224
224
  let hasNewLoadingIndicatorSize = frame.size.width.isBetween(46, and: 47) && frame.size.height.isBetween(2, and: 3)
@@ -226,10 +226,10 @@ private extension XCUIElementAttributes {
226
226
  return hasOldLoadingIndicatorSize || hasNewLoadingIndicatorSize
227
227
  }
228
228
 
229
- var hasWhiteListedIdentifier: Bool {
230
- let whiteListedIdentifiers = ["GeofenceLocationTrackingOn", "StandardLocationTrackingOn"]
229
+ var hasAllowListedIdentifier: Bool {
230
+ let allowListedIdentifiers = ["GeofenceLocationTrackingOn", "StandardLocationTrackingOn"]
231
231
 
232
- return whiteListedIdentifiers.contains(identifier)
232
+ return allowListedIdentifiers.contains(identifier)
233
233
  }
234
234
 
235
235
  func isStatusBar(_ deviceWidth: CGFloat) -> Bool {
@@ -279,4 +279,4 @@ private extension CGFloat {
279
279
 
280
280
  // Please don't remove the lines below
281
281
  // They are used to detect outdated configuration files
282
- // SnapshotHelperVersion [1.22]
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]
@@ -152,6 +152,11 @@ module Snapshot
152
152
  description: "A list of videos that should be added to the simulator before running the application",
153
153
  type: Array,
154
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),
155
160
 
156
161
  # Everything around building
157
162
  FastlaneCore::ConfigItem.new(key: :buildlog_path,
@@ -263,7 +268,12 @@ module Snapshot
263
268
  is_string: false,
264
269
  verify_block: proc do |value|
265
270
  verify_type('skip_testing', [Array, String], value)
266
- end)
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,
276
+ optional: true)
267
277
  ]
268
278
  end
269
279
  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"
@@ -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)
@@ -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"
@@ -193,15 +194,16 @@ module Spaceship
193
194
  self.new(cookie: another_client.instance_variable_get(:@cookie), current_team_id: another_client.team_id)
194
195
  end
195
196
 
196
- def initialize(cookie: nil, current_team_id: nil)
197
+ def initialize(cookie: nil, current_team_id: nil, timeout: nil)
197
198
  options = {
198
199
  request: {
199
- timeout: (ENV["SPACESHIP_TIMEOUT"] || 300).to_i,
200
- open_timeout: (ENV["SPACESHIP_TIMEOUT"] || 300).to_i
200
+ timeout: (ENV["SPACESHIP_TIMEOUT"] || timeout || 300).to_i,
201
+ open_timeout: (ENV["SPACESHIP_TIMEOUT"] || timeout || 300).to_i
201
202
  }
202
203
  }
203
204
  @current_team_id = current_team_id
204
205
  @cookie = cookie || HTTP::CookieJar.new
206
+
205
207
  @client = Faraday.new(self.class.hostname, options) do |c|
206
208
  c.response(:json, content_type: /\bjson$/)
207
209
  c.response(:xml, content_type: /\bxml$/)
@@ -628,7 +630,8 @@ module Spaceship
628
630
  Faraday::TimeoutError,
629
631
  BadGatewayError,
630
632
  AppleTimeoutError,
631
- GatewayTimeoutError => ex
633
+ GatewayTimeoutError,
634
+ AccessForbiddenError => ex
632
635
  tries -= 1
633
636
  unless tries.zero?
634
637
  msg = "Timeout received: '#{ex.class}', '#{ex.message}'. Retrying after 3 seconds (remaining: #{tries})..."
@@ -865,6 +868,12 @@ module Spaceship
865
868
  raise BadGatewayError.new, "Apple 502 detected - this might be temporary server error, try again later"
866
869
  end
867
870
 
871
+ if resp_hash[:status] == 403
872
+ msg = "Access forbidden"
873
+ logger.warn(msg)
874
+ raise AccessForbiddenError.new, msg
875
+ end
876
+
868
877
  return response
869
878
  end
870
879
  end
@@ -1,10 +1,12 @@
1
1
  require 'spaceship/connect_api/model'
2
2
  require 'spaceship/connect_api/response'
3
3
  require 'spaceship/connect_api/token'
4
+ require 'spaceship/connect_api/file_uploader'
4
5
 
5
6
  require 'spaceship/connect_api/provisioning/provisioning'
6
7
  require 'spaceship/connect_api/testflight/testflight'
7
8
  require 'spaceship/connect_api/users/users'
9
+ require 'spaceship/connect_api/tunes/tunes'
8
10
 
9
11
  require 'spaceship/connect_api/models/bundle_id_capability'
10
12
  require 'spaceship/connect_api/models/bundle_id'
@@ -30,11 +32,32 @@ require 'spaceship/connect_api/models/build_delivery'
30
32
  require 'spaceship/connect_api/models/build_beta_detail'
31
33
  require 'spaceship/connect_api/models/pre_release_version'
32
34
 
35
+ require 'spaceship/connect_api/models/age_rating_declaration'
36
+ require 'spaceship/connect_api/models/app_category'
37
+ require 'spaceship/connect_api/models/app_info'
38
+ require 'spaceship/connect_api/models/app_info_localization'
39
+ require 'spaceship/connect_api/models/app_preview_set'
40
+ require 'spaceship/connect_api/models/app_preview'
41
+ require 'spaceship/connect_api/models/app_price'
42
+ require 'spaceship/connect_api/models/app_price_tier'
43
+ require 'spaceship/connect_api/models/app_review_attachment'
44
+ require 'spaceship/connect_api/models/app_store_review_detail'
45
+ require 'spaceship/connect_api/models/app_store_version_submission'
46
+ require 'spaceship/connect_api/models/app_screenshot_set'
47
+ require 'spaceship/connect_api/models/app_screenshot'
48
+ require 'spaceship/connect_api/models/app_store_version_localization'
49
+ require 'spaceship/connect_api/models/app_store_version_phased_release'
50
+ require 'spaceship/connect_api/models/app_store_version'
51
+ require 'spaceship/connect_api/models/idfa_declaration'
52
+ require 'spaceship/connect_api/models/reset_ratings_request'
53
+ require 'spaceship/connect_api/models/territory'
54
+
33
55
  module Spaceship
34
56
  class ConnectAPI
35
57
  extend Spaceship::ConnectAPI::Provisioning
36
58
  extend Spaceship::ConnectAPI::TestFlight
37
59
  extend Spaceship::ConnectAPI::Users
60
+ extend Spaceship::ConnectAPI::Tunes
38
61
 
39
62
  @token = nil
40
63
 
@@ -63,9 +86,9 @@ module Spaceship
63
86
 
64
87
  # Map from fastlane input and Spaceship::TestFlight platform values
65
88
  case platform.to_sym
66
- when :appletvos
89
+ when :appletvos, :tvos
67
90
  return Spaceship::ConnectAPI::Platform::TV_OS
68
- when :osx
91
+ when :osx, :macos, :mac
69
92
  return Spaceship::ConnectAPI::Platform::MAC_OS
70
93
  when :ios
71
94
  return Spaceship::ConnectAPI::Platform::IOS
@@ -13,7 +13,7 @@ module Spaceship
13
13
  # Instantiates a client with cookie session or a JWT token.
14
14
  def initialize(cookie: nil, current_team_id: nil, token: nil)
15
15
  if token.nil?
16
- super(cookie: cookie, current_team_id: current_team_id)
16
+ super(cookie: cookie, current_team_id: current_team_id, timeout: 1200)
17
17
  else
18
18
  options = {
19
19
  request: {
@@ -78,46 +78,76 @@ module Spaceship
78
78
  end
79
79
 
80
80
  def get(url_or_path, params = nil)
81
- response = request(:get) do |req|
82
- req.url(url_or_path)
83
- req.options.params_encoder = Faraday::NestedParamsEncoder
84
- req.params = params if params
85
- req.headers['Content-Type'] = 'application/json'
81
+ response = with_asc_retry do
82
+ request(:get) do |req|
83
+ req.url(url_or_path)
84
+ req.options.params_encoder = Faraday::NestedParamsEncoder
85
+ req.params = params if params
86
+ req.headers['Content-Type'] = 'application/json'
87
+ end
86
88
  end
87
89
  handle_response(response)
88
90
  end
89
91
 
90
92
  def post(url_or_path, body)
91
- response = request(:post) do |req|
92
- req.url(url_or_path)
93
- req.body = body.to_json
94
- req.headers['Content-Type'] = 'application/json'
93
+ response = with_asc_retry do
94
+ request(:post) do |req|
95
+ req.url(url_or_path)
96
+ req.body = body.to_json
97
+ req.headers['Content-Type'] = 'application/json'
98
+ end
95
99
  end
96
100
  handle_response(response)
97
101
  end
98
102
 
99
103
  def patch(url_or_path, body)
100
- response = request(:patch) do |req|
101
- req.url(url_or_path)
102
- req.body = body.to_json
103
- req.headers['Content-Type'] = 'application/json'
104
+ response = with_asc_retry do
105
+ request(:patch) do |req|
106
+ req.url(url_or_path)
107
+ req.body = body.to_json
108
+ req.headers['Content-Type'] = 'application/json'
109
+ end
104
110
  end
105
111
  handle_response(response)
106
112
  end
107
113
 
108
114
  def delete(url_or_path, params = nil, body = nil)
109
- response = request(:delete) do |req|
110
- req.url(url_or_path)
111
- req.options.params_encoder = Faraday::NestedParamsEncoder if params
112
- req.params = params if params
113
- req.body = body.to_json if body
114
- req.headers['Content-Type'] = 'application/json' if body
115
+ response = with_asc_retry do
116
+ request(:delete) do |req|
117
+ req.url(url_or_path)
118
+ req.options.params_encoder = Faraday::NestedParamsEncoder if params
119
+ req.params = params if params
120
+ req.body = body.to_json if body
121
+ req.headers['Content-Type'] = 'application/json' if body
122
+ end
115
123
  end
116
124
  handle_response(response)
117
125
  end
118
126
 
119
127
  protected
120
128
 
129
+ def with_asc_retry(tries = 5, &_block)
130
+ tries = 1 if Object.const_defined?("SpecHelper")
131
+ response = yield
132
+
133
+ tries -= 1
134
+ status = response.status if response
135
+
136
+ if [504].include?(status)
137
+ msg = "Timeout received! Retrying after 3 seconds (remaining: #{tries})..."
138
+ raise msg
139
+ end
140
+
141
+ return response
142
+ rescue => error
143
+ puts(error) if Spaceship::Globals.verbose?
144
+ if tries.zero?
145
+ return response
146
+ else
147
+ retry
148
+ end
149
+ end
150
+
121
151
  def handle_response(response)
122
152
  if (200...300).cover?(response.status) && (response.body.nil? || response.body.empty?)
123
153
  return
@@ -141,21 +171,57 @@ module Spaceship
141
171
  def handle_errors(response)
142
172
  # Example error format
143
173
  # {
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"
174
+ # "errors":[
175
+ # {
176
+ # "id":"cbfd8674-4802-4857-bfe8-444e1ea36e32",
177
+ # "status":"409",
178
+ # "code":"STATE_ERROR",
179
+ # "title":"The request cannot be fulfilled because of the state of another resource.",
180
+ # "detail":"Submit for review errors found.",
181
+ # "meta":{
182
+ # "associatedErrors":{
183
+ # "/v1/appScreenshots/":[
184
+ # {
185
+ # "id":"23d1734f-b81f-411a-98e4-6d3e763d54ed",
186
+ # "status":"409",
187
+ # "code":"STATE_ERROR.SCREENSHOT_REQUIRED.APP_WATCH_SERIES_4",
188
+ # "title":"App screenshot missing (APP_WATCH_SERIES_4)."
189
+ # },
190
+ # {
191
+ # "id":"db993030-0a93-48e9-9fd7-7e5676633431",
192
+ # "status":"409",
193
+ # "code":"STATE_ERROR.SCREENSHOT_REQUIRED.APP_WATCH_SERIES_4",
194
+ # "title":"App screenshot missing (APP_WATCH_SERIES_4)."
195
+ # }
196
+ # ],
197
+ # "/v1/builds/d710b6fa-5235-4fe4-b791-2b80d6818db0":[
198
+ # {
199
+ # "id":"e421fe6f-0e3b-464b-89dc-ba437e7bb77d",
200
+ # "status":"409",
201
+ # "code":"ENTITY_ERROR.ATTRIBUTE.REQUIRED",
202
+ # "title":"The provided entity is missing a required attribute",
203
+ # "detail":"You must provide a value for the attribute 'usesNonExemptEncryption' with this request",
204
+ # "source":{
205
+ # "pointer":"/data/attributes/usesNonExemptEncryption"
206
+ # }
207
+ # }
208
+ # ]
209
+ # }
210
+ # }
152
211
  # }
153
- # } ]
212
+ # ]
154
213
  # }
155
214
 
156
215
  return response.body['errors'].map do |error|
157
- "#{error['title']} - #{error['detail']}"
158
- end.join(" ")
216
+ messages = [[error['title'], error['detail']].compact.join(" - ")]
217
+
218
+ meta = error["meta"] || {}
219
+ associated_errors = meta["associatedErrors"] || {}
220
+
221
+ messages + associated_errors.values.flatten.map do |associated_error|
222
+ [[associated_error["title"], associated_error["detail"]].compact.join(" - ")]
223
+ end
224
+ end.flatten.join("\n")
159
225
  end
160
226
 
161
227
  private