fastlane 2.149.1 → 2.150.0.rc5

Sign up to get free protection for your applications and to get access to all the features.
Files changed (90) hide show
  1. checksums.yaml +4 -4
  2. data/deliver/lib/deliver.rb +0 -1
  3. data/deliver/lib/deliver/app_screenshot.rb +26 -25
  4. data/deliver/lib/deliver/download_screenshots.rb +46 -26
  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 +170 -86
  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 +140 -39
  12. data/{scan/lib/scan/.test_command_generator.rb.swp → fastlane/lib/fastlane/actions/.hockey.rb.swp} +0 -0
  13. data/fastlane/lib/fastlane/actions/.slack.rb.swp +0 -0
  14. data/{snapshot/lib/snapshot/.test_command_generator_base.rb.swp → fastlane/lib/fastlane/actions/.update_project_provisioning.rb.swp} +0 -0
  15. data/fastlane/lib/fastlane/actions/docs/capture_ios_screenshots.md +1 -1
  16. data/fastlane/lib/fastlane/actions/docs/upload_to_app_store.md.erb +81 -96
  17. data/fastlane/lib/fastlane/actions/docs/upload_to_play_store.md +3 -2
  18. data/fastlane/lib/fastlane/actions/download_dsyms.rb +7 -1
  19. data/fastlane/lib/fastlane/actions/google_play_track_release_names.rb +74 -0
  20. data/fastlane/lib/fastlane/actions/set_changelog.rb +23 -20
  21. data/fastlane/lib/fastlane/actions/slack.rb +1 -1
  22. data/fastlane/lib/fastlane/actions/spm.rb +7 -0
  23. data/fastlane/lib/fastlane/actions/upload_symbols_to_crashlytics.rb +1 -32
  24. data/fastlane/lib/fastlane/lane.rb +3 -3
  25. data/fastlane/lib/fastlane/swift_fastlane_function.rb +8 -4
  26. data/fastlane/lib/fastlane/version.rb +1 -1
  27. data/fastlane/swift/ControlCommand.swift +1 -0
  28. data/fastlane/swift/Fastlane.swift +48 -12
  29. data/fastlane/swift/FastlaneSwiftRunner/FastlaneSwiftRunner.xcodeproj/project.xcworkspace/xcuserdata/josh.xcuserdatad/UserInterfaceState.xcuserstate +0 -0
  30. data/fastlane/swift/FastlaneSwiftRunner/FastlaneSwiftRunner.xcodeproj/xcshareddata/xcschemes/FastlaneRunner.xcscheme +3 -9
  31. data/fastlane/swift/LaneFileProtocol.swift +2 -5
  32. data/fastlane/swift/MatchfileProtocol.swift +1 -1
  33. data/fastlane/swift/RubyCommand.swift +29 -6
  34. data/fastlane/swift/RubyCommandable.swift +1 -0
  35. data/fastlane/swift/Runner.swift +85 -13
  36. data/fastlane/swift/ScanfileProtocol.swift +1 -1
  37. data/fastlane/swift/SnapshotfileProtocol.swift +3 -3
  38. data/fastlane/swift/SocketClient.swift +76 -45
  39. data/fastlane/swift/SocketClientDelegateProtocol.swift +1 -1
  40. data/fastlane/swift/SocketResponse.swift +1 -0
  41. data/fastlane_core/lib/fastlane_core/build_watcher.rb +4 -4
  42. data/fastlane_core/lib/fastlane_core/configuration/config_item.rb +1 -3
  43. data/fastlane_core/lib/fastlane_core/itunes_transporter.rb +89 -52
  44. data/fastlane_core/lib/fastlane_core/pkg_file_analyser.rb +7 -0
  45. data/frameit/lib/frameit/device_types.rb +100 -100
  46. data/pilot/lib/pilot/.manager.rb.swp +0 -0
  47. data/produce/lib/produce/itunes_connect.rb +59 -21
  48. data/produce/lib/produce/options.rb +3 -3
  49. data/sigh/lib/assets/resign.sh +7 -7
  50. data/snapshot/lib/assets/SnapshotHelper.swift +5 -5
  51. data/snapshot/lib/assets/SnapshotHelperXcode8.swift +3 -3
  52. data/snapshot/lib/snapshot/options.rb +0 -1
  53. data/snapshot/lib/snapshot/reports_generator.rb +8 -1
  54. data/spaceship/lib/spaceship/client.rb +4 -3
  55. data/spaceship/lib/spaceship/connect_api.rb +25 -2
  56. data/spaceship/lib/spaceship/connect_api/.DS_Store +0 -0
  57. data/spaceship/lib/spaceship/connect_api/client.rb +97 -31
  58. data/spaceship/lib/spaceship/connect_api/file_uploader.rb +98 -0
  59. data/spaceship/lib/spaceship/connect_api/model.rb +1 -1
  60. data/spaceship/lib/spaceship/connect_api/models/age_rating_declaration.rb +113 -0
  61. data/spaceship/lib/spaceship/connect_api/models/app.rb +135 -3
  62. data/spaceship/lib/spaceship/connect_api/models/app_category.rb +94 -0
  63. data/spaceship/lib/spaceship/connect_api/models/app_info.rb +67 -0
  64. data/spaceship/lib/spaceship/connect_api/models/app_info_localization.rb +38 -0
  65. data/spaceship/lib/spaceship/connect_api/models/app_preview.rb +129 -0
  66. data/spaceship/lib/spaceship/connect_api/models/app_preview_set.rb +71 -0
  67. data/spaceship/lib/spaceship/connect_api/models/app_price.rb +22 -0
  68. data/spaceship/lib/spaceship/connect_api/models/app_price_tier.rb +12 -0
  69. data/spaceship/lib/spaceship/connect_api/models/app_review_attachment.rb +71 -0
  70. data/spaceship/lib/spaceship/connect_api/models/app_screenshot.rb +146 -0
  71. data/spaceship/lib/spaceship/connect_api/models/app_screenshot_set.rb +125 -0
  72. data/spaceship/lib/spaceship/connect_api/models/app_store_review_detail.rb +51 -0
  73. data/spaceship/lib/spaceship/connect_api/models/app_store_version.rb +183 -0
  74. data/spaceship/lib/spaceship/connect_api/models/app_store_version_localization.rb +86 -0
  75. data/spaceship/lib/spaceship/connect_api/models/app_store_version_phased_release.rb +36 -0
  76. data/spaceship/lib/spaceship/connect_api/models/app_store_version_submission.rb +26 -0
  77. data/spaceship/lib/spaceship/connect_api/models/build.rb +4 -0
  78. data/spaceship/lib/spaceship/connect_api/models/idfa_declaration.rb +40 -0
  79. data/spaceship/lib/spaceship/connect_api/models/reset_ratings_request.rb +26 -0
  80. data/spaceship/lib/spaceship/connect_api/models/territory.rb +27 -0
  81. data/spaceship/lib/spaceship/connect_api/models/user.rb +2 -1
  82. data/spaceship/lib/spaceship/connect_api/testflight/testflight.rb +10 -3
  83. data/spaceship/lib/spaceship/connect_api/tunes/client.rb +33 -0
  84. data/spaceship/lib/spaceship/connect_api/tunes/tunes.rb +844 -0
  85. data/spaceship/lib/spaceship/connect_api/users/users.rb +13 -0
  86. data/spaceship/lib/spaceship/spaceauth_runner.rb +2 -2
  87. data/supply/lib/supply/client.rb +19 -0
  88. data/supply/lib/supply/reader.rb +16 -0
  89. metadata +34 -22
  90. data/deliver/lib/deliver/upload_assets.rb +0 -27
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 7e38d836b49a278f1c3fd95c820aa3fe9dd7fa4d7f3c0fedfa5ff4fdf4ef033a
4
- data.tar.gz: 7a5d7180b0bf7f32989a7dbc8396a2215d68e645691f0c7afff75817324a3e1e
3
+ metadata.gz: 5713ac3ee6b1f2b1d00c5575f825292626471ea0adb1d82f20963a497b565e3c
4
+ data.tar.gz: dbc6d60bac4cc2fbfc3e806d981ccaf4de1342b8357ff7edca3eeae981d54cc4
5
5
  SHA512:
6
- metadata.gz: 51f0e319102f54e6e1a3878b40adf4a019042e64fcee0047d81564321f5e6b11803ac5701171f7e5ef23403f8ed169204e18635109a94928e61334b16cb36f22
7
- data.tar.gz: 8d86698444bc4f689bc7ada08f30e5e9b335f8f32e8a87c7d9f919bb99f148afd0c4fe84abd421fe2c3114f9c530f75cc26dd360d7108a5f6e93a820ed2bedcc
6
+ metadata.gz: 68c6a15af4df30d5a53e2a161f084f39188bbd293445f921fcc1f47ed4e6d6c35ea9acea25d6ad5ab73156155cfa514a0b239009b73385ce949603e3cacf8dc9
7
+ data.tar.gz: 6b791c19da977f7db0eb906e4dddccd4fbee7f75b098d3eff67f1bad6a249ff6a267c4082c842fd0a2cd1474d98b836d6b7a4c6278c64388f4f858f2b3b09941
@@ -6,7 +6,6 @@ require_relative 'deliver/runner'
6
6
  require_relative 'deliver/upload_metadata'
7
7
  require_relative 'deliver/upload_screenshots'
8
8
  require_relative 'deliver/upload_price_tier'
9
- require_relative 'deliver/upload_assets'
10
9
  require_relative 'deliver/submit_for_review'
11
10
  require_relative 'deliver/app_screenshot'
12
11
  require_relative 'deliver/html_generator'
@@ -1,6 +1,7 @@
1
1
  require 'fastimage'
2
2
 
3
3
  require_relative 'module'
4
+ require 'spaceship/connect_api/models/app_screenshot_set'
4
5
 
5
6
  module Deliver
6
7
  # AppScreenshot represents one screenshots for one specific locale and
@@ -95,31 +96,31 @@ module Deliver
95
96
  # The iTC API requires a different notation for the device
96
97
  def device_type
97
98
  matching = {
98
- ScreenSize::IOS_35 => "iphone35",
99
- ScreenSize::IOS_40 => "iphone4",
100
- ScreenSize::IOS_47 => "iphone6", # also 7 & 8
101
- ScreenSize::IOS_55 => "iphone6Plus", # also 7 Plus & 8 Plus
102
- ScreenSize::IOS_58 => "iphone58",
103
- ScreenSize::IOS_65 => "iphone65",
104
- ScreenSize::IOS_IPAD => "ipad",
105
- ScreenSize::IOS_IPAD_10_5 => "ipad105",
106
- ScreenSize::IOS_IPAD_11 => "ipadPro11",
107
- ScreenSize::IOS_IPAD_PRO => "ipadPro",
108
- ScreenSize::IOS_IPAD_PRO_12_9 => "ipadPro129",
109
- ScreenSize::IOS_40_MESSAGES => "iphone4",
110
- ScreenSize::IOS_47_MESSAGES => "iphone6", # also 7 & 8
111
- ScreenSize::IOS_55_MESSAGES => "iphone6Plus", # also 7 Plus & 8 Plus
112
- ScreenSize::IOS_58_MESSAGES => "iphone58",
113
- ScreenSize::IOS_65_MESSAGES => "iphone65",
114
- ScreenSize::IOS_IPAD_MESSAGES => "ipad",
115
- ScreenSize::IOS_IPAD_PRO_MESSAGES => "ipadPro",
116
- ScreenSize::IOS_IPAD_PRO_12_9_MESSAGES => "ipadPro129",
117
- ScreenSize::IOS_IPAD_10_5_MESSAGES => "ipad105",
118
- ScreenSize::IOS_IPAD_11_MESSAGES => "ipadPro11",
119
- ScreenSize::MAC => "desktop",
120
- ScreenSize::IOS_APPLE_WATCH => "watch",
121
- ScreenSize::IOS_APPLE_WATCH_SERIES4 => "watchSeries4",
122
- ScreenSize::APPLE_TV => "appleTV"
99
+ ScreenSize::IOS_35 => Spaceship::ConnectAPI::AppScreenshotSet::DisplayType::APP_IPHONE_35,
100
+ ScreenSize::IOS_40 => Spaceship::ConnectAPI::AppScreenshotSet::DisplayType::APP_IPHONE_40,
101
+ ScreenSize::IOS_47 => Spaceship::ConnectAPI::AppScreenshotSet::DisplayType::APP_IPHONE_47, # also 7 & 8
102
+ ScreenSize::IOS_55 => Spaceship::ConnectAPI::AppScreenshotSet::DisplayType::APP_IPHONE_55, # also 7 Plus & 8 Plus
103
+ ScreenSize::IOS_58 => Spaceship::ConnectAPI::AppScreenshotSet::DisplayType::APP_IPHONE_58,
104
+ ScreenSize::IOS_65 => Spaceship::ConnectAPI::AppScreenshotSet::DisplayType::APP_IPHONE_65,
105
+ ScreenSize::IOS_IPAD => Spaceship::ConnectAPI::AppScreenshotSet::DisplayType::APP_IPAD_97,
106
+ ScreenSize::IOS_IPAD_10_5 => Spaceship::ConnectAPI::AppScreenshotSet::DisplayType::APP_IPAD_105,
107
+ ScreenSize::IOS_IPAD_11 => Spaceship::ConnectAPI::AppScreenshotSet::DisplayType::APP_IPAD_PRO_3GEN_11,
108
+ ScreenSize::IOS_IPAD_PRO => Spaceship::ConnectAPI::AppScreenshotSet::DisplayType::APP_IPAD_PRO_129,
109
+ ScreenSize::IOS_IPAD_PRO_12_9 => Spaceship::ConnectAPI::AppScreenshotSet::DisplayType::APP_IPAD_PRO_3GEN_129,
110
+ ScreenSize::IOS_40_MESSAGES => Spaceship::ConnectAPI::AppScreenshotSet::DisplayType::IMESSAGE_APP_IPHONE_40,
111
+ ScreenSize::IOS_47_MESSAGES => Spaceship::ConnectAPI::AppScreenshotSet::DisplayType::IMESSAGE_APP_IPHONE_47, # also 7 & 8
112
+ ScreenSize::IOS_55_MESSAGES => Spaceship::ConnectAPI::AppScreenshotSet::DisplayType::IMESSAGE_APP_IPHONE_55, # also 7 Plus & 8 Plus
113
+ ScreenSize::IOS_58_MESSAGES => Spaceship::ConnectAPI::AppScreenshotSet::DisplayType::IMESSAGE_APP_IPHONE_58,
114
+ ScreenSize::IOS_65_MESSAGES => Spaceship::ConnectAPI::AppScreenshotSet::DisplayType::IMESSAGE_APP_IPHONE_65,
115
+ ScreenSize::IOS_IPAD_MESSAGES => Spaceship::ConnectAPI::AppScreenshotSet::DisplayType::IMESSAGE_APP_IPAD_97,
116
+ ScreenSize::IOS_IPAD_PRO_MESSAGES => Spaceship::ConnectAPI::AppScreenshotSet::DisplayType::APP_IPAD_PRO_129,
117
+ ScreenSize::IOS_IPAD_PRO_12_9_MESSAGES => Spaceship::ConnectAPI::AppScreenshotSet::DisplayType::APP_IPAD_PRO_3GEN_129,
118
+ ScreenSize::IOS_IPAD_10_5_MESSAGES => Spaceship::ConnectAPI::AppScreenshotSet::DisplayType::IMESSAGE_APP_IPAD_105,
119
+ ScreenSize::IOS_IPAD_11_MESSAGES => Spaceship::ConnectAPI::AppScreenshotSet::DisplayType::IMESSAGE_APP_IPAD_PRO_3GEN_11,
120
+ ScreenSize::MAC => Spaceship::ConnectAPI::AppScreenshotSet::DisplayType::APP_DESKTOP,
121
+ ScreenSize::IOS_APPLE_WATCH => Spaceship::ConnectAPI::AppScreenshotSet::DisplayType::APP_WATCH_SERIES_3,
122
+ ScreenSize::IOS_APPLE_WATCH_SERIES4 => Spaceship::ConnectAPI::AppScreenshotSet::DisplayType::APP_WATCH_SERIES_4,
123
+ # ScreenSize::APPLE_TV => Spaceship::ConnectAPI::AppScreenshotSet::DisplayType::
123
124
  }
124
125
  return matching[self.screen_size]
125
126
  end
@@ -1,4 +1,5 @@
1
1
  require_relative 'module'
2
+ require 'spaceship'
2
3
  require 'open-uri'
3
4
 
4
5
  module Deliver
@@ -13,35 +14,54 @@ module Deliver
13
14
  end
14
15
 
15
16
  def self.download(options, folder_path)
16
- v = options[:use_live_version] ? options[:app].live_version(platform: options[:platform]) : options[:app].latest_version(platform: options[:platform])
17
-
18
- v.screenshots.each do |language, screenshots|
19
- screenshots.each do |screenshot|
20
- file_name = [screenshot.sort_order, screenshot.device_type, screenshot.sort_order].join("_")
21
- original_file_extension = File.basename(screenshot.original_file_name)
22
- file_name += "." + original_file_extension
23
-
24
- UI.message("Downloading existing screenshot '#{file_name}' for language '#{language}'")
25
-
26
- # If the screen shot is for an appleTV we need to store it in a way that we'll know it's an appleTV
27
- # screen shot later as the screen size is the same as an iPhone 6 Plus in landscape.
28
- if screenshot.device_type == "appleTV"
29
- containing_folder = File.join(folder_path, "appleTV", screenshot.language)
30
- else
31
- containing_folder = File.join(folder_path, screenshot.language)
32
- end
17
+ legacy_app = options[:app]
18
+ app_id = legacy_app.apple_id
19
+ app = Spaceship::ConnectAPI::App.get(app_id: app_id)
33
20
 
34
- if screenshot.is_imessage
35
- containing_folder = File.join(folder_path, "iMessage", screenshot.language)
36
- end
21
+ platform = Spaceship::ConnectAPI::Platform.map(options[:platform])
22
+ version = if options[:use_live_version]
23
+ app.get_live_app_store_version(platform: platform)
24
+ else
25
+ app.get_edit_app_store_version(platform: platform)
26
+ end
27
+
28
+ localizations = version.get_app_store_version_localizations
29
+ localizations.each do |localization|
30
+ screenshot_sets = localization.get_app_screenshot_sets
31
+ screenshot_sets.each do |screenshot_set|
32
+ screenshot_set.app_screenshots.each_with_index do |screenshot, index|
33
+ url = screenshot.image_asset_url
34
+ next if url.nil?
35
+
36
+ file_name = [index, screenshot_set.screenshot_display_type, index].join("_")
37
+ original_file_extension = File.basename(screenshot.file_name)
38
+ file_name += "." + original_file_extension
39
+
40
+ language = localization.locale
41
+
42
+ UI.message("Downloading existing screenshot '#{file_name}' for language '#{language}'")
43
+
44
+ # If the screen shot is for an appleTV we need to store it in a way that we'll know it's an appleTV
45
+ # screen shot later as the screen size is the same as an iPhone 6 Plus in landscape.
46
+ if screenshot_set.apple_tv?
47
+ containing_folder = File.join(folder_path, "appleTV", language)
48
+ else
49
+ containing_folder = File.join(folder_path, language)
50
+ end
51
+
52
+ if screenshot_set.imessage?
53
+ containing_folder = File.join(folder_path, "iMessage", language)
54
+ end
55
+
56
+ begin
57
+ FileUtils.mkdir_p(containing_folder)
58
+ rescue
59
+ # if it's already there
60
+ end
37
61
 
38
- begin
39
- FileUtils.mkdir_p(containing_folder)
40
- rescue
41
- # if it's already there
62
+ path = File.join(containing_folder, file_name)
63
+ File.binwrite(path, open(url).read)
42
64
  end
43
- path = File.join(containing_folder, file_name)
44
- File.binwrite(path, open(screenshot.url).read)
45
65
  end
46
66
  end
47
67
  end
@@ -2,7 +2,6 @@ require 'fastlane_core/configuration/config_item'
2
2
  require 'credentials_manager/appfile_config'
3
3
 
4
4
  require_relative 'module'
5
- require_relative 'upload_assets'
6
5
 
7
6
  module Deliver
8
7
  # rubocop:disable Metrics/ClassLength
@@ -206,6 +205,7 @@ module Deliver
206
205
  short_option: "-b",
207
206
  description: "Extra information for the submission (e.g. compliance specifications, IDFA settings)",
208
207
  is_string: false,
208
+ type: Hash,
209
209
  optional: true),
210
210
 
211
211
  # affiliation
@@ -283,6 +283,7 @@ module Deliver
283
283
  FastlaneCore::ConfigItem.new(key: :individual_metadata_items,
284
284
  env_name: "DELIVER_INDIVUDAL_METADATA_ITEMS",
285
285
  description: "An array of localized metadata items to upload individually by language so that errors can be identified. E.g. ['name', 'keywords', 'description']. Note: slow",
286
+ deprecated: "Removed after the migration to the new App Store Connect API in June 2020",
286
287
  is_string: false,
287
288
  type: Array,
288
289
  default_value: []),
@@ -291,21 +292,15 @@ module Deliver
291
292
  FastlaneCore::ConfigItem.new(key: :app_icon,
292
293
  env_name: "DELIVER_APP_ICON_PATH",
293
294
  description: "Metadata: The path to the app icon",
295
+ deprecated: "Removed after the migration to the new App Store Connect API in June 2020",
294
296
  optional: true,
295
- short_option: "-l",
296
- verify_block: proc do |value|
297
- UI.user_error!("Could not find png file at path '#{File.expand_path(value)}'") unless File.exist?(value)
298
- UI.user_error!("'#{value}' doesn't seem to be one of the supported files. supported: #{Deliver::UploadAssets::SUPPORTED_ICON_EXTENSIONS.join(',')}") unless Deliver::UploadAssets::SUPPORTED_ICON_EXTENSIONS.include?(File.extname(value).downcase)
299
- end),
297
+ short_option: "-l"),
300
298
  FastlaneCore::ConfigItem.new(key: :apple_watch_app_icon,
301
299
  env_name: "DELIVER_APPLE_WATCH_APP_ICON_PATH",
302
300
  description: "Metadata: The path to the Apple Watch app icon",
301
+ deprecated: "Removed after the migration to the new App Store Connect API in June 2020",
303
302
  optional: true,
304
- short_option: "-q",
305
- verify_block: proc do |value|
306
- UI.user_error!("Could not find png file at path '#{File.expand_path(value)}'") unless File.exist?(value)
307
- UI.user_error!("'#{value}' doesn't seem to be one of the supported files. supported: #{Deliver::UploadAssets::SUPPORTED_ICON_EXTENSIONS.join(',')}") unless Deliver::UploadAssets::SUPPORTED_ICON_EXTENSIONS.include?(File.extname(value).downcase)
308
- end),
303
+ short_option: "-q"),
309
304
  FastlaneCore::ConfigItem.new(key: :copyright,
310
305
  env_name: "DELIVER_COPYRIGHT",
311
306
  description: "Metadata: The copyright notice",
@@ -7,7 +7,6 @@ require 'fastlane_core/itunes_transporter'
7
7
  require 'spaceship'
8
8
  require_relative 'html_generator'
9
9
  require_relative 'submit_for_review'
10
- require_relative 'upload_assets'
11
10
  require_relative 'upload_price_tier'
12
11
  require_relative 'upload_metadata'
13
12
  require_relative 'upload_screenshots'
@@ -87,9 +86,14 @@ module Deliver
87
86
  # If not, the new version will automatically be created
88
87
  def verify_version
89
88
  app_version = options[:app_version]
90
- UI.message("Making sure the latest version on App Store Connect matches '#{app_version}' from the ipa file...")
89
+ UI.message("Making sure the latest version on App Store Connect matches '#{app_version}'...")
91
90
 
92
- changed = options[:app].ensure_version!(app_version, platform: options[:platform])
91
+ legacy_app = options[:app]
92
+ app_id = legacy_app.apple_id
93
+ app = Spaceship::ConnectAPI::App.get(app_id: app_id)
94
+
95
+ platform = Spaceship::ConnectAPI::Platform.map(options[:platform])
96
+ changed = app.ensure_version!(app_version, platform: platform)
93
97
 
94
98
  if changed
95
99
  UI.success("Successfully set the version to '#{app_version}'")
@@ -110,9 +114,6 @@ module Deliver
110
114
  # Assign "default" values to all languages
111
115
  upload_metadata.assign_defaults(options)
112
116
 
113
- # Handle app icon / watch icon
114
- prepare_app_icons(options)
115
-
116
117
  # Validate
117
118
  validate_html(screenshots)
118
119
 
@@ -120,21 +121,6 @@ module Deliver
120
121
  upload_metadata.upload(options)
121
122
  upload_screenshots.upload(options, screenshots)
122
123
  UploadPriceTier.new.upload(options)
123
- UploadAssets.new.upload(options) # e.g. app icon
124
- end
125
-
126
- # If options[:app_icon]/options[:apple_watch_app_icon]
127
- # is supplied value/path will be used.
128
- # If it is unset files (app_icon/watch_icon) exists in
129
- # the fastlane/metadata/ folder, those will be used
130
- def prepare_app_icons(options = {})
131
- return unless options[:metadata_path]
132
-
133
- default_app_icon_path = Dir[File.join(options[:metadata_path], "app_icon.{png,jpg}")].first
134
- options[:app_icon] ||= default_app_icon_path if default_app_icon_path && File.exist?(default_app_icon_path)
135
-
136
- default_watch_icon_path = Dir[File.join(options[:metadata_path], "watch_icon.{png,jpg}")].first
137
- options[:apple_watch_app_icon] ||= default_watch_icon_path if default_watch_icon_path && File.exist?(default_watch_icon_path)
138
124
  end
139
125
 
140
126
  # Upload the binary to App Store Connect
@@ -60,9 +60,9 @@ module Deliver
60
60
  app_details = v.application.details
61
61
 
62
62
  # All the localised metadata
63
- (UploadMetadata::LOCALISED_VERSION_VALUES + UploadMetadata::LOCALISED_APP_VALUES).each do |key|
63
+ (UploadMetadata::LOCALISED_VERSION_VALUES.keys + UploadMetadata::LOCALISED_APP_VALUES.keys).each do |key|
64
64
  v.description.languages.each do |language|
65
- if UploadMetadata::LOCALISED_VERSION_VALUES.include?(key)
65
+ if UploadMetadata::LOCALISED_VERSION_VALUES.keys.include?(key)
66
66
  content = v.send(key)[language].to_s
67
67
  else
68
68
  content = app_details.send(key)[language].to_s
@@ -76,8 +76,8 @@ module Deliver
76
76
  end
77
77
 
78
78
  # All non-localised metadata
79
- (UploadMetadata::NON_LOCALISED_VERSION_VALUES + UploadMetadata::NON_LOCALISED_APP_VALUES).each do |key|
80
- if UploadMetadata::NON_LOCALISED_VERSION_VALUES.include?(key)
79
+ (UploadMetadata::NON_LOCALISED_VERSION_VALUES.keys + UploadMetadata::NON_LOCALISED_APP_VALUES).each do |key|
80
+ if UploadMetadata::NON_LOCALISED_VERSION_VALUES.keys.include?(key)
81
81
  content = v.send(key).to_s
82
82
  else
83
83
  content = app_details.send(key).to_s
@@ -88,19 +88,8 @@ module Deliver
88
88
  UI.message("Writing to '#{resulting_path}'")
89
89
  end
90
90
 
91
- # Trade Representative Contact Information
92
- UploadMetadata::TRADE_REPRESENTATIVE_CONTACT_INFORMATION_VALUES.each do |key, option_name|
93
- content = v.send(key).to_s
94
- content += "\n"
95
- base_dir = File.join(path, UploadMetadata::TRADE_REPRESENTATIVE_CONTACT_INFORMATION_DIR)
96
- FileUtils.mkdir_p(base_dir)
97
- resulting_path = File.join(base_dir, "#{option_name}.txt")
98
- File.write(resulting_path, content)
99
- UI.message("Writing to '#{resulting_path}'")
100
- end
101
-
102
91
  # Review information
103
- UploadMetadata::REVIEW_INFORMATION_VALUES.each do |key, option_name|
92
+ UploadMetadata::REVIEW_INFORMATION_VALUES_LEGACY.each do |key, option_name|
104
93
  content = v.send(key).to_s
105
94
  content += "\n"
106
95
  base_dir = File.join(path, UploadMetadata::REVIEW_INFORMATION_DIR)
@@ -111,20 +100,6 @@ module Deliver
111
100
  end
112
101
 
113
102
  UI.success("Successfully created new configuration files.")
114
-
115
- # get App icon + watch icon
116
- if v.large_app_icon.asset_token
117
- app_icon_extension = File.extname(v.large_app_icon.url)
118
- app_icon_path = File.join(path, "app_icon#{app_icon_extension}")
119
- File.write(app_icon_path, open(v.large_app_icon.url).read)
120
- UI.success("Successfully downloaded large app icon")
121
- end
122
- if v.watch_app_icon.asset_token
123
- watch_app_icon_extension = File.extname(v.watch_app_icon.url)
124
- watch_icon_path = File.join(path, "watch_icon#{watch_app_icon_extension}")
125
- File.write(watch_icon_path, open(v.watch_app_icon.url).read)
126
- UI.success("Successfully downloaded watch icon")
127
- end
128
103
  end
129
104
 
130
105
  def download_screenshots(path, options)
@@ -1,132 +1,216 @@
1
1
  require_relative 'module'
2
2
 
3
+ require 'fastlane_core/build_watcher'
4
+ require 'fastlane_core/ipa_file_analyser'
5
+ require 'fastlane_core/pkg_file_analyser'
6
+
3
7
  module Deliver
4
8
  class SubmitForReview
5
9
  def submit!(options)
6
- app = options[:app]
7
- select_build(options)
8
-
9
- UI.message("Submitting the app for review...")
10
- submission = app.create_submission(platform: options[:platform])
11
-
12
- # Set app submission information
13
- # Default Values
14
- submission.content_rights_contains_third_party_content = false
15
- submission.content_rights_has_rights = true
16
- submission.add_id_info_uses_idfa = false
17
-
18
- # User Values
19
- if options[:submission_information]
20
- options[:submission_information].each do |key, value|
21
- UI.message("Setting '#{key}' to '#{value}'...")
22
- submission.send("#{key}=", value)
23
- end
10
+ legacy_app = options[:app]
11
+ app_id = legacy_app.apple_id
12
+ app = Spaceship::ConnectAPI::App.get(app_id: app_id)
13
+
14
+ platform = Spaceship::ConnectAPI::Platform.map(options[:platform])
15
+ version = app.get_edit_app_store_version(platform: platform)
16
+
17
+ unless version
18
+ UI.user_error!("Cannot submit for review - could not find an editable version for '#{platform}'")
19
+ return
24
20
  end
25
21
 
26
- # Finalize app submission
27
- submission.complete!
22
+ build = select_build(options, app, version, platform)
23
+
24
+ update_export_compliance(options, app, build)
25
+ update_idfa(options, app, version)
26
+ update_submission_information(options, app)
27
+
28
+ version.create_app_store_version_submission
28
29
 
29
30
  UI.success("Successfully submitted the app for review!")
30
31
  end
31
32
 
32
- private def select_build(options)
33
- app = options[:app]
34
- app_version = options[:app_version]
35
- v = app.edit_version(platform: options[:platform])
36
-
33
+ private def select_build(options, app, version, platform)
37
34
  if options[:build_number] && options[:build_number] != "latest"
38
35
  UI.message("Selecting existing build-number: #{options[:build_number]}")
39
- if app_version
40
- build = v.candidate_builds.detect { |a| a.build_version == options[:build_number] && a.train_version == app_version }
41
- else
42
- build = v.candidate_builds.detect { |a| a.build_version == options[:build_number] }
43
- end
36
+
37
+ build = Spaceship::ConnectAPI::Build.all(
38
+ app_id: app.id,
39
+ version: options[:app_version],
40
+ build_number: options[:build_number],
41
+ platform: platform
42
+ ).first
43
+
44
44
  unless build
45
45
  UI.user_error!("Build number: #{options[:build_number]} does not exist")
46
46
  end
47
47
  else
48
48
  UI.message("Selecting the latest build...")
49
- build = wait_for_build(app, app_version)
49
+ build = wait_for_build_processing_to_be_complete(app: app, platform: platform, options: options)
50
50
  end
51
- UI.message("Selecting build #{app_version} (#{build.build_version})...")
51
+ UI.message("Selecting build #{build.app_version} (#{build.version})...")
52
52
 
53
- v.select_build(build)
54
- v.save!
53
+ version.select_build(build_id: build.id)
55
54
 
56
55
  UI.success("Successfully selected build")
56
+
57
+ return build
57
58
  end
58
59
 
59
- def wait_for_build(app, app_version)
60
- UI.user_error!("Could not find app with app identifier") unless app
60
+ def update_export_compliance(options, app, build)
61
+ submission_information = options[:submission_information] || {}
62
+ submission_information = submission_information.collect { |k, v| [k.to_sym, v] }.to_h
63
+
64
+ uses_encryption = submission_information[:export_compliance_uses_encryption]
65
+
66
+ if build.uses_non_exempt_encryption.nil?
67
+ UI.verbose("Updating build for export compliance status of '#{uses_encryption}'")
68
+
69
+ if uses_encryption.to_s.empty?
70
+ message = [
71
+ "Export compliance is required to submit",
72
+ "Add information to the :submission_information option...",
73
+ " Docs: http://docs.fastlane.tools/actions/deliver/#compliance-and-idfa-settings",
74
+ " Example: submission_information: { export_compliance_uses_encryption: false }",
75
+ " Example CLI:",
76
+ " --submission_information \"{\\\"export_compliance_uses_encryption\\\": false}\"",
77
+ "This can also be set in your Info.plist with key 'ITSAppUsesNonExemptEncryption'"
78
+ ].join("\n")
79
+ UI.user_error!(message)
80
+ end
81
+
82
+ build = build.update(attributes: {
83
+ usesNonExemptEncryption: uses_encryption
84
+ })
61
85
 
62
- start = Time.now
63
- build = nil
86
+ UI.verbose("Successfully updated build for export compliance status of '#{build.uses_non_exempt_encryption}' on App Store Connect")
87
+ end
88
+ end
64
89
 
65
- use_latest_version = app_version.nil?
90
+ def update_idfa(options, app, version)
91
+ submission_information = options[:submission_information] || {}
92
+ submission_information = submission_information.collect { |k, v| [k.to_sym, v] }.to_h
66
93
 
67
- loop do
68
- # Sometimes candidate_builds don't appear immediately after submission
69
- # Wait for candidate_builds to appear on App Store Connect
70
- # Issue https://github.com/fastlane/fastlane/issues/10411
71
- if use_latest_version
72
- candidate_builds = app.latest_version.candidate_builds
73
- else
74
- candidate_builds = app.tunes_all_builds_for_train(train: app_version)
75
- end
76
- if (candidate_builds || []).count == 0
77
- UI.message("Waiting for candidate builds to appear...")
78
- if (Time.now - start) > (60 * 5)
79
- UI.user_error!("Could not find any available candidate builds on App Store Connect to submit")
80
- else
81
- sleep(30)
82
- next
83
- end
84
- end
94
+ uses_idfa = submission_information[:add_id_info_uses_idfa]
85
95
 
86
- latest_build = find_build(candidate_builds)
96
+ idfa_declaration = begin
97
+ version.fetch_idfa_declaration
98
+ rescue
99
+ nil
100
+ end
87
101
 
88
- # if the app version isn't present in the hash (could happen if we are waiting for submission, but didn't provide
89
- # it explicitly and no ipa was passed to grab it from), then fall back to the best guess, which is the train_version
90
- # of the most recently uploaded build
91
- app_version ||= latest_build.train_version
102
+ updated_idfa = false
92
103
 
93
- # Sometimes latest build will disappear and a different build would get selected
94
- # Only set build if no latest build found or if same build versions as previously fetched build
95
- # Issue: https://github.com/fastlane/fastlane/issues/10945
96
- if build.nil? || (latest_build && latest_build.build_version == build.build_version && latest_build.train_version == app_version)
97
- build = latest_build
98
- end
104
+ # Set IDFA on version
105
+ unless uses_idfa.nil?
106
+ UI.verbose("Updating app store version for IDFA status of '#{uses_idfa}'")
107
+ version = version.update(attributes: {
108
+ usesIdfa: uses_idfa
109
+ })
110
+ UI.verbose("Updated app store version for IDFA status of '#{version.uses_idfa}'")
111
+ updated_idfa = true
112
+ end
99
113
 
100
- return build if build && build.processing == false
114
+ # Error if uses_idfa not set
115
+ if version.uses_idfa.nil?
116
+ message = [
117
+ "Use of Advertising Identifier (IDFA) is required to submit",
118
+ "Add information to the :submission_information option...",
119
+ " Docs: http://docs.fastlane.tools/actions/deliver/#compliance-and-idfa-settings",
120
+ " Example: submission_information: { add_id_info_uses_idfa: false }",
121
+ " Example: submission_information: {",
122
+ " add_id_info_uses_idfa: true,",
123
+ " add_id_info_limits_tracking: false,",
124
+ " add_id_info_serves_ads: false,",
125
+ " add_id_info_uses_idfa: false,",
126
+ " add_id_info_tracks_install: false",
127
+ " }",
128
+ " Example CLI:",
129
+ " --submission_information \"{\\\"add_id_info_uses_idfa\\\": false}\""
130
+ ].join("\n")
131
+ UI.user_error!(message)
132
+ end
101
133
 
102
- if build
103
- UI.message("Waiting App Store Connect processing for build #{app_version} (#{build.build_version})... this might take a while...")
134
+ # Create, update, or delete IDFA declaration
135
+ if uses_idfa == false
136
+ if idfa_declaration
137
+ UI.verbose("Deleting IDFA delcaration")
138
+ idfa_declaration.delete!
139
+ updated_idfa = true
140
+ UI.verbose("Deleted IDFA delcaration")
141
+ end
142
+ elsif uses_idfa == true
143
+ attributes = {
144
+ honorsLimitedAdTracking: !!submission_information[:add_id_info_limits_tracking],
145
+ servesAds: !!submission_information[:add_id_info_serves_ads],
146
+ attributesAppInstallationToPreviousAd: !!submission_information[:add_id_info_tracks_install],
147
+ attributesActionWithPreviousAd: !!submission_information[:add_id_info_tracks_action]
148
+ }
149
+
150
+ if idfa_declaration
151
+ UI.verbose("Updating IDFA delcaration")
152
+ idfa_declaration.update(attributes: attributes)
153
+ UI.verbose("Updated IDFA delcaration")
104
154
  else
105
- UI.message("Waiting App Store Connect processing for build... this might take a while...")
155
+ UI.verbose("Creating IDFA delcaration")
156
+ version.create_idfa_declaration(attributes: attributes)
157
+ UI.verbose("Created IDFA delcaration")
106
158
  end
107
159
 
108
- if (Time.now - start) > (60 * 5)
109
- UI.message("")
110
- UI.message("You can tweet: \"App Store Connect #iosprocessingtime #{((Time.now - start) / 60).round} minutes\"")
111
- end
112
- sleep(30)
160
+ updated_idfa = true
113
161
  end
114
- nil
162
+
163
+ UI.success("Successfully updated IDFA delcarations on App Store Connect") if updated_idfa
115
164
  end
116
165
 
117
- def find_build(candidate_builds)
118
- if (candidate_builds || []).count == 0
119
- UI.user_error!("Could not find any available candidate builds on App Store Connect to submit")
166
+ def update_submission_information(options, app)
167
+ submission_information = options[:submission_information] || {}
168
+ submission_information = submission_information.collect { |k, v| [k.to_sym, v] }.to_h
169
+
170
+ content_rights = submission_information[:content_rights_contains_third_party_content]
171
+
172
+ unless content_rights.nil?
173
+ value = if content_rights
174
+ Spaceship::ConnectAPI::App::ContentRightsDeclaration::USES_THIRD_PARTY_CONTENT
175
+ else
176
+ Spaceship::ConnectAPI::App::ContentRightsDeclaration::DOES_NOT_USE_THIRD_PARTY_CONTENT
177
+ end
178
+
179
+ UI.verbose("Updating contents rights declaration on App Store Connect")
180
+ app.update(attributes: {
181
+ contentRightsDeclaration: value
182
+ })
183
+ UI.success("Successfully updated contents rights declaration on App Store Connect")
120
184
  end
185
+ end
186
+
187
+ def wait_for_build_processing_to_be_complete(app: nil, platform: nil, options: nil)
188
+ app_version = options[:app_version]
121
189
 
122
- build = candidate_builds.first
123
- candidate_builds.each do |b|
124
- if b.upload_date > build.upload_date
125
- build = b
190
+ app_version ||= FastlaneCore::IpaFileAnalyser.fetch_app_version(options[:ipa]) if options[:ipa]
191
+ app_version ||= FastlaneCore::PkgFileAnalyser.fetch_app_version(options[:pkg]) if options[:pkg]
192
+
193
+ app_build ||= FastlaneCore::IpaFileAnalyser.fetch_app_build(options[:ipa]) if options[:ipa]
194
+ app_build ||= FastlaneCore::PkgFileAnalyser.fetch_app_build(options[:pkg]) if options[:pkg]
195
+
196
+ latest_build = FastlaneCore::BuildWatcher.wait_for_build_processing_to_be_complete(
197
+ app_id: app.id,
198
+ platform: platform,
199
+ app_version: app_version,
200
+ build_version: app_build,
201
+ poll_interval: 15,
202
+ return_when_build_appears: false,
203
+ return_spaceship_testflight_build: false,
204
+ select_latest: true
205
+ )
206
+
207
+ if !app_version.nil? && !app_build.nil?
208
+ unless latest_build.app_version == app_version && latest_build.version == app_build
209
+ UI.important("Uploaded app #{app_version} - #{app_build}, but received build #{latest_build.app_version} - #{latest_build.version}.")
126
210
  end
127
211
  end
128
212
 
129
- return build
213
+ return latest_build
130
214
  end
131
215
  end
132
216
  end