fastlane 2.149.1 → 2.150.0.rc1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (76) 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/options.rb +6 -11
  5. data/deliver/lib/deliver/runner.rb +7 -4
  6. data/deliver/lib/deliver/setup.rb +5 -30
  7. data/deliver/lib/deliver/submit_for_review.rb +124 -87
  8. data/deliver/lib/deliver/upload_metadata.rb +284 -143
  9. data/deliver/lib/deliver/upload_price_tier.rb +15 -8
  10. data/deliver/lib/deliver/upload_screenshots.rb +86 -37
  11. data/fastlane/lib/fastlane/actions/docs/capture_ios_screenshots.md +1 -1
  12. data/fastlane/lib/fastlane/actions/docs/upload_to_app_store.md.erb +3 -11
  13. data/fastlane/lib/fastlane/actions/docs/upload_to_play_store.md +3 -2
  14. data/fastlane/lib/fastlane/actions/download_dsyms.rb +7 -1
  15. data/fastlane/lib/fastlane/actions/google_play_track_release_names.rb +74 -0
  16. data/fastlane/lib/fastlane/actions/slack.rb +1 -1
  17. data/fastlane/lib/fastlane/actions/spm.rb +7 -0
  18. data/fastlane/lib/fastlane/actions/upload_symbols_to_crashlytics.rb +1 -32
  19. data/fastlane/lib/fastlane/lane.rb +3 -3
  20. data/fastlane/lib/fastlane/swift_fastlane_function.rb +8 -4
  21. data/fastlane/lib/fastlane/version.rb +1 -1
  22. data/fastlane/swift/ControlCommand.swift +1 -0
  23. data/fastlane/swift/Fastlane.swift +48 -12
  24. data/fastlane/swift/FastlaneSwiftRunner/FastlaneSwiftRunner.xcodeproj/xcshareddata/xcschemes/FastlaneRunner.xcscheme +3 -9
  25. data/fastlane/swift/LaneFileProtocol.swift +2 -5
  26. data/fastlane/swift/MatchfileProtocol.swift +1 -1
  27. data/fastlane/swift/RubyCommand.swift +29 -6
  28. data/fastlane/swift/RubyCommandable.swift +1 -0
  29. data/fastlane/swift/Runner.swift +85 -13
  30. data/fastlane/swift/ScanfileProtocol.swift +1 -1
  31. data/fastlane/swift/SnapshotfileProtocol.swift +3 -3
  32. data/fastlane/swift/SocketClient.swift +76 -45
  33. data/fastlane/swift/SocketClientDelegateProtocol.swift +1 -1
  34. data/fastlane/swift/SocketResponse.swift +1 -0
  35. data/fastlane_core/lib/fastlane_core/configuration/config_item.rb +1 -3
  36. data/fastlane_core/lib/fastlane_core/pkg_file_analyser.rb +7 -0
  37. data/frameit/lib/frameit/device_types.rb +100 -100
  38. data/produce/lib/produce/itunes_connect.rb +20 -20
  39. data/produce/lib/produce/options.rb +3 -3
  40. data/sigh/lib/assets/resign.sh +7 -7
  41. data/snapshot/lib/assets/SnapshotHelper.swift +5 -5
  42. data/snapshot/lib/assets/SnapshotHelperXcode8.swift +3 -3
  43. data/snapshot/lib/snapshot/options.rb +0 -1
  44. data/snapshot/lib/snapshot/reports_generator.rb +8 -1
  45. data/spaceship/lib/spaceship/.DS_Store +0 -0
  46. data/spaceship/lib/spaceship/connect_api.rb +21 -2
  47. data/spaceship/lib/spaceship/connect_api/client.rb +47 -11
  48. data/spaceship/lib/spaceship/connect_api/model.rb +1 -1
  49. data/spaceship/lib/spaceship/connect_api/models/age_rating_declaration.rb +109 -0
  50. data/spaceship/lib/spaceship/connect_api/models/app.rb +113 -3
  51. data/spaceship/lib/spaceship/connect_api/models/app_category.rb +94 -0
  52. data/spaceship/lib/spaceship/connect_api/models/app_info.rb +74 -0
  53. data/spaceship/lib/spaceship/connect_api/models/app_info_localization.rb +38 -0
  54. data/spaceship/lib/spaceship/connect_api/models/app_price.rb +22 -0
  55. data/spaceship/lib/spaceship/connect_api/models/app_price_tier.rb +12 -0
  56. data/spaceship/lib/spaceship/connect_api/models/app_review_attachment.rb +81 -0
  57. data/spaceship/lib/spaceship/connect_api/models/app_screenshot.rb +117 -0
  58. data/spaceship/lib/spaceship/connect_api/models/app_screenshot_set.rb +101 -0
  59. data/spaceship/lib/spaceship/connect_api/models/app_store_review_detail.rb +51 -0
  60. data/spaceship/lib/spaceship/connect_api/models/app_store_version.rb +182 -0
  61. data/spaceship/lib/spaceship/connect_api/models/app_store_version_localization.rb +70 -0
  62. data/spaceship/lib/spaceship/connect_api/models/app_store_version_phased_release.rb +36 -0
  63. data/spaceship/lib/spaceship/connect_api/models/app_store_version_submission.rb +26 -0
  64. data/spaceship/lib/spaceship/connect_api/models/build.rb +4 -0
  65. data/spaceship/lib/spaceship/connect_api/models/idfa_declaration.rb +40 -0
  66. data/spaceship/lib/spaceship/connect_api/models/reset_ratings_request.rb +26 -0
  67. data/spaceship/lib/spaceship/connect_api/testflight/testflight.rb +10 -3
  68. data/spaceship/lib/spaceship/connect_api/tunes/client.rb +33 -0
  69. data/spaceship/lib/spaceship/connect_api/tunes/tunes.rb +703 -0
  70. data/spaceship/lib/spaceship/spaceauth_runner.rb +2 -2
  71. data/supply/lib/supply/client.rb +19 -0
  72. data/supply/lib/supply/reader.rb +16 -0
  73. metadata +27 -24
  74. data/deliver/lib/deliver/upload_assets.rb +0 -27
  75. data/scan/lib/scan/.test_command_generator.rb.swp +0 -0
  76. data/snapshot/lib/snapshot/.test_command_generator_base.rb.swp +0 -0
@@ -2,40 +2,38 @@ require_relative 'module'
2
2
 
3
3
  module Deliver
4
4
  # upload description, rating, etc.
5
+ # rubocop:disable Metrics/ClassLength
5
6
  class UploadMetadata
6
7
  # All the localised values attached to the version
7
- LOCALISED_VERSION_VALUES = [:description, :keywords, :release_notes, :support_url, :marketing_url, :promotional_text]
8
+ LOCALISED_VERSION_VALUES = {
9
+ description: "description",
10
+ keywords: "keywords",
11
+ release_notes: "whatsNew",
12
+ support_url: "supportUrl",
13
+ marketing_url: "marketingUrl",
14
+ promotional_text: "promotionalText"
15
+ }
8
16
 
9
17
  # Everything attached to the version but not being localised
10
- NON_LOCALISED_VERSION_VALUES = [:copyright]
18
+ NON_LOCALISED_VERSION_VALUES = {
19
+ copyright: "copyright"
20
+ }
11
21
 
12
22
  # Localised app details values
13
- LOCALISED_APP_VALUES = [:name, :subtitle, :privacy_url, :apple_tv_privacy_policy]
23
+ LOCALISED_APP_VALUES = {
24
+ name: "name",
25
+ subtitle: "subtitle",
26
+ privacy_url: "privacyPolicyUrl",
27
+ apple_tv_privacy_policy: "privacyPolicyText"
28
+ }
14
29
 
15
30
  # Non localized app details values
16
31
  NON_LOCALISED_APP_VALUES = [:primary_category, :secondary_category,
17
32
  :primary_first_sub_category, :primary_second_sub_category,
18
33
  :secondary_first_sub_category, :secondary_second_sub_category]
19
34
 
20
- # Trade Representative Contact Information values
21
- TRADE_REPRESENTATIVE_CONTACT_INFORMATION_VALUES = {
22
- trade_representative_trade_name: :trade_name,
23
- trade_representative_first_name: :first_name,
24
- trade_representative_last_name: :last_name,
25
- trade_representative_address_line_1: :address_line1,
26
- trade_representative_address_line_2: :address_line2,
27
- trade_representative_address_line_3: :address_line3,
28
- trade_representative_city_name: :city_name,
29
- trade_representative_state: :state,
30
- trade_representative_country: :country,
31
- trade_representative_postal_code: :postal_code,
32
- trade_representative_phone_number: :phone_number,
33
- trade_representative_email: :email_address,
34
- trade_representative_is_displayed_on_app_store: :is_displayed_on_app_store
35
- }
36
-
37
35
  # Review information values
38
- REVIEW_INFORMATION_VALUES = {
36
+ REVIEW_INFORMATION_VALUES_LEGACY = {
39
37
  review_first_name: :first_name,
40
38
  review_last_name: :last_name,
41
39
  review_phone_number: :phone_number,
@@ -44,6 +42,15 @@ module Deliver
44
42
  review_demo_password: :demo_password,
45
43
  review_notes: :notes
46
44
  }
45
+ REVIEW_INFORMATION_VALUES = {
46
+ first_name: "contactFirstName",
47
+ last_name: "contactLastName",
48
+ phone_number: "contactPhone",
49
+ email_address: "contactEmail",
50
+ demo_user: "demoAccountName",
51
+ demo_password: "demoAccountPassword",
52
+ notes: "notes"
53
+ }
47
54
 
48
55
  # Localized app details values, that are editable in live state
49
56
  LOCALISED_LIVE_VALUES = [:description, :release_notes, :support_url, :marketing_url, :promotional_text, :privacy_url]
@@ -66,35 +73,46 @@ module Deliver
66
73
  # Make sure to call `load_from_filesystem` before calling upload
67
74
  def upload(options)
68
75
  return if options[:skip_metadata]
69
- # it is not possible to create new languages, because
70
- # :keywords is not write-able on published versions
71
- # therefore skip it.
72
- verify_available_languages!(options) unless options[:edit_live]
73
76
 
74
- app = options[:app]
77
+ legacy_app = options[:app]
78
+ app_id = legacy_app.apple_id
79
+ app = Spaceship::ConnectAPI::App.get(app_id: app_id)
80
+
81
+ platform = Spaceship::ConnectAPI::Platform.map(options[:platform])
82
+
83
+ app_store_version_localizations = verify_available_version_languages!(options, app) unless options[:edit_live]
84
+ app_info_localizations = verify_available_info_languages!(options, app) unless options[:edit_live]
75
85
 
76
- details = app.details
77
86
  if options[:edit_live]
78
87
  # not all values are editable when using live_version
79
- v = app.live_version(platform: options[:platform])
88
+ version = app.get_live_app_store_version(platform: platform)
80
89
  localised_options = LOCALISED_LIVE_VALUES
81
90
  non_localised_options = NON_LOCALISED_LIVE_VALUES
82
91
 
83
92
  if v.nil?
84
93
  UI.message("Couldn't find live version, editing the current version on App Store Connect instead")
85
- v = app.edit_version(platform: options[:platform])
94
+ version = app.get_edit_app_store_version(platform: platform)
86
95
  # we don't want to update the localised_options and non_localised_options
87
96
  # as we also check for `options[:edit_live]` at other areas in the code
88
97
  # by not touching those 2 variables, deliver is more consistent with what the option says
89
98
  # in the documentation
99
+ else
100
+ UI.message("Found live version")
90
101
  end
91
102
  else
92
- v = app.edit_version(platform: options[:platform])
93
- localised_options = (LOCALISED_VERSION_VALUES + LOCALISED_APP_VALUES)
94
- non_localised_options = (NON_LOCALISED_VERSION_VALUES + NON_LOCALISED_APP_VALUES)
103
+ version = app.get_edit_app_store_version(platform: platform)
104
+ localised_options = (LOCALISED_VERSION_VALUES.keys + LOCALISED_APP_VALUES.keys)
105
+ non_localised_options = NON_LOCALISED_VERSION_VALUES.keys
95
106
  end
96
107
 
97
- individual = options[:individual_metadata_items] || []
108
+ # Needed for to filter out release notes from being sent up
109
+ is_first_version = app.get_live_app_store_version(platform: platform).nil?
110
+
111
+ UI.important("Will begin uploading metadata for '#{version.version_string}' on App Store Connect")
112
+
113
+ localized_version_attributes_by_locale = {}
114
+ localized_info_attributes_by_locale = {}
115
+
98
116
  localised_options.each do |key|
99
117
  current = options[key]
100
118
  next unless current
@@ -104,70 +122,139 @@ module Deliver
104
122
  next
105
123
  end
106
124
 
125
+ if key == :release_notes && is_first_version
126
+ UI.error("Skipping 'release_notes'... this is the first version of the app")
127
+ next
128
+ end
129
+
107
130
  current.each do |language, value|
108
131
  next unless value.to_s.length > 0
109
132
  strip_value = value.to_s.strip
110
- if individual.include?(key.to_s)
111
- upload_individual_item(app, v, language, key, strip_value)
112
- else
113
- v.send(key)[language] = strip_value if LOCALISED_VERSION_VALUES.include?(key)
114
- details.send(key)[language] = strip_value if LOCALISED_APP_VALUES.include?(key)
133
+
134
+ if LOCALISED_VERSION_VALUES.include?(key) && !strip_value.empty?
135
+ attribute_name = LOCALISED_VERSION_VALUES[key]
136
+
137
+ localized_version_attributes_by_locale[language] ||= {}
138
+ localized_version_attributes_by_locale[language][attribute_name] = strip_value
115
139
  end
140
+
141
+ next unless LOCALISED_APP_VALUES.include?(key) && !strip_value.empty?
142
+ attribute_name = LOCALISED_APP_VALUES[key]
143
+
144
+ localized_info_attributes_by_locale[language] ||= {}
145
+ localized_info_attributes_by_locale[language][attribute_name] = strip_value
116
146
  end
117
147
  end
118
148
 
149
+ non_localized_version_attributes = {}
119
150
  non_localised_options.each do |key|
120
- current = options[key].to_s.strip
121
- next unless current.to_s.length > 0
122
- v.send("#{key}=", current) if NON_LOCALISED_VERSION_VALUES.include?(key)
123
- details.send("#{key}=", current) if NON_LOCALISED_APP_VALUES.include?(key)
151
+ strip_value = options[key].to_s.strip
152
+ next unless strip_value.to_s.length > 0
153
+
154
+ if NON_LOCALISED_VERSION_VALUES.include?(key) && !strip_value.empty?
155
+ attribute_name = NON_LOCALISED_VERSION_VALUES[key]
156
+ non_localized_version_attributes[attribute_name] = strip_value
157
+ end
124
158
  end
125
159
 
126
- v.release_on_approval = options[:automatic_release]
127
- v.auto_release_date = options[:auto_release_date] unless options[:auto_release_date].nil?
128
- v.toggle_phased_release(enabled: !!options[:phased_release]) unless options[:phased_release].nil?
160
+ release_type = if options[:auto_release_date]
161
+ non_localized_version_attributes['earliestReleaseDate'] = options[:auto_release_date]
162
+ Spaceship::ConnectAPI::AppStoreVersion::ReleaseType::SCHEDULED
163
+ elsif options[:automatic_release]
164
+ Spaceship::ConnectAPI::AppStoreVersion::ReleaseType::AFTER_APPROVAL
165
+ else
166
+ Spaceship::ConnectAPI::AppStoreVersion::ReleaseType::MANUAL
167
+ end
168
+ non_localized_version_attributes['releaseType'] = release_type
169
+
170
+ # Update app store version localizations
171
+ app_store_version_localizations.each do |app_store_version_localization|
172
+ attributes = localized_version_attributes_by_locale[app_store_version_localization.locale]
173
+ if attributes
174
+ UI.message("Uploading metadata to App Store Connect for localized version '#{app_store_version_localization.locale}'")
175
+ app_store_version_localization.update(attributes: attributes)
176
+ end
177
+ end
129
178
 
130
- set_trade_representative_contact_information(v, options)
131
- set_review_information(v, options)
132
- set_app_rating(v, options)
133
- v.ratings_reset = options[:reset_ratings] unless options[:reset_ratings].nil?
179
+ # Update app info localizations
180
+ app_info_localizations.each do |app_info_localization|
181
+ attributes = localized_info_attributes_by_locale[app_info_localization.locale]
182
+ if attributes
183
+ UI.message("Uploading metadata to App Store Connect for localized info '#{app_info_localization.locale}'")
184
+ app_info_localization.update(attributes: attributes)
185
+ end
186
+ end
134
187
 
135
- set_review_attachment_file(v, options)
188
+ # Update app store version
189
+ UI.message("Uploading metadata to App Store Connect for version")
190
+ version.update(attributes: non_localized_version_attributes)
191
+
192
+ # Update categories
193
+ app_info = app.fetch_edit_app_info
194
+ if app_info
195
+ app_info.update_categories(
196
+ primary_category_id: Spaceship::ConnectAPI::AppCategory.map_category_from_itc(
197
+ options[:primary_category].to_s.strip
198
+ ),
199
+ secondary_category_id: Spaceship::ConnectAPI::AppCategory.map_category_from_itc(
200
+ options[:secondary_category].to_s.strip
201
+ ),
202
+ primary_subcategory_one_id: Spaceship::ConnectAPI::AppCategory.map_subcategory_from_itc(
203
+ options[:primary_first_sub_category].to_s.strip
204
+ ),
205
+ primary_subcategory_two_id: Spaceship::ConnectAPI::AppCategory.map_subcategory_from_itc(
206
+ options[:primary_second_sub_category].to_s.strip
207
+ ),
208
+ secondary_subcategory_one_id: Spaceship::ConnectAPI::AppCategory.map_subcategory_from_itc(
209
+ options[:secondary_first_sub_category].to_s.strip
210
+ ),
211
+ secondary_subcategory_two_id: Spaceship::ConnectAPI::AppCategory.map_subcategory_from_itc(
212
+ options[:secondary_second_sub_category].to_s.strip
213
+ )
214
+ )
215
+ end
136
216
 
137
- Helper.show_loading_indicator("Uploading metadata to App Store Connect")
138
- v.save!
139
- Helper.hide_loading_indicator
140
- begin
141
- details.save!
142
- UI.success("Successfully uploaded set of metadata to App Store Connect")
143
- rescue Spaceship::TunesClient::ITunesConnectError => e
144
- # This makes sure that we log invalid app names as user errors
145
- # If another string needs to be checked here we should
146
- # figure out a more generic way to handle these cases.
147
- if e.message.include?('App Name cannot be longer than 50 characters') || e.message.include?('The app name you entered is already being used')
148
- UI.error("Error in app name. Try using 'individual_metadata_items' to identify the problem language.")
149
- UI.user_error!(e.message)
150
- else
151
- raise e
217
+ # Update phased release
218
+ unless options[:phased_release].nil?
219
+ phased_release = begin
220
+ version.fetch_app_store_version_phased_release
221
+ rescue
222
+ nil
223
+ end # returns no data error so need to rescue
224
+ if !!options[:phased_release]
225
+ unless phased_release
226
+ UI.message("Creating phased release on App Store Connect")
227
+ version.create_app_store_version_phased_release(attributes: {
228
+ phasedReleaseState: Spaceship::ConnectAPI::AppStoreVersionPhasedRelease::PhasedReleaseState::INACTIVE
229
+ })
230
+ end
231
+ elsif phased_release
232
+ UI.message("Removing phased release on App Store Connect")
233
+ phased_release.delete!
152
234
  end
153
235
  end
154
- end
155
236
 
156
- # Uploads metadata individually by language to help identify exactly which items have issues
157
- def upload_individual_item(app, version, language, key, value)
158
- details = app.details
159
- version.send(key)[language] = value if LOCALISED_VERSION_VALUES.include?(key)
160
- details.send(key)[language] = value if LOCALISED_APP_VALUES.include?(key)
161
- Helper.show_loading_indicator("Uploading #{language} #{key} to App Store Connect")
162
- version.save!
163
- Helper.hide_loading_indicator
164
- begin
165
- details.save!
166
- UI.success("Successfully uploaded #{language} #{key} to App Store Connect")
167
- rescue Spaceship::TunesClient::ITunesConnectError => e
168
- UI.error("Error in #{language} #{key}: \n#{value}")
169
- UI.error(e.message) # Don't use user_error to allow all values to get checked
237
+ # Update rating reset
238
+ unless options[:reset_ratings].nil?
239
+ reset_rating_request = begin
240
+ version.fetch_reset_ratings_request
241
+ rescue
242
+ nil
243
+ end # returns no data error so need to rescue
244
+ if !!options[:reset_ratings]
245
+ unless reset_rating_request
246
+ UI.message("Creating reset ratings request on App Store Connect")
247
+ version.create_reset_ratings_request
248
+ end
249
+ elsif reset_rating_request
250
+ UI.message("Removing reset ratings request on App Store Connect")
251
+ reset_rating_request.delete!
252
+ end
170
253
  end
254
+
255
+ set_review_information(version, options)
256
+ set_review_attachment_file(version, options)
257
+ set_app_rating(version, options)
171
258
  end
172
259
 
173
260
  # rubocop:enable Metrics/PerceivedComplexity
@@ -181,7 +268,7 @@ module Deliver
181
268
  enabled_languages = detect_languages(options)
182
269
 
183
270
  # Get all languages used in existing settings
184
- (LOCALISED_VERSION_VALUES + LOCALISED_APP_VALUES).each do |key|
271
+ (LOCALISED_VERSION_VALUES.keys + LOCALISED_APP_VALUES.keys).each do |key|
185
272
  current = options[key]
186
273
  next unless current && current.kind_of?(Hash)
187
274
  current.each do |language, value|
@@ -200,7 +287,7 @@ module Deliver
200
287
  return unless enabled_languages.include?("default")
201
288
  UI.message("Detected languages: " + enabled_languages.to_s)
202
289
 
203
- (LOCALISED_VERSION_VALUES + LOCALISED_APP_VALUES).each do |key|
290
+ (LOCALISED_VERSION_VALUES.keys + LOCALISED_APP_VALUES.keys).each do |key|
204
291
  current = options[key]
205
292
  next unless current && current.kind_of?(Hash)
206
293
 
@@ -222,7 +309,7 @@ module Deliver
222
309
  enabled_languages = options[:languages] || []
223
310
 
224
311
  # Get all languages used in existing settings
225
- (LOCALISED_VERSION_VALUES + LOCALISED_APP_VALUES).each do |key|
312
+ (LOCALISED_VERSION_VALUES.keys + LOCALISED_APP_VALUES.keys).each do |key|
226
313
  current = options[key]
227
314
  next unless current && current.kind_of?(Hash)
228
315
  current.each do |language, value|
@@ -245,41 +332,73 @@ module Deliver
245
332
  .uniq
246
333
  end
247
334
 
248
- # Makes sure all languages we need are actually created
249
- def verify_available_languages!(options)
250
- return if options[:skip_metadata]
335
+ # Finding languages to enable
336
+ def verify_available_info_languages!(options, app)
337
+ app_info = app.fetch_edit_app_info
251
338
 
252
- # Collect all languages we need
253
- # We only care about languages from user provided values
254
- # as the other languages are on iTC already anyway
255
- v = options[:app].edit_version(platform: options[:platform])
256
- UI.user_error!("Could not find a version to edit for app '#{options[:app].name}', the app metadata is read-only currently") unless v
339
+ unless app_info
340
+ UI.user_error!("Cannot update languages - could not find an editable info")
341
+ return
342
+ end
257
343
 
258
- enabled_languages = options[:languages] || []
259
- LOCALISED_VERSION_VALUES.each do |key|
260
- current = options[key]
261
- next unless current && current.kind_of?(Hash)
262
- current.each do |language, value|
263
- language = language.to_s
264
- enabled_languages << language unless enabled_languages.include?(language)
344
+ localizations = app_info.get_app_info_localizations
345
+
346
+ languages = options[:languages] || []
347
+ locales_to_enable = languages - localizations.map(&:locale)
348
+
349
+ if locales_to_enable.count > 0
350
+ lng_text = "language"
351
+ lng_text += "s" if locales_to_enable.count != 1
352
+ Helper.show_loading_indicator("Activating info #{lng_text} #{locales_to_enable.join(', ')}...")
353
+
354
+ locales_to_enable.each do |locale|
355
+ app_info.create_app_info_localization(attributes: {
356
+ locale: locale
357
+ })
265
358
  end
359
+
360
+ Helper.hide_loading_indicator
361
+
362
+ # Refresh version localizations
363
+ localizations = app_info.get_app_info_localizations
266
364
  end
267
365
 
268
- # Reject "default" language from getting enabled
269
- # because "default" is not an iTC language
270
- enabled_languages = enabled_languages.reject do |lang|
271
- lang == "default"
272
- end.uniq
366
+ return localizations
367
+ end
273
368
 
274
- if enabled_languages.count > 0
275
- v.create_languages(enabled_languages)
369
+ # Finding languages to enable
370
+ def verify_available_version_languages!(options, app)
371
+ platform = Spaceship::ConnectAPI::Platform.map(options[:platform])
372
+ version = app.get_edit_app_store_version(platform: platform)
373
+
374
+ unless version
375
+ UI.user_error!("Cannot update languages - could not find an editable version for '#{platform}'")
376
+ return
377
+ end
378
+
379
+ localizations = version.get_app_store_version_localizations
380
+
381
+ languages = options[:languages] || []
382
+ locales_to_enable = languages - localizations.map(&:locale)
383
+
384
+ if locales_to_enable.count > 0
276
385
  lng_text = "language"
277
- lng_text += "s" if enabled_languages.count != 1
278
- Helper.show_loading_indicator("Activating #{lng_text} #{enabled_languages.join(', ')}...")
279
- v.save!
386
+ lng_text += "s" if locales_to_enable.count != 1
387
+ Helper.show_loading_indicator("Activating version #{lng_text} #{locales_to_enable.join(', ')}...")
388
+
389
+ locales_to_enable.each do |locale|
390
+ version.create_app_store_version_localization(attributes: {
391
+ locale: locale
392
+ })
393
+ end
394
+
280
395
  Helper.hide_loading_indicator
396
+
397
+ # Refresh version localizations
398
+ localizations = version.get_app_store_version_localizations
281
399
  end
282
- true
400
+
401
+ return localizations
283
402
  end
284
403
 
285
404
  # Loads the metadata files and stores them into the options object
@@ -290,7 +409,7 @@ module Deliver
290
409
  ignore_validation = options[:ignore_language_directory_validation]
291
410
  Loader.language_folders(options[:metadata_path], ignore_validation).each do |lang_folder|
292
411
  language = File.basename(lang_folder)
293
- (LOCALISED_VERSION_VALUES + LOCALISED_APP_VALUES).each do |key|
412
+ (LOCALISED_VERSION_VALUES.keys + LOCALISED_APP_VALUES.keys).each do |key|
294
413
  path = File.join(lang_folder, "#{key}.txt")
295
414
  next unless File.exist?(path)
296
415
 
@@ -301,7 +420,7 @@ module Deliver
301
420
  end
302
421
 
303
422
  # Load non localised data
304
- (NON_LOCALISED_VERSION_VALUES + NON_LOCALISED_APP_VALUES).each do |key|
423
+ (NON_LOCALISED_VERSION_VALUES.keys + NON_LOCALISED_APP_VALUES).each do |key|
305
424
  path = File.join(options[:metadata_path], "#{key}.txt")
306
425
  next unless File.exist?(path)
307
426
 
@@ -309,20 +428,9 @@ module Deliver
309
428
  options[key] ||= File.read(path)
310
429
  end
311
430
 
312
- # Load trade representative contact information
313
- options[:trade_representative_contact_information] ||= {}
314
- TRADE_REPRESENTATIVE_CONTACT_INFORMATION_VALUES.values.each do |option_name|
315
- path = File.join(options[:metadata_path], TRADE_REPRESENTATIVE_CONTACT_INFORMATION_DIR, "#{option_name}.txt")
316
- next unless File.exist?(path)
317
- next if options[:trade_representative_contact_information][option_name].to_s.length > 0
318
-
319
- UI.message("Loading '#{path}'...")
320
- options[:trade_representative_contact_information][option_name] ||= File.read(path)
321
- end
322
-
323
431
  # Load review information
324
432
  options[:app_review_information] ||= {}
325
- REVIEW_INFORMATION_VALUES.values.each do |option_name|
433
+ REVIEW_INFORMATION_VALUES.keys.each do |option_name|
326
434
  path = File.join(options[:metadata_path], REVIEW_INFORMATION_DIR, "#{option_name}.txt")
327
435
  next unless File.exist?(path)
328
436
  next if options[:app_review_information][option_name].to_s.length > 0
@@ -336,7 +444,7 @@ module Deliver
336
444
 
337
445
  # Normalizes languages keys from symbols to strings
338
446
  def normalize_language_keys(options)
339
- (LOCALISED_VERSION_VALUES + LOCALISED_APP_VALUES).each do |key|
447
+ (LOCALISED_VERSION_VALUES.keys + LOCALISED_APP_VALUES.keys).each do |key|
340
448
  current = options[key]
341
449
  next unless current && current.kind_of?(Hash)
342
450
 
@@ -348,33 +456,55 @@ module Deliver
348
456
  options
349
457
  end
350
458
 
351
- def set_trade_representative_contact_information(v, options)
352
- return unless options[:trade_representative_contact_information]
353
- info = options[:trade_representative_contact_information]
354
- UI.user_error!("`trade_representative_contact_information` must be a hash", show_github_issues: true) unless info.kind_of?(Hash)
355
-
356
- TRADE_REPRESENTATIVE_CONTACT_INFORMATION_VALUES.each do |key, option_name|
357
- v.send("#{key}=", info[option_name].to_s.chomp) if info[option_name]
358
- end
359
- end
360
-
361
- def set_review_information(v, options)
459
+ def set_review_information(version, options)
362
460
  return unless options[:app_review_information]
363
461
  info = options[:app_review_information]
364
462
  UI.user_error!("`app_review_information` must be a hash", show_github_issues: true) unless info.kind_of?(Hash)
365
463
 
366
- REVIEW_INFORMATION_VALUES.each do |key, option_name|
367
- v.send("#{key}=", info[option_name].to_s.chomp) if info[option_name]
464
+ attributes = {}
465
+ REVIEW_INFORMATION_VALUES.each do |key, attribute_name|
466
+ strip_value = info[key].to_s.strip
467
+ attributes[attribute_name] = strip_value unless strip_value.empty?
468
+ end
469
+
470
+ if !attributes["demoAccountName"].to_s.empty? && !attributes["demoAccountPassword"].to_s.empty?
471
+ attributes["demoAccountRequired"] = true
472
+ else
473
+ attributes["demoAccountRequired"] = false
474
+ end
475
+
476
+ UI.message("Uploading app review information to App Store Connect")
477
+ app_store_review_detail = begin
478
+ version.fetch_app_store_review_detail
479
+ rescue
480
+ nil
481
+ end # errors if doesn't exist
482
+ if app_store_review_detail
483
+ app_store_review_detail.update(attributes: attributes)
484
+ else
485
+ version.create_app_store_review_detail(attributes: attributes)
368
486
  end
369
- v.review_user_needed = (v.review_demo_user.to_s.chomp + v.review_demo_password.to_s.chomp).length > 0
370
487
  end
371
488
 
372
- def set_review_attachment_file(v, options)
373
- return unless options[:app_review_attachment_file]
374
- v.upload_review_attachment!(options[:app_review_attachment_file])
489
+ def set_review_attachment_file(version, options)
490
+ app_store_review_detail = version.fetch_app_store_review_detail
491
+ app_review_attachments = app_store_review_detail.fetch_app_review_attachments
492
+
493
+ if options[:app_review_attachment_file]
494
+ app_review_attachments.each do |app_review_attachment|
495
+ UI.message("Removing previous review attachment file from App Store Connect")
496
+ app_review_attachment.delete!
497
+ end
498
+
499
+ UI.message("Uploading review attachment file to App Store Connect")
500
+ app_store_review_detail.upload_attachment(path: options[:app_review_attachment_file])
501
+ else
502
+ app_review_attachments.each(&:delete!)
503
+ UI.message("Removing review attachment file to App Store Connect") unless app_review_attachments.empty?
504
+ end
375
505
  end
376
506
 
377
- def set_app_rating(v, options)
507
+ def set_app_rating(version, options)
378
508
  return unless options[:app_rating_config_path]
379
509
 
380
510
  require 'json'
@@ -385,7 +515,18 @@ module Deliver
385
515
  UI.user_error!("Error parsing JSON file at path '#{options[:app_rating_config_path]}'")
386
516
  end
387
517
  UI.message("Setting the app's age rating...")
388
- v.update_rating(json)
518
+
519
+ # Maping from legacy ITC values to App Store Connect Values
520
+ attributes = {}
521
+ json.each do |k, v|
522
+ new_key = Spaceship::ConnectAPI::AgeRatingDeclaration.map_key_from_itc(k)
523
+ new_value = Spaceship::ConnectAPI::AgeRatingDeclaration.map_value_from_itc(new_key, v)
524
+ attributes[new_key] = new_value
525
+ end
526
+
527
+ age_rating_delcaration = version.fetch_age_rating_declaration
528
+ age_rating_delcaration.update(attributes: attributes)
389
529
  end
390
530
  end
531
+ # rubocop:enable Metrics/ClassLength
391
532
  end