fastlane 2.134.0 → 2.135.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (47) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +72 -72
  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/docs/capture_ios_screenshots.md +1 -1
  6. data/fastlane/lib/fastlane/actions/docs/sync_code_signing.md +4 -2
  7. data/fastlane/lib/fastlane/actions/docs/upload_to_play_store.md +26 -2
  8. data/fastlane/lib/fastlane/actions/download_dsyms.rb +1 -1
  9. data/fastlane/lib/fastlane/actions/download_from_play_store.rb +1 -1
  10. data/fastlane/lib/fastlane/environment_printer.rb +2 -2
  11. data/fastlane/lib/fastlane/lane_manager.rb +1 -1
  12. data/fastlane/lib/fastlane/plugins/plugin_manager.rb +12 -2
  13. data/fastlane/lib/fastlane/plugins/template/.rubocop.yml +1 -0
  14. data/fastlane/lib/fastlane/runner.rb +2 -2
  15. data/fastlane/lib/fastlane/version.rb +1 -1
  16. data/fastlane/swift/Deliverfile.swift +1 -1
  17. data/fastlane/swift/Fastlane.swift +50 -20
  18. data/fastlane/swift/Gymfile.swift +1 -1
  19. data/fastlane/swift/Matchfile.swift +1 -1
  20. data/fastlane/swift/MatchfileProtocol.swift +2 -2
  21. data/fastlane/swift/Precheckfile.swift +1 -1
  22. data/fastlane/swift/Scanfile.swift +1 -1
  23. data/fastlane/swift/Screengrabfile.swift +1 -1
  24. data/fastlane/swift/Snapshotfile.swift +1 -1
  25. data/fastlane_core/lib/fastlane_core/configuration/commander_generator.rb +3 -3
  26. data/fastlane_core/lib/fastlane_core/configuration/configuration.rb +1 -1
  27. data/fastlane_core/lib/fastlane_core/swag.rb +1 -1
  28. data/fastlane_core/lib/fastlane_core/ui/fastlane_runner.rb +1 -1
  29. data/{pilot/lib/pilot/.manager.rb.swp → gym/lib/gym/.module.rb.swp} +0 -0
  30. data/sigh/lib/assets/resign.sh +2 -2
  31. data/snapshot/lib/snapshot/simulator_launchers/simulator_launcher.rb +1 -1
  32. data/supply/lib/supply.rb +23 -0
  33. data/{fastlane/lib/fastlane/actions/.update_project_provisioning.rb.swp → supply/lib/supply/.client.rb.swp} +0 -0
  34. data/supply/lib/supply/.options.rb.swp +0 -0
  35. data/supply/lib/supply/.uploader.rb.swp +0 -0
  36. data/supply/lib/supply/client.rb +101 -55
  37. data/supply/lib/supply/options.rb +49 -14
  38. data/supply/lib/supply/release_listing.rb +18 -0
  39. data/supply/lib/supply/setup.rb +42 -34
  40. data/supply/lib/supply/uploader.rb +168 -93
  41. metadata +21 -24
  42. data/fastlane/lib/fastlane/actions/.download_dsyms.rb.swp +0 -0
  43. data/fastlane/lib/fastlane/actions/.hockey.rb.swp +0 -0
  44. data/fastlane/lib/fastlane/actions/.slack.rb.swp +0 -0
  45. data/fastlane/swift/FastlaneSwiftRunner/FastlaneSwiftRunner.xcodeproj/project.xcworkspace/xcuserdata/josh.xcuserdatad/UserInterfaceState.xcuserstate +0 -0
  46. data/spaceship/lib/spaceship/connect_api/.DS_Store +0 -0
  47. 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,36 @@ 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
+ description: "Version code (used when updating rollout or promoting specific versions)",
28
+ default_value: CredentialsManager::AppfileConfig.try_fetch_value(:version_code),
29
+ default_value_dynamic: true),
30
+ FastlaneCore::ConfigItem.new(key: :release_status,
31
+ env_name: "SUPPLY_RELEASE_STATUS",
32
+ short_option: "-e",
33
+ optional: true,
34
+ description: "Release status (used when uploading new apks/aabs) - valid values are #{Supply::ReleaseStatus::ALL.join(', ')}",
35
+ default_value: Supply::ReleaseStatus::COMPLETED,
36
+ default_value_dynamic: true,
37
+ verify_block: proc do |value|
38
+ UI.user_error!("Value must be one of '#{Supply::RELEASE_STATUS}'") unless Supply::ReleaseStatus::ALL.include?(value)
39
+ end),
17
40
  FastlaneCore::ConfigItem.new(key: :track,
18
41
  short_option: "-a",
19
42
  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'),
43
+ description: "The track of the application to use. The default available tracks are: #{Supply::Tracks::DEFAULTS.join(', ')}",
44
+ default_value: Supply::Tracks::DEFAULT,
45
+ type: String),
22
46
  FastlaneCore::ConfigItem.new(key: :rollout,
23
47
  short_option: "-r",
24
48
  description: "The percentage of the user fraction when uploading to the rollout track",
@@ -104,6 +128,7 @@ module Supply
104
128
  FastlaneCore::ConfigItem.new(key: :apk_paths,
105
129
  env_name: "SUPPLY_APK_PATHS",
106
130
  conflicting_options: [:apk, :aab, :aab_paths],
131
+ code_gen_sensitive: true,
107
132
  optional: true,
108
133
  type: Array,
109
134
  description: "An array of paths to APK files to upload",
@@ -131,6 +156,7 @@ module Supply
131
156
  FastlaneCore::ConfigItem.new(key: :aab_paths,
132
157
  env_name: "SUPPLY_AAB_PATHS",
133
158
  conflicting_options: [:apk, :apk_paths, :aab],
159
+ code_gen_sensitive: true,
134
160
  optional: true,
135
161
  type: Array,
136
162
  description: "An array of paths to AAB files to upload",
@@ -146,41 +172,47 @@ module Supply
146
172
  env_name: "SUPPLY_SKIP_UPLOAD_APK",
147
173
  optional: true,
148
174
  description: "Whether to skip uploading APK",
149
- is_string: false,
175
+ type: Boolean,
150
176
  default_value: false),
151
177
  FastlaneCore::ConfigItem.new(key: :skip_upload_aab,
152
178
  env_name: "SUPPLY_SKIP_UPLOAD_AAB",
153
179
  optional: true,
154
180
  description: "Whether to skip uploading AAB",
155
- is_string: false,
181
+ type: Boolean,
156
182
  default_value: false),
157
183
  FastlaneCore::ConfigItem.new(key: :skip_upload_metadata,
158
184
  env_name: "SUPPLY_SKIP_UPLOAD_METADATA",
159
185
  optional: true,
160
- description: "Whether to skip uploading metadata",
161
- is_string: false,
186
+ description: "Whether to skip uploading metadata, changelogs not included",
187
+ type: Boolean,
188
+ default_value: false),
189
+ FastlaneCore::ConfigItem.new(key: :skip_upload_changelogs,
190
+ env_name: "SUPPLY_SKIP_UPLOAD_CHANGELOGS",
191
+ optional: true,
192
+ description: "Whether to skip uploading changelogs",
193
+ type: Boolean,
162
194
  default_value: false),
163
195
  FastlaneCore::ConfigItem.new(key: :skip_upload_images,
164
196
  env_name: "SUPPLY_SKIP_UPLOAD_IMAGES",
165
197
  optional: true,
166
198
  description: "Whether to skip uploading images, screenshots not included",
167
- is_string: false,
199
+ type: Boolean,
168
200
  default_value: false),
169
201
  FastlaneCore::ConfigItem.new(key: :skip_upload_screenshots,
170
202
  env_name: "SUPPLY_SKIP_UPLOAD_SCREENSHOTS",
171
203
  optional: true,
172
204
  description: "Whether to skip uploading SCREENSHOTS",
173
- is_string: false,
205
+ type: Boolean,
174
206
  default_value: false),
175
207
  FastlaneCore::ConfigItem.new(key: :track_promote_to,
176
208
  env_name: "SUPPLY_TRACK_PROMOTE_TO",
177
209
  optional: true,
178
- description: "The track to promote to. The default available tracks are: #{default_tracks.join(', ')}"),
210
+ description: "The track to promote to. The default available tracks are: #{Supply::Tracks::DEFAULTS.join(', ')}"),
179
211
  FastlaneCore::ConfigItem.new(key: :validate_only,
180
212
  env_name: "SUPPLY_VALIDATE_ONLY",
181
213
  optional: true,
182
214
  description: "Only validate changes with Google Play rather than actually publish",
183
- is_string: false,
215
+ type: Boolean,
184
216
  default_value: false),
185
217
  FastlaneCore::ConfigItem.new(key: :mapping,
186
218
  env_name: "SUPPLY_MAPPING",
@@ -215,7 +247,8 @@ module Supply
215
247
  env_name: "SUPPLY_CHECK_SUPERSEDED_TRACKS",
216
248
  optional: true,
217
249
  description: "Check the other tracks for superseded versions and disable them",
218
- is_string: false,
250
+ deprecated: "Google Play does this automatically now",
251
+ type: Boolean,
219
252
  default_value: false),
220
253
  FastlaneCore::ConfigItem.new(key: :timeout,
221
254
  env_name: "SUPPLY_TIMEOUT",
@@ -227,16 +260,18 @@ module Supply
227
260
  env_name: "SUPPLY_DEACTIVATE_ON_PROMOTE",
228
261
  optional: true,
229
262
  description: "When promoting to a new track, deactivate the binary in the origin track",
230
- is_string: false,
263
+ deprecated: "Google Play does this automatically now",
264
+ type: Boolean,
231
265
  default_value: true),
232
266
  FastlaneCore::ConfigItem.new(key: :version_codes_to_retain,
233
267
  optional: true,
234
268
  type: Array,
235
269
  description: "An array of version codes to retain when publishing a new APK",
236
270
  verify_block: proc do |version_codes|
271
+ version_codes = version_codes.map(&:to_i)
237
272
  UI.user_error!("Could not evaluate array from '#{version_codes}'") unless version_codes.kind_of?(Array)
238
273
  version_codes.each do |version_code|
239
- UI.user_error!("Version code '#{version_code}' is not an integer") unless version_code.kind_of?(Integer)
274
+ UI.user_error!("Version code '#{version_code}' is not an integer") if version_code == 0
240
275
  end
241
276
  end),
242
277
  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
@@ -7,22 +7,6 @@ module Supply
7
7
 
8
8
  verify_config!
9
9
 
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
10
  apk_version_codes = []
27
11
  apk_version_codes.concat(upload_apks) unless Supply.config[:skip_upload_apk]
28
12
  apk_version_codes.concat(upload_bundles) unless Supply.config[:skip_upload_aab]
@@ -34,19 +18,103 @@ module Supply
34
18
  # Updating a track with empty version codes can completely clear out a track
35
19
  update_track(apk_version_codes) unless apk_version_codes.empty?
36
20
 
21
+ if !Supply.config[:rollout].nil? && Supply.config[:track].to_s != ""
22
+ update_rollout
23
+ end
24
+
37
25
  promote_track if Supply.config[:track_promote_to]
38
26
 
39
27
  if Supply.config[:validate_only]
40
- UI.message("Validating all changes with Google Play...")
28
+ UI.message("Validating all track and release changes with Google Play...")
29
+ client.validate_current_edit!
30
+ UI.success("Successfully validated the upload to Google Play")
31
+ else
32
+ UI.message("Uploading all track and release changes to Google Play...")
33
+ client.commit_current_edit!
34
+ UI.success("Successfully finished the upload to Google Play")
35
+ end
36
+
37
+ perform_upload_meta(apk_version_codes)
38
+ end
39
+
40
+ def perform_upload_meta(version_codes)
41
+ client.begin_edit(package_name: Supply.config[:package_name])
42
+
43
+ if (!Supply.config[:skip_upload_metadata] || !Supply.config[:skip_upload_images] || !Supply.config[:skip_upload_changelogs] || !Supply.config[:skip_upload_screenshots]) && metadata_path
44
+ version_codes = [Supply.config[:version_code]] if version_codes.empty?
45
+ version_codes.each do |version_code|
46
+ UI.user_error!("Could not find folder #{metadata_path}") unless File.directory?(metadata_path)
47
+
48
+ track, release = fetch_track_and_release!(Supply.config[:track], version_code)
49
+ UI.user_error!("Unable to find the requested track - '#{Supply.config[:track]}'") unless track
50
+ UI.user_error!("Coult not find release for version code '#{version_code}' to update changelog") unless release
51
+
52
+ release_notes = []
53
+ all_languages.each do |language|
54
+ next if language.start_with?('.') # e.g. . or .. or hidden folders
55
+ UI.message("Preparing to upload for language '#{language}'...")
56
+
57
+ listing = client.listing_for_language(language)
58
+
59
+ upload_metadata(language, listing) unless Supply.config[:skip_upload_metadata]
60
+ upload_images(language) unless Supply.config[:skip_upload_images]
61
+ upload_screenshots(language) unless Supply.config[:skip_upload_screenshots]
62
+ release_notes << upload_changelog(language, release.name) unless Supply.config[:skip_upload_changelogs]
63
+ end
64
+
65
+ upload_changelogs(release_notes, release, track) unless release_notes.empty?
66
+ end
67
+ end
68
+
69
+ if Supply.config[:validate_only]
70
+ UI.message("Validating all meta changes with Google Play...")
41
71
  client.validate_current_edit!
42
72
  UI.success("Successfully validated the upload to Google Play")
43
73
  else
44
- UI.message("Uploading all changes to Google Play...")
74
+ UI.message("Uploading all meta changes to Google Play...")
45
75
  client.commit_current_edit!
46
76
  UI.success("Successfully finished the upload to Google Play")
47
77
  end
48
78
  end
49
79
 
80
+ def fetch_track_and_release!(track, version_code, status = nil)
81
+ tracks = client.tracks(track)
82
+ return nil, nil if tracks.empty?
83
+
84
+ track = tracks.first
85
+ releases = track.releases
86
+ releases = releases.select { |r| r.status == status } if status
87
+
88
+ if releases.size > 1
89
+ UI.user_error!("More than one release found in this track. Please specify with the :version_code option to select a release.")
90
+ end
91
+
92
+ release = releases.first { |r| r.version_codes.include?(version_code) }
93
+
94
+ return track, release
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 || []).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,71 @@ 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] == '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
72
146
 
73
- def upload_changelogs(language)
74
- client.apks_version_codes.each do |apk_version_code|
75
- upload_changelog(language, apk_version_code)
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])
151
+ end
152
+ end
153
+
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')
88
185
  end
186
+
187
+ AndroidPublisher::LocalizedText.new({
188
+ language: language,
189
+ text: changelog_text
190
+ })
191
+ end
192
+
193
+ def upload_changelogs(release_notes, release, track)
194
+ release.release_notes = release_notes
195
+ client.upload_changelogs(track, Supply.config[:track])
89
196
  end
90
197
 
91
198
  def upload_metadata(language, listing)
@@ -163,14 +270,6 @@ module Supply
163
270
  aab_paths.each do |aab_path|
164
271
  UI.message("Preparing aab at path '#{aab_path}' for upload...")
165
272
  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
273
  aab_version_codes.push(bundle_version_code)
175
274
  end
176
275
 
@@ -188,6 +287,7 @@ module Supply
188
287
  # @return [Integer] The apk version code returned after uploading, or nil if there was a problem
189
288
  def upload_binary_data(apk_path)
190
289
  apk_version_code = nil
290
+
191
291
  if apk_path
192
292
  UI.message("Preparing apk at path '#{apk_path}' for upload...")
193
293
  apk_version_code = client.upload_apk(apk_path)
@@ -208,16 +308,11 @@ module Supply
208
308
  end
209
309
 
210
310
  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
311
  else
219
312
  UI.message("No apk file found, you can pass the path to your apk using the `apk` option")
220
313
  end
314
+
315
+ UI.message("\tVersion Code: #{apk_version_code}")
221
316
  apk_version_code
222
317
  end
223
318
 
@@ -230,55 +325,35 @@ module Supply
230
325
  end
231
326
 
232
327
  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
328
+ return if apk_version_codes.empty?
242
329
 
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
330
+ UI.message("Updating track '#{Supply.config[:track]}'...")
270
331
 
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
332
+ track_release = AndroidPublisher::TrackRelease.new(
333
+ name: Supply.config[:version_name],
334
+ status: Supply.config[:release_status],
335
+ version_codes: apk_version_codes
336
+ )
274
337
 
275
- next if removed_version_codes.empty?
338
+ if Supply.config[:rollout]
339
+ track_release.status = Supply::ReleaseStatus::IN_PROGRESS
340
+ track_release.user_fraction = Supply.config[:rollout].to_f
341
+ end
276
342
 
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}'")
343
+ tracks = client.tracks(Supply.config[:track])
344
+ track = tracks.first
345
+ if track
346
+ # Its okay to set releases to an array containing the newest release
347
+ # Google Play will keep previous releases there this release is a partial rollout
348
+ track.releases = [track_release]
349
+ else
350
+ track = AndroidPublisher::Track.new(
351
+ track: Supply.config[:track],
352
+ releases: [track_release]
353
+ )
281
354
  end
355
+
356
+ client.update_track(Supply.config[:track], track)
282
357
  end
283
358
 
284
359
  # returns only language directories from metadata_path