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



86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
# File 'supply/lib/supply/uploader.rb', line 86

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
# 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]

  # Only update tracks if we have version codes
  # Updating a track with empty version codes can completely clear out a track
  update_track(apk_version_codes) unless apk_version_codes.empty?

  if Supply.config[:track_promote_to]
    promote_track
  elsif !Supply.config[:rollout].nil? && Supply.config[:track].to_s != ""
    update_rollout
  end

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

  perform_upload_meta(apk_version_codes)
end

#perform_upload_meta(version_codes) ⇒ Object



41
42
43
44
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
72
73
74
75
76
77
78
79
80
81
82
83
84
# File 'supply/lib/supply/uploader.rb', line 41

def perform_upload_meta(version_codes)
  client.begin_edit(package_name: Supply.config[:package_name])

  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

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

#promote_trackObject



149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
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
# File 'supply/lib/supply/uploader.rb', line 149

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

  if Supply.config[:rollout]
    release.status = Supply::ReleaseStatus::IN_PROGRESS
    release.user_fraction = Supply.config[: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



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

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



263
264
265
266
267
268
269
270
271
272
273
274
# File 'supply/lib/supply/uploader.rb', line 263

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



285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
# File 'supply/lib/supply/uploader.rb', line 285

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



197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
# File 'supply/lib/supply/uploader.rb', line 197

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
    UI.message("Could not find changelog for '#{version_code}' and language '#{language}' at path #{path}...")
  end

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

#upload_changelogs(release_notes, release, track) ⇒ Object



215
216
217
218
# File 'supply/lib/supply/uploader.rb', line 215

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

#upload_images(language) ⇒ Object



233
234
235
236
237
238
239
240
241
242
243
244
# File 'supply/lib/supply/uploader.rb', line 233

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



276
277
278
279
280
281
282
283
# File 'supply/lib/supply/uploader.rb', line 276

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
      client.upload_mapping(mapping_path, version_code)
    end
  end
end

#upload_metadata(language, listing) ⇒ Object



220
221
222
223
224
225
226
227
228
229
230
231
# File 'supply/lib/supply/uploader.rb', line 220

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



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

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



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

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