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
@@ -1,132 +1,197 @@
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
+ uses_encryption = submission_information[:export_compliance_uses_encryption]
63
+
64
+ if build.uses_non_exempt_encryption.nil?
65
+ UI.verbose("Updating build for export compliance status of '#{uses_encryption}'")
66
+
67
+ if uses_encryption.to_s.empty?
68
+ message = [
69
+ "Export compliance is required to submit",
70
+ "Add information to the :submission_information option...",
71
+ " Docs: http://docs.fastlane.tools/actions/deliver/#compliance-and-idfa-settings",
72
+ " Example: submission_information: { export_compliance_uses_encryption: false }",
73
+ "This can also be set in your Info.plist with key 'ITSAppUsesNonExemptEncryption'"
74
+ ].join("\n")
75
+ UI.user_error!(message)
76
+ end
77
+
78
+ build = build.update(attributes: {
79
+ usesNonExemptEncryption: uses_encryption
80
+ })
61
81
 
62
- start = Time.now
63
- build = nil
82
+ UI.verbose("Successfully updated build for export compliance status of '#{build.uses_non_exempt_encryption}' on App Store Connect")
83
+ end
84
+ end
64
85
 
65
- use_latest_version = app_version.nil?
86
+ def update_idfa(options, app, version)
87
+ submission_information = options[:submission_information] || {}
88
+ uses_idfa = submission_information[:add_id_info_uses_idfa]
89
+
90
+ idfa_declaration = begin
91
+ version.fetch_idfa_declaration
92
+ rescue
93
+ nil
94
+ end
95
+
96
+ # Set IDFA on version
97
+ UI.verbose("Updating app store version for IDFA status of '#{uses_idfa}'")
98
+ unless uses_idfa.nil?
99
+ version = version.update(attributes: {
100
+ usesIdfa: uses_idfa
101
+ })
102
+ end
103
+ UI.verbose("Updated app store version for IDFA status of '#{version.uses_idfa}'")
104
+
105
+ # Error if uses_idfa not set
106
+ if version.uses_idfa.nil?
107
+ message = [
108
+ "Use of Advertising Identifier (IDFA) is required to submit",
109
+ "Add information to the :submission_information option...",
110
+ " Docs: http://docs.fastlane.tools/actions/deliver/#compliance-and-idfa-settings",
111
+ " Example: submission_information: { add_id_info_uses_idfa: false }",
112
+ " Example: submission_information: {",
113
+ " add_id_info_uses_idfa: true,",
114
+ " add_id_info_limits_tracking: false,",
115
+ " add_id_info_serves_ads: false,",
116
+ " add_id_info_uses_idfa: false,",
117
+ " add_id_info_tracks_install: false",
118
+ " }"
119
+ ].join("\n")
120
+ UI.user_error!(message)
121
+ end
66
122
 
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)
123
+ # Create, update, or delete IDFA declaration
124
+ if uses_idfa == false
125
+ if idfa_declaration
126
+ UI.verbose("Deleting IDFA delcaration")
127
+ idfa_declaration.delete!
128
+ UI.verbose("Deleted IDFA delcaration")
75
129
  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
130
+ elsif uses_idfa == true
131
+ attributes = {
132
+ honorsLimitedAdTracking: !!submission_information[:add_id_info_limits_tracking],
133
+ servesAds: !!submission_information[:add_id_info_serves_ads],
134
+ attributesAppInstallationToPreviousAd: !!submission_information[:add_id_info_tracks_install],
135
+ attributesActionWithPreviousAd: !!submission_information[:add_id_info_tracks_action]
136
+ }
137
+
138
+ if idfa_declaration
139
+ UI.verbose("Updating IDFA delcaration")
140
+ idfa_declaration.update(attributes: attributes)
141
+ UI.verbose("Updated IDFA delcaration")
142
+ else
143
+ UI.verbose("Creating IDFA delcaration")
144
+ version.create_idfa_declaration(attributes: attributes)
145
+ UI.verbose("Created IDFA delcaration")
84
146
  end
147
+ end
85
148
 
86
- latest_build = find_build(candidate_builds)
149
+ UI.success("Successfully updated IDFA delcarations on App Store Connect")
150
+ end
87
151
 
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
152
+ def update_submission_information(options, app)
153
+ submission_information = options[:submission_information] || {}
92
154
 
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
155
+ content_rights = submission_information[:content_rights_contains_third_party_content]
99
156
 
100
- return build if build && build.processing == false
157
+ unless content_rights.nil?
158
+ value = if content_rights
159
+ Spaceship::ConnectAPI::App::ContentRightsDeclaration::USES_THIRD_PARTY_CONTENT
160
+ else
161
+ Spaceship::ConnectAPI::App::ContentRightsDeclaration::DOES_NOT_USE_THIRD_PARTY_CONTENT
162
+ end
101
163
 
102
- if build
103
- UI.message("Waiting App Store Connect processing for build #{app_version} (#{build.build_version})... this might take a while...")
104
- else
105
- UI.message("Waiting App Store Connect processing for build... this might take a while...")
106
- end
107
-
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)
164
+ UI.verbose("Updating contents rights declaration on App Store Connect")
165
+ app.update(attributes: {
166
+ contentRightsDeclaration: value
167
+ })
168
+ UI.success("Successfully updated contents rights declaration on App Store Connect")
113
169
  end
114
- nil
115
170
  end
116
171
 
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")
120
- end
121
-
122
- build = candidate_builds.first
123
- candidate_builds.each do |b|
124
- if b.upload_date > build.upload_date
125
- build = b
126
- end
172
+ def wait_for_build_processing_to_be_complete(app: nil, platform: nil, options: nil)
173
+ app_version = options[:app_version]
174
+ app_version ||= FastlaneCore::IpaFileAnalyser.fetch_app_version(options[:ipa]) if options[:ipa]
175
+ app_version ||= FastlaneCore::PkgFileAnalyser.fetch_app_version(options[:pkg]) if options[:pkg]
176
+
177
+ app_build ||= FastlaneCore::IpaFileAnalyser.fetch_app_build(options[:ipa]) if options[:ipa]
178
+ app_build ||= FastlaneCore::PkgFileAnalyser.fetch_app_build(options[:pkg]) if options[:pkg]
179
+
180
+ latest_build = FastlaneCore::BuildWatcher.wait_for_build_processing_to_be_complete(
181
+ app_id: app.id,
182
+ platform: platform,
183
+ app_version: app_version,
184
+ build_version: app_build,
185
+ poll_interval: 15,
186
+ return_when_build_appears: false,
187
+ return_spaceship_testflight_build: false
188
+ )
189
+
190
+ unless latest_build.app_version == app_version && latest_build.version == app_build
191
+ UI.important("Uploaded app #{app_version} - #{app_build}, but received build #{latest_build.app_version} - #{latest_build.version}.")
127
192
  end
128
193
 
129
- return build
194
+ return latest_build
130
195
  end
131
196
  end
132
197
  end
@@ -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,195 @@ 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)
136
191
 
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
192
+ # Update categories
193
+ app_info = app.fetch_edit_app_info
194
+ if app_info
195
+ category_id_map = {}
196
+
197
+ primary_category = options[:primary_category].to_s.strip
198
+ secondary_category = options[:secondary_category].to_s.strip
199
+ primary_first_sub_category = options[:primary_first_sub_category].to_s.strip
200
+ primary_second_sub_category = options[:primary_second_sub_category].to_s.strip
201
+ secondary_first_sub_category = options[:secondary_first_sub_category].to_s.strip
202
+ secondary_second_sub_category = options[:secondary_second_sub_category].to_s.strip
203
+
204
+ mapped_values = {}
205
+
206
+ # Only update primary and secondar category if explicitly set
207
+ unless primary_category.empty?
208
+ mapped = Spaceship::ConnectAPI::AppCategory.map_category_from_itc(
209
+ primary_category
210
+ )
211
+
212
+ mapped_values[primary_category] = mapped
213
+ category_id_map[:primary_category_id] = mapped
214
+ end
215
+ unless secondary_category.empty?
216
+ mapped = Spaceship::ConnectAPI::AppCategory.map_category_from_itc(
217
+ secondary_category
218
+ )
219
+
220
+ mapped_values[secondary_category] = mapped
221
+ category_id_map[:secondary_category_id] = mapped
152
222
  end
223
+
224
+ # Only set if primary category is going to be set
225
+ unless primary_category.empty?
226
+ mapped = Spaceship::ConnectAPI::AppCategory.map_subcategory_from_itc(
227
+ primary_first_sub_category
228
+ )
229
+
230
+ mapped_values[primary_first_sub_category] = mapped
231
+ category_id_map[:primary_subcategory_one_id] = mapped
232
+ end
233
+ unless primary_category.empty?
234
+ mapped = Spaceship::ConnectAPI::AppCategory.map_subcategory_from_itc(
235
+ primary_second_sub_category
236
+ )
237
+
238
+ mapped_values[primary_second_sub_category] = mapped
239
+ category_id_map[:primary_subcategory_two_id] = mapped
240
+ end
241
+
242
+ # Only set if secondary category is going to be set
243
+ unless secondary_category.empty?
244
+ mapped = Spaceship::ConnectAPI::AppCategory.map_subcategory_from_itc(
245
+ secondary_first_sub_category
246
+ )
247
+
248
+ mapped_values[secondary_first_sub_category] = mapped
249
+ category_id_map[:secondary_subcategory_one_id] = mapped
250
+ end
251
+ unless secondary_category.empty?
252
+ mapped = Spaceship::ConnectAPI::AppCategory.map_subcategory_from_itc(
253
+ secondary_second_sub_category
254
+ )
255
+
256
+ mapped_values[secondary_second_sub_category] = mapped
257
+ category_id_map[:secondary_subcategory_two_id] = mapped
258
+ end
259
+
260
+ # Print deprecation warnings if category was mapped
261
+ has_mapped_values = false
262
+ mapped_values.each do |k, v|
263
+ next if k.nil? || v.nil?
264
+ next if k == v
265
+ has_mapped_values = true
266
+ UI.deprecated("Category '#{k}' from iTunesConnect as been deprecated. Please replace with '#{v}'")
267
+ end
268
+ UI.deprecated("You can find more info at https://docs.fastlane.tools/actions/deliver/#reference") if has_mapped_values
269
+
270
+ app_info.update_categories(category_id_map: category_id_map)
153
271
  end
154
- end
155
272
 
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
273
+ # Update phased release
274
+ unless options[:phased_release].nil?
275
+ phased_release = begin
276
+ version.fetch_app_store_version_phased_release
277
+ rescue
278
+ nil
279
+ end # returns no data error so need to rescue
280
+ if !!options[:phased_release]
281
+ unless phased_release
282
+ UI.message("Creating phased release on App Store Connect")
283
+ version.create_app_store_version_phased_release(attributes: {
284
+ phasedReleaseState: Spaceship::ConnectAPI::AppStoreVersionPhasedRelease::PhasedReleaseState::INACTIVE
285
+ })
286
+ end
287
+ elsif phased_release
288
+ UI.message("Removing phased release on App Store Connect")
289
+ phased_release.delete!
290
+ end
170
291
  end
292
+
293
+ # Update rating reset
294
+ unless options[:reset_ratings].nil?
295
+ reset_rating_request = begin
296
+ version.fetch_reset_ratings_request
297
+ rescue
298
+ nil
299
+ end # returns no data error so need to rescue
300
+ if !!options[:reset_ratings]
301
+ unless reset_rating_request
302
+ UI.message("Creating reset ratings request on App Store Connect")
303
+ version.create_reset_ratings_request
304
+ end
305
+ elsif reset_rating_request
306
+ UI.message("Removing reset ratings request on App Store Connect")
307
+ reset_rating_request.delete!
308
+ end
309
+ end
310
+
311
+ set_review_information(version, options)
312
+ set_review_attachment_file(version, options)
313
+ set_app_rating(version, options)
171
314
  end
172
315
 
173
316
  # rubocop:enable Metrics/PerceivedComplexity
@@ -181,7 +324,7 @@ module Deliver
181
324
  enabled_languages = detect_languages(options)
182
325
 
183
326
  # Get all languages used in existing settings
184
- (LOCALISED_VERSION_VALUES + LOCALISED_APP_VALUES).each do |key|
327
+ (LOCALISED_VERSION_VALUES.keys + LOCALISED_APP_VALUES.keys).each do |key|
185
328
  current = options[key]
186
329
  next unless current && current.kind_of?(Hash)
187
330
  current.each do |language, value|
@@ -200,7 +343,7 @@ module Deliver
200
343
  return unless enabled_languages.include?("default")
201
344
  UI.message("Detected languages: " + enabled_languages.to_s)
202
345
 
203
- (LOCALISED_VERSION_VALUES + LOCALISED_APP_VALUES).each do |key|
346
+ (LOCALISED_VERSION_VALUES.keys + LOCALISED_APP_VALUES.keys).each do |key|
204
347
  current = options[key]
205
348
  next unless current && current.kind_of?(Hash)
206
349
 
@@ -222,7 +365,7 @@ module Deliver
222
365
  enabled_languages = options[:languages] || []
223
366
 
224
367
  # Get all languages used in existing settings
225
- (LOCALISED_VERSION_VALUES + LOCALISED_APP_VALUES).each do |key|
368
+ (LOCALISED_VERSION_VALUES.keys + LOCALISED_APP_VALUES.keys).each do |key|
226
369
  current = options[key]
227
370
  next unless current && current.kind_of?(Hash)
228
371
  current.each do |language, value|
@@ -245,41 +388,73 @@ module Deliver
245
388
  .uniq
246
389
  end
247
390
 
248
- # Makes sure all languages we need are actually created
249
- def verify_available_languages!(options)
250
- return if options[:skip_metadata]
391
+ # Finding languages to enable
392
+ def verify_available_info_languages!(options, app)
393
+ app_info = app.fetch_edit_app_info
251
394
 
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
395
+ unless app_info
396
+ UI.user_error!("Cannot update languages - could not find an editable info")
397
+ return
398
+ end
257
399
 
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)
400
+ localizations = app_info.get_app_info_localizations
401
+
402
+ languages = (options[:languages] || []).reject { |lang| lang == "default" }
403
+ locales_to_enable = languages - localizations.map(&:locale)
404
+
405
+ if locales_to_enable.count > 0
406
+ lng_text = "language"
407
+ lng_text += "s" if locales_to_enable.count != 1
408
+ Helper.show_loading_indicator("Activating info #{lng_text} #{locales_to_enable.join(', ')}...")
409
+
410
+ locales_to_enable.each do |locale|
411
+ app_info.create_app_info_localization(attributes: {
412
+ locale: locale
413
+ })
265
414
  end
415
+
416
+ Helper.hide_loading_indicator
417
+
418
+ # Refresh version localizations
419
+ localizations = app_info.get_app_info_localizations
420
+ end
421
+
422
+ return localizations
423
+ end
424
+
425
+ # Finding languages to enable
426
+ def verify_available_version_languages!(options, app)
427
+ platform = Spaceship::ConnectAPI::Platform.map(options[:platform])
428
+ version = app.get_edit_app_store_version(platform: platform)
429
+
430
+ unless version
431
+ UI.user_error!("Cannot update languages - could not find an editable version for '#{platform}'")
432
+ return
266
433
  end
267
434
 
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
435
+ localizations = version.get_app_store_version_localizations
273
436
 
274
- if enabled_languages.count > 0
275
- v.create_languages(enabled_languages)
437
+ languages = (options[:languages] || []).reject { |lang| lang == "default" }
438
+ locales_to_enable = languages - localizations.map(&:locale)
439
+
440
+ if locales_to_enable.count > 0
276
441
  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!
442
+ lng_text += "s" if locales_to_enable.count != 1
443
+ Helper.show_loading_indicator("Activating version #{lng_text} #{locales_to_enable.join(', ')}...")
444
+
445
+ locales_to_enable.each do |locale|
446
+ version.create_app_store_version_localization(attributes: {
447
+ locale: locale
448
+ })
449
+ end
450
+
280
451
  Helper.hide_loading_indicator
452
+
453
+ # Refresh version localizations
454
+ localizations = version.get_app_store_version_localizations
281
455
  end
282
- true
456
+
457
+ return localizations
283
458
  end
284
459
 
285
460
  # Loads the metadata files and stores them into the options object
@@ -290,7 +465,7 @@ module Deliver
290
465
  ignore_validation = options[:ignore_language_directory_validation]
291
466
  Loader.language_folders(options[:metadata_path], ignore_validation).each do |lang_folder|
292
467
  language = File.basename(lang_folder)
293
- (LOCALISED_VERSION_VALUES + LOCALISED_APP_VALUES).each do |key|
468
+ (LOCALISED_VERSION_VALUES.keys + LOCALISED_APP_VALUES.keys).each do |key|
294
469
  path = File.join(lang_folder, "#{key}.txt")
295
470
  next unless File.exist?(path)
296
471
 
@@ -301,7 +476,7 @@ module Deliver
301
476
  end
302
477
 
303
478
  # Load non localised data
304
- (NON_LOCALISED_VERSION_VALUES + NON_LOCALISED_APP_VALUES).each do |key|
479
+ (NON_LOCALISED_VERSION_VALUES.keys + NON_LOCALISED_APP_VALUES).each do |key|
305
480
  path = File.join(options[:metadata_path], "#{key}.txt")
306
481
  next unless File.exist?(path)
307
482
 
@@ -309,20 +484,9 @@ module Deliver
309
484
  options[key] ||= File.read(path)
310
485
  end
311
486
 
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
487
  # Load review information
324
488
  options[:app_review_information] ||= {}
325
- REVIEW_INFORMATION_VALUES.values.each do |option_name|
489
+ REVIEW_INFORMATION_VALUES.keys.each do |option_name|
326
490
  path = File.join(options[:metadata_path], REVIEW_INFORMATION_DIR, "#{option_name}.txt")
327
491
  next unless File.exist?(path)
328
492
  next if options[:app_review_information][option_name].to_s.length > 0
@@ -336,7 +500,7 @@ module Deliver
336
500
 
337
501
  # Normalizes languages keys from symbols to strings
338
502
  def normalize_language_keys(options)
339
- (LOCALISED_VERSION_VALUES + LOCALISED_APP_VALUES).each do |key|
503
+ (LOCALISED_VERSION_VALUES.keys + LOCALISED_APP_VALUES.keys).each do |key|
340
504
  current = options[key]
341
505
  next unless current && current.kind_of?(Hash)
342
506
 
@@ -348,33 +512,55 @@ module Deliver
348
512
  options
349
513
  end
350
514
 
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)
515
+ def set_review_information(version, options)
362
516
  return unless options[:app_review_information]
363
517
  info = options[:app_review_information]
364
518
  UI.user_error!("`app_review_information` must be a hash", show_github_issues: true) unless info.kind_of?(Hash)
365
519
 
366
- REVIEW_INFORMATION_VALUES.each do |key, option_name|
367
- v.send("#{key}=", info[option_name].to_s.chomp) if info[option_name]
520
+ attributes = {}
521
+ REVIEW_INFORMATION_VALUES.each do |key, attribute_name|
522
+ strip_value = info[key].to_s.strip
523
+ attributes[attribute_name] = strip_value unless strip_value.empty?
524
+ end
525
+
526
+ if !attributes["demoAccountName"].to_s.empty? && !attributes["demoAccountPassword"].to_s.empty?
527
+ attributes["demoAccountRequired"] = true
528
+ else
529
+ attributes["demoAccountRequired"] = false
530
+ end
531
+
532
+ UI.message("Uploading app review information to App Store Connect")
533
+ app_store_review_detail = begin
534
+ version.fetch_app_store_review_detail
535
+ rescue
536
+ nil
537
+ end # errors if doesn't exist
538
+ if app_store_review_detail
539
+ app_store_review_detail.update(attributes: attributes)
540
+ else
541
+ version.create_app_store_review_detail(attributes: attributes)
368
542
  end
369
- v.review_user_needed = (v.review_demo_user.to_s.chomp + v.review_demo_password.to_s.chomp).length > 0
370
543
  end
371
544
 
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])
545
+ def set_review_attachment_file(version, options)
546
+ app_store_review_detail = version.fetch_app_store_review_detail
547
+ app_review_attachments = app_store_review_detail.fetch_app_review_attachments
548
+
549
+ if options[:app_review_attachment_file]
550
+ app_review_attachments.each do |app_review_attachment|
551
+ UI.message("Removing previous review attachment file from App Store Connect")
552
+ app_review_attachment.delete!
553
+ end
554
+
555
+ UI.message("Uploading review attachment file to App Store Connect")
556
+ app_store_review_detail.upload_attachment(path: options[:app_review_attachment_file])
557
+ else
558
+ app_review_attachments.each(&:delete!)
559
+ UI.message("Removing review attachment file to App Store Connect") unless app_review_attachments.empty?
560
+ end
375
561
  end
376
562
 
377
- def set_app_rating(v, options)
563
+ def set_app_rating(version, options)
378
564
  return unless options[:app_rating_config_path]
379
565
 
380
566
  require 'json'
@@ -385,7 +571,33 @@ module Deliver
385
571
  UI.user_error!("Error parsing JSON file at path '#{options[:app_rating_config_path]}'")
386
572
  end
387
573
  UI.message("Setting the app's age rating...")
388
- v.update_rating(json)
574
+
575
+ # Maping from legacy ITC values to App Store Connect Values
576
+ mapped_values = {}
577
+ attributes = {}
578
+ json.each do |k, v|
579
+ new_key = Spaceship::ConnectAPI::AgeRatingDeclaration.map_key_from_itc(k)
580
+ new_value = Spaceship::ConnectAPI::AgeRatingDeclaration.map_value_from_itc(new_key, v)
581
+
582
+ mapped_values[k] = new_key
583
+ mapped_values[v] = new_value
584
+
585
+ attributes[new_key] = new_value
586
+ end
587
+
588
+ # Print deprecation warnings if category was mapped
589
+ has_mapped_values = false
590
+ mapped_values.each do |k, v|
591
+ next if k.nil? || v.nil?
592
+ next if k == v
593
+ has_mapped_values = true
594
+ UI.deprecated("Age rating '#{k}' from iTunesConnect as been deprecated. Please replace with '#{v}'")
595
+ end
596
+ UI.deprecated("You can find more info at https://docs.fastlane.tools/actions/deliver/#reference") if has_mapped_values
597
+
598
+ age_rating_delcaration = version.fetch_age_rating_declaration
599
+ age_rating_delcaration.update(attributes: attributes)
389
600
  end
390
601
  end
602
+ # rubocop:enable Metrics/ClassLength
391
603
  end