fastlane 2.132.0 → 2.135.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (71) hide show
  1. checksums.yaml +5 -5
  2. data/README.md +74 -74
  3. data/fastlane/lib/fastlane/action.rb +1 -1
  4. data/fastlane/lib/fastlane/actions/actions_helper.rb +1 -1
  5. data/fastlane/lib/fastlane/actions/carthage.rb +7 -0
  6. data/fastlane/lib/fastlane/actions/cocoapods.rb +24 -2
  7. data/fastlane/lib/fastlane/actions/deploygate.rb +1 -1
  8. data/fastlane/lib/fastlane/actions/docs/capture_ios_screenshots.md +1 -1
  9. data/fastlane/lib/fastlane/actions/docs/sync_code_signing.md +4 -2
  10. data/fastlane/lib/fastlane/actions/docs/upload_to_play_store.md +26 -2
  11. data/fastlane/lib/fastlane/actions/download_dsyms.rb +26 -3
  12. data/fastlane/lib/fastlane/actions/download_from_play_store.rb +1 -1
  13. data/fastlane/lib/fastlane/actions/get_version_number.rb +10 -4
  14. data/fastlane/lib/fastlane/actions/google_play_track_version_codes.rb +5 -1
  15. data/fastlane/lib/fastlane/actions/sonar.rb +16 -0
  16. data/fastlane/lib/fastlane/actions/testfairy.rb +1 -1
  17. data/fastlane/lib/fastlane/actions/update_fastlane.rb +9 -49
  18. data/fastlane/lib/fastlane/actions/update_keychain_access_groups.rb +94 -0
  19. data/fastlane/lib/fastlane/environment_printer.rb +9 -3
  20. data/fastlane/lib/fastlane/fast_file.rb +3 -2
  21. data/fastlane/lib/fastlane/lane_manager.rb +1 -1
  22. data/fastlane/lib/fastlane/plugins/plugin_manager.rb +12 -2
  23. data/fastlane/lib/fastlane/plugins/template/.rubocop.yml +1 -0
  24. data/fastlane/lib/fastlane/runner.rb +2 -2
  25. data/fastlane/lib/fastlane/swift_fastlane_api_generator.rb +10 -2
  26. data/fastlane/lib/fastlane/swift_fastlane_function.rb +72 -3
  27. data/fastlane/lib/fastlane/version.rb +1 -1
  28. data/fastlane/swift/Deliverfile.swift +1 -1
  29. data/fastlane/swift/DeliverfileProtocol.swift +121 -1
  30. data/fastlane/swift/Fastlane.swift +3900 -16
  31. data/fastlane/swift/Gymfile.swift +1 -1
  32. data/fastlane/swift/GymfileProtocol.swift +81 -1
  33. data/fastlane/swift/Matchfile.swift +1 -1
  34. data/fastlane/swift/MatchfileProtocol.swift +60 -2
  35. data/fastlane/swift/Precheckfile.swift +1 -1
  36. data/fastlane/swift/PrecheckfileProtocol.swift +15 -2
  37. data/fastlane/swift/Scanfile.swift +1 -1
  38. data/fastlane/swift/ScanfileProtocol.swift +109 -1
  39. data/fastlane/swift/Screengrabfile.swift +1 -1
  40. data/fastlane/swift/ScreengrabfileProtocol.swift +39 -2
  41. data/fastlane/swift/Snapshotfile.swift +1 -1
  42. data/fastlane/swift/SnapshotfileProtocol.swift +69 -1
  43. data/fastlane_core/lib/fastlane_core/configuration/commander_generator.rb +3 -3
  44. data/fastlane_core/lib/fastlane_core/configuration/configuration.rb +1 -1
  45. data/fastlane_core/lib/fastlane_core/device_manager.rb +1 -1
  46. data/fastlane_core/lib/fastlane_core/swag.rb +1 -1
  47. data/fastlane_core/lib/fastlane_core/ui/fastlane_runner.rb +1 -1
  48. data/match/lib/match/importer.rb +1 -1
  49. data/match/lib/match/storage/google_cloud_storage.rb +3 -0
  50. data/scan/lib/scan/error_handler.rb +9 -4
  51. data/scan/lib/scan/runner.rb +1 -1
  52. data/sigh/lib/assets/resign.sh +2 -2
  53. data/snapshot/lib/snapshot/simulator_launchers/simulator_launcher.rb +1 -1
  54. data/spaceship/lib/spaceship/client.rb +2 -2
  55. data/supply/lib/supply.rb +23 -0
  56. data/supply/lib/supply/.options.rb.swp +0 -0
  57. data/supply/lib/supply/.uploader.rb.swp +0 -0
  58. data/supply/lib/supply/client.rb +101 -55
  59. data/supply/lib/supply/options.rb +50 -14
  60. data/supply/lib/supply/release_listing.rb +18 -0
  61. data/supply/lib/supply/setup.rb +42 -34
  62. data/supply/lib/supply/uploader.rb +171 -93
  63. metadata +36 -41
  64. data/fastlane/lib/fastlane/actions/.hockey.rb.swp +0 -0
  65. data/fastlane/lib/fastlane/actions/.slack.rb.swp +0 -0
  66. data/fastlane/lib/fastlane/actions/.update_project_provisioning.rb.swp +0 -0
  67. data/fastlane/swift/FastlaneSwiftRunner/FastlaneSwiftRunner.xcodeproj/project.xcworkspace/xcuserdata/josh.xcuserdatad/UserInterfaceState.xcuserstate +0 -0
  68. data/gym/lib/gym/.runner.rb.swp +0 -0
  69. data/pilot/lib/pilot/.manager.rb.swp +0 -0
  70. data/spaceship/lib/spaceship/connect_api/.DS_Store +0 -0
  71. data/spaceship/lib/spaceship/portal/.certificate.rb.swp +0 -0
@@ -5,7 +5,6 @@ module Supply
5
5
  class Options
6
6
  # rubocop:disable Metrics/PerceivedComplexity
7
7
  def self.available_options
8
- default_tracks = %w(production beta alpha internal rollout)
9
8
  @options ||= [
10
9
  FastlaneCore::ConfigItem.new(key: :package_name,
11
10
  env_name: "SUPPLY_PACKAGE_NAME",
@@ -14,11 +13,37 @@ module Supply
14
13
  code_gen_sensitive: true,
15
14
  default_value: CredentialsManager::AppfileConfig.try_fetch_value(:package_name),
16
15
  default_value_dynamic: true),
16
+ FastlaneCore::ConfigItem.new(key: :version_name,
17
+ env_name: "SUPPLY_VERSION_NAME",
18
+ short_option: "-n",
19
+ optional: true,
20
+ description: "Version name (used when uploading new apks/aabs) - defaults to 'versionName' in build.gradle or AndroidManifest.xml",
21
+ default_value: CredentialsManager::AppfileConfig.try_fetch_value(:version_name),
22
+ default_value_dynamic: true),
23
+ FastlaneCore::ConfigItem.new(key: :version_code,
24
+ env_name: "SUPPLY_VERSION_CODE",
25
+ short_option: "-C",
26
+ optional: true,
27
+ type: Integer,
28
+ description: "Version code (used when updating rollout or promoting specific versions)",
29
+ default_value: CredentialsManager::AppfileConfig.try_fetch_value(:version_code),
30
+ default_value_dynamic: true),
31
+ FastlaneCore::ConfigItem.new(key: :release_status,
32
+ env_name: "SUPPLY_RELEASE_STATUS",
33
+ short_option: "-e",
34
+ optional: true,
35
+ description: "Release status (used when uploading new apks/aabs) - valid values are #{Supply::ReleaseStatus::ALL.join(', ')}",
36
+ default_value: Supply::ReleaseStatus::COMPLETED,
37
+ default_value_dynamic: true,
38
+ verify_block: proc do |value|
39
+ UI.user_error!("Value must be one of '#{Supply::RELEASE_STATUS}'") unless Supply::ReleaseStatus::ALL.include?(value)
40
+ end),
17
41
  FastlaneCore::ConfigItem.new(key: :track,
18
42
  short_option: "-a",
19
43
  env_name: "SUPPLY_TRACK",
20
- description: "The track of the application to use. The default available tracks are: #{default_tracks.join(', ')}",
21
- default_value: 'production'),
44
+ description: "The track of the application to use. The default available tracks are: #{Supply::Tracks::DEFAULTS.join(', ')}",
45
+ default_value: Supply::Tracks::DEFAULT,
46
+ type: String),
22
47
  FastlaneCore::ConfigItem.new(key: :rollout,
23
48
  short_option: "-r",
24
49
  description: "The percentage of the user fraction when uploading to the rollout track",
@@ -104,6 +129,7 @@ module Supply
104
129
  FastlaneCore::ConfigItem.new(key: :apk_paths,
105
130
  env_name: "SUPPLY_APK_PATHS",
106
131
  conflicting_options: [:apk, :aab, :aab_paths],
132
+ code_gen_sensitive: true,
107
133
  optional: true,
108
134
  type: Array,
109
135
  description: "An array of paths to APK files to upload",
@@ -131,6 +157,7 @@ module Supply
131
157
  FastlaneCore::ConfigItem.new(key: :aab_paths,
132
158
  env_name: "SUPPLY_AAB_PATHS",
133
159
  conflicting_options: [:apk, :apk_paths, :aab],
160
+ code_gen_sensitive: true,
134
161
  optional: true,
135
162
  type: Array,
136
163
  description: "An array of paths to AAB files to upload",
@@ -146,41 +173,47 @@ module Supply
146
173
  env_name: "SUPPLY_SKIP_UPLOAD_APK",
147
174
  optional: true,
148
175
  description: "Whether to skip uploading APK",
149
- is_string: false,
176
+ type: Boolean,
150
177
  default_value: false),
151
178
  FastlaneCore::ConfigItem.new(key: :skip_upload_aab,
152
179
  env_name: "SUPPLY_SKIP_UPLOAD_AAB",
153
180
  optional: true,
154
181
  description: "Whether to skip uploading AAB",
155
- is_string: false,
182
+ type: Boolean,
156
183
  default_value: false),
157
184
  FastlaneCore::ConfigItem.new(key: :skip_upload_metadata,
158
185
  env_name: "SUPPLY_SKIP_UPLOAD_METADATA",
159
186
  optional: true,
160
- description: "Whether to skip uploading metadata",
161
- is_string: false,
187
+ description: "Whether to skip uploading metadata, changelogs not included",
188
+ type: Boolean,
189
+ default_value: false),
190
+ FastlaneCore::ConfigItem.new(key: :skip_upload_changelogs,
191
+ env_name: "SUPPLY_SKIP_UPLOAD_CHANGELOGS",
192
+ optional: true,
193
+ description: "Whether to skip uploading changelogs",
194
+ type: Boolean,
162
195
  default_value: false),
163
196
  FastlaneCore::ConfigItem.new(key: :skip_upload_images,
164
197
  env_name: "SUPPLY_SKIP_UPLOAD_IMAGES",
165
198
  optional: true,
166
199
  description: "Whether to skip uploading images, screenshots not included",
167
- is_string: false,
200
+ type: Boolean,
168
201
  default_value: false),
169
202
  FastlaneCore::ConfigItem.new(key: :skip_upload_screenshots,
170
203
  env_name: "SUPPLY_SKIP_UPLOAD_SCREENSHOTS",
171
204
  optional: true,
172
205
  description: "Whether to skip uploading SCREENSHOTS",
173
- is_string: false,
206
+ type: Boolean,
174
207
  default_value: false),
175
208
  FastlaneCore::ConfigItem.new(key: :track_promote_to,
176
209
  env_name: "SUPPLY_TRACK_PROMOTE_TO",
177
210
  optional: true,
178
- description: "The track to promote to. The default available tracks are: #{default_tracks.join(', ')}"),
211
+ description: "The track to promote to. The default available tracks are: #{Supply::Tracks::DEFAULTS.join(', ')}"),
179
212
  FastlaneCore::ConfigItem.new(key: :validate_only,
180
213
  env_name: "SUPPLY_VALIDATE_ONLY",
181
214
  optional: true,
182
215
  description: "Only validate changes with Google Play rather than actually publish",
183
- is_string: false,
216
+ type: Boolean,
184
217
  default_value: false),
185
218
  FastlaneCore::ConfigItem.new(key: :mapping,
186
219
  env_name: "SUPPLY_MAPPING",
@@ -215,7 +248,8 @@ module Supply
215
248
  env_name: "SUPPLY_CHECK_SUPERSEDED_TRACKS",
216
249
  optional: true,
217
250
  description: "Check the other tracks for superseded versions and disable them",
218
- is_string: false,
251
+ deprecated: "Google Play does this automatically now",
252
+ type: Boolean,
219
253
  default_value: false),
220
254
  FastlaneCore::ConfigItem.new(key: :timeout,
221
255
  env_name: "SUPPLY_TIMEOUT",
@@ -227,16 +261,18 @@ module Supply
227
261
  env_name: "SUPPLY_DEACTIVATE_ON_PROMOTE",
228
262
  optional: true,
229
263
  description: "When promoting to a new track, deactivate the binary in the origin track",
230
- is_string: false,
264
+ deprecated: "Google Play does this automatically now",
265
+ type: Boolean,
231
266
  default_value: true),
232
267
  FastlaneCore::ConfigItem.new(key: :version_codes_to_retain,
233
268
  optional: true,
234
269
  type: Array,
235
270
  description: "An array of version codes to retain when publishing a new APK",
236
271
  verify_block: proc do |version_codes|
272
+ version_codes = version_codes.map(&:to_i)
237
273
  UI.user_error!("Could not evaluate array from '#{version_codes}'") unless version_codes.kind_of?(Array)
238
274
  version_codes.each do |version_code|
239
- UI.user_error!("Version code '#{version_code}' is not an integer") unless version_code.kind_of?(Integer)
275
+ UI.user_error!("Version code '#{version_code}' is not an integer") if version_code == 0
240
276
  end
241
277
  end),
242
278
  FastlaneCore::ConfigItem.new(key: :obb_main_references_version,
@@ -0,0 +1,18 @@
1
+ module Supply
2
+ class ReleaseListing
3
+ attr_accessor :track
4
+ attr_accessor :version
5
+ attr_accessor :versioncodes
6
+ attr_accessor :language
7
+ attr_accessor :release_notes
8
+
9
+ # Initializes the release listing with the current listing if available
10
+ def initialize(track, version, versioncodes, language, text)
11
+ self.track = track
12
+ self.version = version
13
+ self.versioncodes = versioncodes
14
+ self.language = language
15
+ self.release_notes = text
16
+ end
17
+ end
18
+ end
@@ -12,16 +12,22 @@ module Supply
12
12
 
13
13
  client.listings.each do |listing|
14
14
  store_metadata(listing)
15
- create_screenshots_folder(listing)
16
15
  download_images(listing)
17
16
  end
18
17
 
19
- client.apks_version_codes.each do |apk_version_code|
20
- client.apk_listings(apk_version_code).each do |apk_listing|
21
- store_apk_listing(apk_listing)
18
+ if Supply.config[:version_name].to_s == ""
19
+ latest_version = client.latest_version(Supply.config[:track])
20
+ if latest_version
21
+ Supply.config[:version_name] = latest_version.name
22
+ else
23
+ UI.user_error!("Could not find the latest version to download metadata, images, and screenshots from")
22
24
  end
23
25
  end
24
26
 
27
+ client.release_listings(Supply.config[:version_name]).each do |release_listing|
28
+ store_release_listing(release_listing)
29
+ end
30
+
25
31
  client.abort_current_edit
26
32
 
27
33
  UI.success("✅ Successfully stored metadata in '#{metadata_path}'")
@@ -43,25 +49,40 @@ module Supply
43
49
  def download_images(listing)
44
50
  UI.message("🖼️ Downloading images (#{listing.language})")
45
51
 
46
- # We cannot download existing screenshots as they are compressed
47
- # But we can at least download the images
48
52
  require 'net/http'
49
53
 
50
- IMAGES_TYPES.each do |image_type|
51
- if ['featureGraphic'].include?(image_type)
52
- # we don't get all files in full resolution :(
53
- UI.message("📵 Due to a limitation of the Google Play API, there is no way for `supply` to download your existing feature graphic. Please copy your feature graphic to `metadata/android/#{listing.language}/images/featureGraphic.png`")
54
- next
55
- end
54
+ allowed_imagetypes = [Supply::IMAGES_TYPES, Supply::SCREENSHOT_TYPES].flatten
56
55
 
56
+ allowed_imagetypes.each do |image_type|
57
57
  begin
58
+ path = File.join(metadata_path, listing.language, IMAGES_FOLDER_NAME, image_type)
59
+
60
+ p = Pathname.new(path)
61
+ if IMAGES_TYPES.include?(image_type) # IMAGE_TYPES are stored in locale/images location
62
+ FileUtils.mkdir_p(p.dirname.to_s)
63
+ else # SCREENSHOT_TYPES go under their respective folders.
64
+ FileUtils.mkdir_p(p.to_s)
65
+ end
66
+
58
67
  UI.message("Downloading `#{image_type}` for #{listing.language}...")
59
68
 
60
- url = client.fetch_images(image_type: image_type, language: listing.language).last
61
- next unless url
69
+ urls = client.fetch_images(image_type: image_type, language: listing.language)
70
+ next if urls.nil? || urls.empty?
71
+
72
+ image_counter = 1 # Used to prefix the downloaded files, so order is preserved.
73
+ urls.each do |url|
74
+ if IMAGES_TYPES.include?(image_type) # IMAGE_TYPES are stored in locale/images
75
+ file_path = "#{path}.#{FastImage.type(url)}"
76
+ else # SCREENSHOT_TYPES are stored in locale/images/<screensho_types>
77
+ file_path = File.join(path, "#{image_counter}_#{listing.language}.#{FastImage.type(url)}")
78
+ end
79
+
80
+ File.binwrite(file_path, Net::HTTP.get(URI.parse(url)))
81
+
82
+ UI.message("\tDownloaded - #{file_path}")
62
83
 
63
- path = File.join(metadata_path, listing.language, IMAGES_FOLDER_NAME, "#{image_type}.png")
64
- File.write(path, Net::HTTP.get(URI.parse(url)))
84
+ image_counter += 1
85
+ end
65
86
  rescue => ex
66
87
  UI.error(ex.to_s)
67
88
  UI.error("Error downloading '#{image_type}' for #{listing.language}...")
@@ -69,30 +90,17 @@ module Supply
69
90
  end
70
91
  end
71
92
 
72
- def create_screenshots_folder(listing)
73
- UI.message("📱 Downloading screenshots (#{listing.language})")
74
-
75
- containing = File.join(metadata_path, listing.language)
76
-
77
- FileUtils.mkdir_p(File.join(containing, IMAGES_FOLDER_NAME))
78
- Supply::SCREENSHOT_TYPES.each do |screenshot_type|
79
- FileUtils.mkdir_p(File.join(containing, IMAGES_FOLDER_NAME, screenshot_type))
80
- end
81
-
82
- UI.message("📵 Due to a limitation of the Google Play API, there is no way for `supply` to download your existing screenshots. Please copy your screenshots into `metadata/android/#{listing.language}/images/`")
83
- end
84
-
85
- def store_apk_listing(apk_listing)
86
- UI.message("🔨 Downloading changelogs (#{apk_listing.language}, #{apk_listing.apk_version_code})")
93
+ def store_release_listing(release_listing)
94
+ UI.message("🔨 Downloading changelogs (#{release_listing.language}, #{release_listing.version})")
87
95
 
88
- containing = File.join(metadata_path, apk_listing.language, CHANGELOGS_FOLDER_NAME)
96
+ containing = File.join(metadata_path, release_listing.language, CHANGELOGS_FOLDER_NAME)
89
97
  unless File.exist?(containing)
90
98
  FileUtils.mkdir_p(containing)
91
99
  end
92
100
 
93
- path = File.join(containing, "#{apk_listing.apk_version_code}.txt")
101
+ path = File.join(containing, "#{release_listing.version}.txt")
94
102
  UI.message("Writing to #{path}...")
95
- File.write(path, apk_listing.recent_changes)
103
+ File.write(path, release_listing.release_notes)
96
104
  end
97
105
 
98
106
  private
@@ -1,4 +1,5 @@
1
1
  module Supply
2
+ # rubocop:disable Metrics/ClassLength
2
3
  class Uploader
3
4
  def perform_upload
4
5
  FastlaneCore::PrintTable.print_values(config: Supply.config, hide_keys: [:issuer], mask_keys: [:json_key_data], title: "Summary for supply #{Fastlane::VERSION}")
@@ -7,22 +8,6 @@ module Supply
7
8
 
8
9
  verify_config!
9
10
 
10
- if metadata_path
11
- UI.user_error!("Could not find folder #{metadata_path}") unless File.directory?(metadata_path)
12
-
13
- all_languages.each do |language|
14
- next if language.start_with?('.') # e.g. . or .. or hidden folders
15
- UI.message("Preparing to upload for language '#{language}'...")
16
-
17
- listing = client.listing_for_language(language)
18
-
19
- upload_metadata(language, listing) unless Supply.config[:skip_upload_metadata]
20
- upload_images(language) unless Supply.config[:skip_upload_images]
21
- upload_screenshots(language) unless Supply.config[:skip_upload_screenshots]
22
- upload_changelogs(language) unless Supply.config[:skip_upload_metadata]
23
- end
24
- end
25
-
26
11
  apk_version_codes = []
27
12
  apk_version_codes.concat(upload_apks) unless Supply.config[:skip_upload_apk]
28
13
  apk_version_codes.concat(upload_bundles) unless Supply.config[:skip_upload_aab]
@@ -34,19 +19,102 @@ module Supply
34
19
  # Updating a track with empty version codes can completely clear out a track
35
20
  update_track(apk_version_codes) unless apk_version_codes.empty?
36
21
 
22
+ if !Supply.config[:rollout].nil? && Supply.config[:track].to_s != ""
23
+ update_rollout
24
+ end
25
+
37
26
  promote_track if Supply.config[:track_promote_to]
38
27
 
39
28
  if Supply.config[:validate_only]
40
- UI.message("Validating all changes with Google Play...")
29
+ UI.message("Validating all track and release changes with Google Play...")
30
+ client.validate_current_edit!
31
+ UI.success("Successfully validated the upload to Google Play")
32
+ else
33
+ UI.message("Uploading all track and release changes to Google Play...")
34
+ client.commit_current_edit!
35
+ UI.success("Successfully finished the upload to Google Play")
36
+ end
37
+
38
+ perform_upload_meta(apk_version_codes)
39
+ end
40
+
41
+ def perform_upload_meta(version_codes)
42
+ client.begin_edit(package_name: Supply.config[:package_name])
43
+
44
+ if (!Supply.config[:skip_upload_metadata] || !Supply.config[:skip_upload_images] || !Supply.config[:skip_upload_changelogs] || !Supply.config[:skip_upload_screenshots]) && metadata_path
45
+ version_codes = [Supply.config[:version_code]] if version_codes.empty?
46
+ version_codes.each do |version_code|
47
+ UI.user_error!("Could not find folder #{metadata_path}") unless File.directory?(metadata_path)
48
+
49
+ track, release = fetch_track_and_release!(Supply.config[:track], version_code)
50
+ UI.user_error!("Unable to find the requested track - '#{Supply.config[:track]}'") unless track
51
+ UI.user_error!("Could not find release for version code '#{version_code}' to update changelog") unless release
52
+
53
+ release_notes = []
54
+ all_languages.each do |language|
55
+ next if language.start_with?('.') # e.g. . or .. or hidden folders
56
+ UI.message("Preparing to upload for language '#{language}'...")
57
+
58
+ listing = client.listing_for_language(language)
59
+
60
+ upload_metadata(language, listing) unless Supply.config[:skip_upload_metadata]
61
+ upload_images(language) unless Supply.config[:skip_upload_images]
62
+ upload_screenshots(language) unless Supply.config[:skip_upload_screenshots]
63
+ release_notes << upload_changelog(language, release.name) unless Supply.config[:skip_upload_changelogs]
64
+ end
65
+
66
+ upload_changelogs(release_notes, release, track) unless release_notes.empty?
67
+ end
68
+ end
69
+
70
+ if Supply.config[:validate_only]
71
+ UI.message("Validating all meta changes with Google Play...")
41
72
  client.validate_current_edit!
42
73
  UI.success("Successfully validated the upload to Google Play")
43
74
  else
44
- UI.message("Uploading all changes to Google Play...")
75
+ UI.message("Uploading all meta changes to Google Play...")
45
76
  client.commit_current_edit!
46
77
  UI.success("Successfully finished the upload to Google Play")
47
78
  end
48
79
  end
49
80
 
81
+ def fetch_track_and_release!(track, version_code, status = nil)
82
+ tracks = client.tracks(track)
83
+ return nil, nil if tracks.empty?
84
+
85
+ track = tracks.first
86
+ releases = track.releases
87
+ releases = releases.select { |r| r.status == status } if status
88
+ releases = releases.select { |r| r.version_codes.map(&:to_s).include?(version_code.to_s) }
89
+
90
+ if releases.size > 1
91
+ UI.user_error!("More than one release found in this track. Please specify with the :version_code option to select a release.")
92
+ end
93
+
94
+ return track, releases.first
95
+ end
96
+
97
+ def update_rollout
98
+ track, release = fetch_track_and_release!(Supply.config[:track], Supply.config[:version_code], Supply::ReleaseStatus::IN_PROGRESS)
99
+ version_code = release.version_codes.first
100
+
101
+ UI.message("Updating #{version_code}'s rollout to '#{Supply.config[:rollout]}' on track '#{Supply.config[:track]}'...")
102
+ UI.user_error!("Unable to find the requested track - '#{Supply.config[:track]}'") unless track
103
+
104
+ if track && release
105
+ completed = Supply.config[:rollout].to_f == 1
106
+ release.user_fraction = completed ? nil : Supply.config[:rollout]
107
+ release.status = Supply::ReleaseStatus::COMPLETED if completed
108
+
109
+ # Deleted other version codes if completed because only allowed on completed version in a release
110
+ track.releases.delete_if { |r| !(r.version_codes || []).map(&:to_s).include?(version_code) } if completed
111
+ else
112
+ UI.user_error!("Unable to find version to rollout in track '#{Supply.config[:track]}'")
113
+ end
114
+
115
+ client.update_track(Supply.config[:track], track)
116
+ end
117
+
50
118
  def verify_config!
51
119
  unless metadata_path || Supply.config[:apk] || Supply.config[:apk_paths] || Supply.config[:aab] || Supply.config[:aab_paths] || (Supply.config[:track] && Supply.config[:track_promote_to])
52
120
  UI.user_error!("No local metadata, apks, aab, or track to promote were found, make sure to run `fastlane supply init` to setup supply")
@@ -60,32 +128,73 @@ module Supply
60
128
  if could_upload_apk && could_upload_aab
61
129
  UI.user_error!("Cannot provide both apk(s) and aab - use `skip_upload_apk`, `skip_upload_aab`, or make sure to remove any existing .apk or .aab files that are no longer needed")
62
130
  end
131
+
132
+ if Supply.config[:release_status] == Supply::ReleaseStatus::DRAFT && Supply.config[:rollout]
133
+ UI.user_error!(%(Cannot specify rollout percentage when the release status is set to 'draft'))
134
+ end
135
+
136
+ unless Supply.config[:version_codes_to_retain].nil?
137
+ Supply.config[:version_codes_to_retain] = Supply.config[:version_codes_to_retain].map(&:to_i)
138
+ end
63
139
  end
64
140
 
65
141
  def promote_track
66
- version_codes = client.track_version_codes(Supply.config[:track])
67
- # the actual value passed for the rollout argument does not matter because it will be ignored by the Google Play API
68
- # but it has to be between 0.0 and 1.0 to pass the validity check. So we are passing the default value 0.1
69
- client.update_track(Supply.config[:track], 0.1, nil) if Supply.config[:deactivate_on_promote]
70
- client.update_track(Supply.config[:track_promote_to], Supply.config[:rollout] || 0.1, version_codes)
71
- end
142
+ track_from = client.tracks(Supply.config[:track]).first
143
+ unless track_from
144
+ UI.user_error!("Cannot promote from track '#{Supply.config[:track]}' - track doesn't exist")
145
+ end
146
+
147
+ releases = track_from.releases
148
+ if Supply.config[:version_code].to_s != ""
149
+ releases = releases.select do |release|
150
+ release.version_codes.include?(Supply.config[:version_code].to_s)
151
+ end
152
+ end
72
153
 
73
- def upload_changelogs(language)
74
- client.apks_version_codes.each do |apk_version_code|
75
- upload_changelog(language, apk_version_code)
154
+ if releases.size == 0
155
+ UI.user_error!("Track '#{Supply.config[:track]}' doesn't have any releases")
156
+ elsif releases.size > 1
157
+ UI.user_error!("Track '#{Supply.config[:track]}' has more than one release - use :version_code to filter the release to promote")
76
158
  end
77
- client.aab_version_codes.each do |aab_version_code|
78
- upload_changelog(language, aab_version_code)
159
+
160
+ release = track_from.releases.first
161
+ track_to = client.tracks(Supply.config[:track_promote_to]).first
162
+
163
+ if track_to
164
+ # Its okay to set releases to an array containing the newest release
165
+ # Google Play will keep previous releases there this release is a partial rollout
166
+ track_to.releases = [release]
167
+ else
168
+ track_to = AndroidPublisher::Track.new(
169
+ track: Supply.config[:track_promote_to],
170
+ releases: [release]
171
+ )
79
172
  end
173
+
174
+ client.update_track(Supply.config[:track_promote_to], track_to)
80
175
  end
81
176
 
82
- def upload_changelog(language, version_code)
83
- path = File.join(metadata_path, language, Supply::CHANGELOGS_FOLDER_NAME, "#{version_code}.txt")
177
+ def upload_changelog(language, version_name)
178
+ UI.user_error!("Cannot find changelog because no version name given - please specify :version_name") unless version_name
179
+
180
+ path = File.join(Supply.config[:metadata_path], language, Supply::CHANGELOGS_FOLDER_NAME, "#{version_name}.txt")
181
+ changelog_text = ''
84
182
  if File.exist?(path)
85
- UI.message("Updating changelog for code version '#{version_code}' and language '#{language}'...")
86
- apk_listing = ApkListing.new(File.read(path, encoding: 'UTF-8'), language, version_code)
87
- client.update_apk_listing_for_language(apk_listing)
183
+ UI.message("Updating changelog for '#{version_name}' and language '#{language}'...")
184
+ changelog_text = File.read(path, encoding: 'UTF-8')
185
+ else
186
+ UI.message("Could not find changelog for '#{version_name}' and language '#{language}' at path #{path}...")
88
187
  end
188
+
189
+ AndroidPublisher::LocalizedText.new({
190
+ language: language,
191
+ text: changelog_text
192
+ })
193
+ end
194
+
195
+ def upload_changelogs(release_notes, release, track)
196
+ release.release_notes = release_notes
197
+ client.upload_changelogs(track, Supply.config[:track])
89
198
  end
90
199
 
91
200
  def upload_metadata(language, listing)
@@ -163,14 +272,6 @@ module Supply
163
272
  aab_paths.each do |aab_path|
164
273
  UI.message("Preparing aab at path '#{aab_path}' for upload...")
165
274
  bundle_version_code = client.upload_bundle(aab_path)
166
-
167
- if metadata_path
168
- all_languages.each do |language|
169
- next if language.start_with?('.') # e.g. . or .. or hidden folders
170
- upload_changelog(language, bundle_version_code)
171
- end
172
- end
173
-
174
275
  aab_version_codes.push(bundle_version_code)
175
276
  end
176
277
 
@@ -188,6 +289,7 @@ module Supply
188
289
  # @return [Integer] The apk version code returned after uploading, or nil if there was a problem
189
290
  def upload_binary_data(apk_path)
190
291
  apk_version_code = nil
292
+
191
293
  if apk_path
192
294
  UI.message("Preparing apk at path '#{apk_path}' for upload...")
193
295
  apk_version_code = client.upload_apk(apk_path)
@@ -208,16 +310,11 @@ module Supply
208
310
  end
209
311
 
210
312
  upload_obbs(apk_path, apk_version_code)
211
-
212
- if metadata_path
213
- all_languages.each do |language|
214
- next if language.start_with?('.') # e.g. . or .. or hidden folders
215
- upload_changelog(language, apk_version_code)
216
- end
217
- end
218
313
  else
219
314
  UI.message("No apk file found, you can pass the path to your apk using the `apk` option")
220
315
  end
316
+
317
+ UI.message("\tVersion Code: #{apk_version_code}")
221
318
  apk_version_code
222
319
  end
223
320
 
@@ -230,55 +327,35 @@ module Supply
230
327
  end
231
328
 
232
329
  def update_track(apk_version_codes)
233
- UI.message("Updating track '#{Supply.config[:track]}'...")
234
- check_superseded_tracks(apk_version_codes) if Supply.config[:check_superseded_tracks]
235
-
236
- if Supply.config[:track].eql?("rollout")
237
- client.update_track(Supply.config[:track], Supply.config[:rollout] || 0.1, apk_version_codes)
238
- else
239
- client.update_track(Supply.config[:track], 1.0, apk_version_codes)
240
- end
241
- end
330
+ return if apk_version_codes.empty?
242
331
 
243
- # Remove any version codes that is:
244
- # - Lesser than the greatest of any later (i.e. production) track
245
- # - Or lesser than the currently being uploaded if it's in an earlier (i.e. alpha) track
246
- def check_superseded_tracks(apk_version_codes)
247
- UI.message("Checking superseded tracks, uploading '#{apk_version_codes}' to '#{Supply.config[:track]}'...")
248
- max_apk_version_code = apk_version_codes.max
249
- max_tracks_version_code = nil
250
-
251
- tracks = ["production", "rollout", "beta", "alpha", "internal"]
252
- config_track_index = tracks.index(Supply.config[:track])
253
-
254
- # Custom "closed" tracks are now allowed (https://support.google.com/googleplay/android-developer/answer/3131213)
255
- # Custom tracks have an equal level with alpha (alpha is considered a closed track as well)
256
- # If a track index is not found, we will assume is a custom track so an alpha index is given
257
- config_track_index = tracks.index("alpha") unless config_track_index
258
-
259
- tracks.each_index do |track_index|
260
- track = tracks[track_index]
261
- track_version_codes = client.track_version_codes(track).sort
262
- UI.verbose("Found '#{track_version_codes}' on track '#{track}'")
263
-
264
- next if track_index.eql?(config_track_index)
265
- next if track_version_codes.empty?
266
-
267
- if max_tracks_version_code.nil?
268
- max_tracks_version_code = track_version_codes.max
269
- end
332
+ UI.message("Updating track '#{Supply.config[:track]}'...")
270
333
 
271
- removed_version_codes = track_version_codes.take_while do |v|
272
- v < max_tracks_version_code || (v < max_apk_version_code && track_index > config_track_index)
273
- end
334
+ track_release = AndroidPublisher::TrackRelease.new(
335
+ name: Supply.config[:version_name],
336
+ status: Supply.config[:release_status],
337
+ version_codes: apk_version_codes
338
+ )
274
339
 
275
- next if removed_version_codes.empty?
340
+ if Supply.config[:rollout]
341
+ track_release.status = Supply::ReleaseStatus::IN_PROGRESS
342
+ track_release.user_fraction = Supply.config[:rollout].to_f
343
+ end
276
344
 
277
- keep_version_codes = track_version_codes - removed_version_codes
278
- max_tracks_version_code = keep_version_codes[0] unless keep_version_codes.empty?
279
- client.update_track(track, 1.0, keep_version_codes)
280
- UI.message("Superseded track '#{track}', removed '#{removed_version_codes}'")
345
+ tracks = client.tracks(Supply.config[:track])
346
+ track = tracks.first
347
+ if track
348
+ # Its okay to set releases to an array containing the newest release
349
+ # Google Play will keep previous releases there this release is a partial rollout
350
+ track.releases = [track_release]
351
+ else
352
+ track = AndroidPublisher::Track.new(
353
+ track: Supply.config[:track],
354
+ releases: [track_release]
355
+ )
281
356
  end
357
+
358
+ client.update_track(Supply.config[:track], track)
282
359
  end
283
360
 
284
361
  # returns only language directories from metadata_path
@@ -346,4 +423,5 @@ module Supply
346
423
  end
347
424
  end
348
425
  end
426
+ # rubocop:enable Metrics/ClassLength
349
427
  end