Class: Supply::Uploader

Inherits:
Object
  • Object
show all
Defined in:
supply/lib/supply/uploader.rb

Overview

rubocop:disable Metrics/ClassLength

Instance Method Summary collapse

Instance Method Details

#fetch_track_and_release!(track, version_code, status = nil) ⇒ Object



106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
# File 'supply/lib/supply/uploader.rb', line 106

def fetch_track_and_release!(track, version_code, status = nil)
  tracks = client.tracks(track)
  return nil, nil if tracks.empty?

  track = tracks.first
  releases = track.releases

  releases = releases.select { |r| r.status == status } if status
  releases = releases.select { |r| (r.version_codes || []).map(&:to_s).include?(version_code.to_s) } if version_code

  if releases.size > 1
    UI.user_error!("More than one release found in this track. Please specify with the :version_code option to select a release.")
  end

  return track, releases.first
end

#perform_uploadObject



4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
# File 'supply/lib/supply/uploader.rb', line 4

def perform_upload
  FastlaneCore::PrintTable.print_values(config: Supply.config, hide_keys: [:issuer], mask_keys: [:json_key_data], title: "Summary for supply #{Fastlane::VERSION}")

  client.begin_edit(package_name: Supply.config[:package_name])

  verify_config!

  apk_version_codes = []
  apk_version_codes.concat(upload_apks) unless Supply.config[:skip_upload_apk]
  apk_version_codes.concat(upload_bundles) unless Supply.config[:skip_upload_aab]
  upload_mapping(apk_version_codes)

  apk_version_codes.concat(Supply.config[:version_codes_to_retain]) if Supply.config[:version_codes_to_retain]

  if !apk_version_codes.empty?
    # Only update tracks if we have version codes
    # update_track handle setting rollout if needed
    # Updating a track with empty version codes can completely clear out a track
    update_track(apk_version_codes)
  else
    # Only promote or rollout if we don't have version codes
    if Supply.config[:track_promote_to]
      promote_track
    elsif !Supply.config[:rollout].nil? && Supply.config[:track].to_s != ""
      update_rollout
    end
  end

  perform_upload_meta(apk_version_codes)

  if Supply.config[:validate_only]
    UI.message("Validating all changes with Google Play...")
    client.validate_current_edit!
    UI.success("Successfully validated the upload to Google Play")
  else
    UI.message("Uploading all changes to Google Play...")
    client.commit_current_edit!
    UI.success("Successfully finished the upload to Google Play")
  end
end

#perform_upload_meta(version_codes) ⇒ Object



73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
# File 'supply/lib/supply/uploader.rb', line 73

def perform_upload_meta(version_codes)
  if (!Supply.config[:skip_upload_metadata] || !Supply.config[:skip_upload_images] || !Supply.config[:skip_upload_changelogs] || !Supply.config[:skip_upload_screenshots]) && 
    # Use version code from config if version codes is empty and no nil or empty string
    version_codes = [Supply.config[:version_code]] if version_codes.empty?
    version_codes = version_codes.reject do |version_code|
      version_codes.to_s == ""
    end

    version_codes.each do |version_code|
      UI.user_error!("Could not find folder #{}") unless File.directory?()

      track, release = fetch_track_and_release!(Supply.config[:track], version_code)
      UI.user_error!("Unable to find the requested track - '#{Supply.config[:track]}'") unless track
      UI.user_error!("Could not find release for version code '#{version_code}' to update changelog") unless release

      release_notes = []
      all_languages.each do |language|
        next if language.start_with?('.') # e.g. . or .. or hidden folders
        UI.message("Preparing to upload for language '#{language}'...")

        listing = client.listing_for_language(language)

        (language, listing) unless Supply.config[:skip_upload_metadata]
        upload_images(language) unless Supply.config[:skip_upload_images]
        upload_screenshots(language) unless Supply.config[:skip_upload_screenshots]
        release_notes << upload_changelog(language, version_code) unless Supply.config[:skip_upload_changelogs]
      end

      upload_changelogs(release_notes, release, track) unless release_notes.empty?
    end
  end
end

#perform_upload_to_internal_app_sharingObject



45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
# File 'supply/lib/supply/uploader.rb', line 45

def perform_upload_to_internal_app_sharing
  download_urls = []

  package_name = Supply.config[:package_name]

  apk_paths = [Supply.config[:apk]] unless (apk_paths = Supply.config[:apk_paths])
  apk_paths.compact!
  apk_paths.each do |apk_path|
    download_url = client.upload_apk_to_internal_app_sharing(package_name, apk_path)
    download_urls << download_url
    UI.success("Successfully uploaded APK to Internal App Sharing URL: #{download_url}")
  end

  aab_paths = [Supply.config[:aab]] unless (aab_paths = Supply.config[:aab_paths])
  aab_paths.compact!
  aab_paths.each do |aab_path|
    download_url = client.upload_bundle_to_internal_app_sharing(package_name, aab_path)
    download_urls << download_url
    UI.success("Successfully uploaded AAB to Internal App Sharing URL: #{download_url}")
  end

  if download_urls.count == 1
    return download_urls.first
  else
    return download_urls
  end
end

#promote_trackObject



169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
# File 'supply/lib/supply/uploader.rb', line 169

def promote_track
  track_from = client.tracks(Supply.config[:track]).first
  unless track_from
    UI.user_error!("Cannot promote from track '#{Supply.config[:track]}' - track doesn't exist")
  end

  releases = track_from.releases
  if Supply.config[:version_code].to_s != ""
    releases = releases.select do |release|
      release.version_codes.include?(Supply.config[:version_code].to_s)
    end
  else
    releases = releases.select do |release|
      release.status == Supply::ReleaseStatus::COMPLETED
    end
  end

  if releases.size == 0
    UI.user_error!("Track '#{Supply.config[:track]}' doesn't have any releases")
  elsif releases.size > 1
    UI.user_error!("Track '#{Supply.config[:track]}' has more than one release - use :version_code to filter the release to promote")
  end

  release = releases.first
  track_to = client.tracks(Supply.config[:track_promote_to]).first

  rollout = (Supply.config[:rollout] || 0).to_f
  if rollout > 0 && rollout < 1
    release.status = Supply::ReleaseStatus::IN_PROGRESS
    release.user_fraction = rollout
  else
    release.status = Supply::ReleaseStatus::COMPLETED
    release.user_fraction = nil
  end

  if track_to
    # Its okay to set releases to an array containing the newest release
    # Google Play will keep previous releases there this release is a partial rollout
    track_to.releases = [release]
  else
    track_to = AndroidPublisher::Track.new(
      track: Supply.config[:track_promote_to],
      releases: [release]
    )
  end

  client.update_track(Supply.config[:track_promote_to], track_to)
end

#update_rolloutObject



123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
# File 'supply/lib/supply/uploader.rb', line 123

def update_rollout
  track, release = fetch_track_and_release!(Supply.config[:track], Supply.config[:version_code], Supply::ReleaseStatus::IN_PROGRESS)
  UI.user_error!("Unable to find the requested track - '#{Supply.config[:track]}'") unless track
  UI.user_error!("Unable to find the requested release on track - '#{Supply.config[:track]}'") unless release

  version_code = release.version_codes.first

  UI.message("Updating #{version_code}'s rollout to '#{Supply.config[:rollout]}' on track '#{Supply.config[:track]}'...")

  if track && release
    completed = Supply.config[:rollout].to_f == 1
    release.user_fraction = completed ? nil : Supply.config[:rollout]
    release.status = Supply::ReleaseStatus::COMPLETED if completed

    # Deleted other version codes if completed because only allowed on completed version in a release
    track.releases.delete_if { |r| !(r.version_codes || []).map(&:to_s).include?(version_code) } if completed
  else
    UI.user_error!("Unable to find version to rollout in track '#{Supply.config[:track]}'")
  end

  client.update_track(Supply.config[:track], track)
end

#upload_apksObject



290
291
292
293
294
295
296
297
298
299
300
301
# File 'supply/lib/supply/uploader.rb', line 290

def upload_apks
  apk_paths = [Supply.config[:apk]] unless (apk_paths = Supply.config[:apk_paths])
  apk_paths.compact!

  apk_version_codes = []

  apk_paths.each do |apk_path|
    apk_version_codes.push(upload_binary_data(apk_path))
  end

  return apk_version_codes
end

#upload_bundlesObject



313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
# File 'supply/lib/supply/uploader.rb', line 313

def upload_bundles
  aab_paths = [Supply.config[:aab]] unless (aab_paths = Supply.config[:aab_paths])
  return [] unless aab_paths
  aab_paths.compact!

  aab_version_codes = []

  aab_paths.each do |aab_path|
    UI.message("Preparing aab at path '#{aab_path}' for upload...")
    bundle_version_code = client.upload_bundle(aab_path)
    aab_version_codes.push(bundle_version_code)
  end

  return aab_version_codes
end

#upload_changelog(language, version_code) ⇒ Object



218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
# File 'supply/lib/supply/uploader.rb', line 218

def upload_changelog(language, version_code)
  UI.user_error!("Cannot find changelog because no version code given - please specify :version_code") unless version_code

  path = File.join(Supply.config[:metadata_path], language, Supply::CHANGELOGS_FOLDER_NAME, "#{version_code}.txt")
  changelog_text = ''
  if File.exist?(path)
    UI.message("Updating changelog for '#{version_code}' and language '#{language}'...")
    changelog_text = File.read(path, encoding: 'UTF-8')
  else
    default_changelog_path = File.join(Supply.config[:metadata_path], language, Supply::CHANGELOGS_FOLDER_NAME, "default.txt")
    if File.exist?(default_changelog_path)
      UI.message("Updating changelog for '#{version_code}' and language '#{language}' to default changelog...")
      changelog_text = File.read(default_changelog_path, encoding: 'UTF-8')
    else
      UI.message("Could not find changelog for '#{version_code}' and language '#{language}' at path #{path}...")
    end
  end

  AndroidPublisher::LocalizedText.new(
    language: language,
    text: changelog_text
  )
end

#upload_changelogs(release_notes, release, track) ⇒ Object



242
243
244
245
# File 'supply/lib/supply/uploader.rb', line 242

def upload_changelogs(release_notes, release, track)
  release.release_notes = release_notes
  client.upload_changelogs(track, Supply.config[:track])
end

#upload_images(language) ⇒ Object



260
261
262
263
264
265
266
267
268
269
270
271
# File 'supply/lib/supply/uploader.rb', line 260

def upload_images(language)
  Supply::IMAGES_TYPES.each do |image_type|
    search = File.join(, language, Supply::IMAGES_FOLDER_NAME, image_type) + ".#{IMAGE_FILE_EXTENSIONS}"
    path = Dir.glob(search, File::FNM_CASEFOLD).last
    next unless path

    UI.message("Uploading image file #{path}...")
    client.upload_image(image_path: File.expand_path(path),
                        image_type: image_type,
                          language: language)
  end
end

#upload_mapping(apk_version_codes) ⇒ Object



303
304
305
306
307
308
309
310
311
# File 'supply/lib/supply/uploader.rb', line 303

def upload_mapping(apk_version_codes)
  mapping_paths = [Supply.config[:mapping]] unless (mapping_paths = Supply.config[:mapping_paths])
  mapping_paths.zip(apk_version_codes).each do |mapping_path, version_code|
    if mapping_path
      UI.message("Preparing mapping at path '#{mapping_path}', version code #{version_code} for upload...")
      client.upload_mapping(mapping_path, version_code)
    end
  end
end

#upload_metadata(language, listing) ⇒ Object



247
248
249
250
251
252
253
254
255
256
257
258
# File 'supply/lib/supply/uploader.rb', line 247

def (language, listing)
  Supply::AVAILABLE_METADATA_FIELDS.each do |key|
    path = File.join(, language, "#{key}.txt")
    listing.send("#{key}=".to_sym, File.read(path, encoding: 'UTF-8')) if File.exist?(path)
  end
  begin
    listing.save
  rescue Encoding::InvalidByteSequenceError => ex
    message = (ex.message || '').capitalize
    UI.user_error!("Metadata must be UTF-8 encoded. #{message}")
  end
end

#upload_screenshots(language) ⇒ Object



273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
# File 'supply/lib/supply/uploader.rb', line 273

def upload_screenshots(language)
  Supply::SCREENSHOT_TYPES.each do |screenshot_type|
    search = File.join(, language, Supply::IMAGES_FOLDER_NAME, screenshot_type, "*.#{IMAGE_FILE_EXTENSIONS}")
    paths = Dir.glob(search, File::FNM_CASEFOLD)
    next unless paths.count > 0

    client.clear_screenshots(image_type: screenshot_type, language: language)

    paths.sort.each do |path|
      UI.message("Uploading screenshot #{path}...")
      client.upload_image(image_path: File.expand_path(path),
                          image_type: screenshot_type,
                            language: language)
    end
  end
end

#verify_config!Object



146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
# File 'supply/lib/supply/uploader.rb', line 146

def verify_config!
  unless  || Supply.config[:apk] || Supply.config[:apk_paths] || Supply.config[:aab] || Supply.config[:aab_paths] || (Supply.config[:track] && Supply.config[:track_promote_to])
    UI.user_error!("No local metadata, apks, aab, or track to promote were found, make sure to run `fastlane supply init` to setup supply")
  end

  # Can't upload both at apk and aab at same time
  # Need to error out users when there both apks and aabs are detected
  apk_paths = [Supply.config[:apk], Supply.config[:apk_paths]].flatten.compact
  could_upload_apk = !apk_paths.empty? && !Supply.config[:skip_upload_apk]
  could_upload_aab = Supply.config[:aab] && !Supply.config[:skip_upload_aab]
  if could_upload_apk && could_upload_aab
    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")
  end

  if Supply.config[:release_status] == Supply::ReleaseStatus::DRAFT && Supply.config[:rollout]
    UI.user_error!(%(Cannot specify rollout percentage when the release status is set to 'draft'))
  end

  unless Supply.config[:version_codes_to_retain].nil?
    Supply.config[:version_codes_to_retain] = Supply.config[:version_codes_to_retain].map(&:to_i)
  end
end