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



78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
# File 'supply/lib/supply/uploader.rb', line 78

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



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
# File 'supply/lib/supply/uploader.rb', line 45

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

#promote_trackObject



141
142
143
144
145
146
147
148
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
# File 'supply/lib/supply/uploader.rb', line 141

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



95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
# File 'supply/lib/supply/uploader.rb', line 95

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



255
256
257
258
259
260
261
262
263
264
265
266
# File 'supply/lib/supply/uploader.rb', line 255

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



277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
# File 'supply/lib/supply/uploader.rb', line 277

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



189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
# File 'supply/lib/supply/uploader.rb', line 189

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



207
208
209
210
# File 'supply/lib/supply/uploader.rb', line 207

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

#upload_images(language) ⇒ Object



225
226
227
228
229
230
231
232
233
234
235
236
# File 'supply/lib/supply/uploader.rb', line 225

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



268
269
270
271
272
273
274
275
# File 'supply/lib/supply/uploader.rb', line 268

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



212
213
214
215
216
217
218
219
220
221
222
223
# File 'supply/lib/supply/uploader.rb', line 212

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



238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
# File 'supply/lib/supply/uploader.rb', line 238

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



118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
# File 'supply/lib/supply/uploader.rb', line 118

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