Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[supply] parallel uploads for meta per language #21474

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
8 changes: 6 additions & 2 deletions fastlane/lib/fastlane/actions/docs/upload_to_play_store.md
Expand Up @@ -179,6 +179,12 @@ This can be done using the `--track_promote_to` parameter. The `--track_promote_
Before performing a new APK upload you may want to check existing track version codes or release names, or you may simply want to provide an informational lane that displays the currently promoted version codes or release name for the production track. You can use the `google_play_track_version_codes` action to retrieve existing version codes for a package and track. You can use the `google_play_track_release_names` action to retrieve existing release names for a package and track.
For more information, see the `fastlane action google_play_track_version_codes` and `fastlane action google_play_track_release_names` help output.

## Parallel uploads

By default _supply_ will spawn 10 threads to upload the metadata concurrently (_images, screenshots, texts_). If you want to change this, set either `DELIVER_NUMBER_OF_THREADS` or `FL_NUMBER_OF_THREADS` environment variable to any value between 1 and 10.

If you want _supply_ to upload with more than 10 threads in parallel then you need to **additionally** set `FL_MAX_NUMBER_OF_THREADS` environment variable to the max number of parallel upload threads you wish to have (**Warning ⚠️** use this at your own risk!).

## Migration from AndroidPublisherV2 to AndroidPublisherV3 in _fastlane_ 2.135.0

### New Options
Expand All @@ -200,5 +206,3 @@ For more information, see the `fastlane action google_play_track_version_codes`
- Google Play will automatically remove releases that are superseded now
- `:deactivate_on_promote`
- Google Play will automatically deactivate a release from its previous track on promote

:
2 changes: 1 addition & 1 deletion fastlane_core/lib/fastlane_core/queue_worker.rb
Expand Up @@ -6,7 +6,7 @@ module FastlaneCore
# Use this when you have all the items that you'll process in advance.
# Simply enqueue them to this and call `QueueWorker#start`.
class QueueWorker
NUMBER_OF_THREADS = FastlaneCore::Helper.test? ? 1 : [(ENV["DELIVER_NUMBER_OF_THREADS"] || ENV.fetch("FL_NUMBER_OF_THREADS", 10)).to_i, 10].min
NUMBER_OF_THREADS = FastlaneCore::Helper.test? ? 1 : [ENV["DELIVER_NUMBER_OF_THREADS"], ENV["FL_NUMBER_OF_THREADS"], 10].map(&:to_i).find(&:positive?).clamp(1, ENV.fetch("FL_MAX_NUMBER_OF_THREADS", 10).to_i)

# @param concurrency (Numeric) - A number of threads to be created
# @param block (Proc) - A task you want to execute with enqueued items
Expand Down
39 changes: 27 additions & 12 deletions supply/lib/supply/uploader.rb
@@ -1,6 +1,10 @@
require 'fastlane_core'

module Supply
# rubocop:disable Metrics/ClassLength
class Uploader
UploadJob = Struct.new(:language, :version_code, :release_notes_queue)

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

Expand Down Expand Up @@ -88,19 +92,15 @@ def perform_upload_meta(version_codes, track_name)
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 = []
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One difference in behavior before/after this change is that before, release_notes was reset to [] on each iteration of the version_codes loop, while now it's not, and thus is common to all version_codes.

That might break the logic (and potentially mix up the release notes published when there are different version codes with different changelogs/*.txt files.

You might thus want to keep this reset of release_notes = [] inside the loop to cover for this case.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nicely observed 😄 I haven't been testing the multi version codes scenario. Will fix.

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)

upload_metadata(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
release_notes_queue = Queue.new
upload_worker = create_meta_upload_worker
upload_worker.batch_enqueue(
# skip . or .. or hidden folders
all_languages.reject { |lang| lang.start_with?('.') }.map { |lang| UploadJob.new(lang, version_code, release_notes_queue) }
)
upload_worker.start

release_notes = Array.new(release_notes_queue.size) { release_notes_queue.pop } # Queue to Array
upload_changelogs(release_notes, release, track, track_name) unless release_notes.empty?
end
end
Expand Down Expand Up @@ -511,6 +511,21 @@ def obb_expansion_file_type(obb_file_path)
'patch'
end
end

def create_meta_upload_worker
FastlaneCore::QueueWorker.new do |job|
UI.message("Preparing uploads for language '#{job.language}'...")
start_time = Time.now
listing = client.listing_for_language(job.language)
upload_metadata(job.language, listing) unless Supply.config[:skip_upload_metadata]
upload_images(job.language) unless Supply.config[:skip_upload_images]
upload_screenshots(job.language) unless Supply.config[:skip_upload_screenshots]
job.release_notes_queue << upload_changelog(job.language, job.version_code) unless Supply.config[:skip_upload_changelogs]
UI.message("Uploaded all items for language '#{job.language}'... (#{Time.now - start_time} secs)")
rescue => error
UI.abort_with_message!("#{job.language} - #{error}")
end
end
end
# rubocop:enable Metrics/ClassLength
end
Empty file.
@@ -0,0 +1 @@
en-US changelog 1
@@ -0,0 +1 @@
en-US changelog 2
@@ -0,0 +1 @@
en-US changelog -1
@@ -0,0 +1 @@
en-US full description
@@ -0,0 +1 @@
en-US short description
1 change: 1 addition & 0 deletions supply/spec/fixtures/metadata/android/en-US/title.txt
@@ -0,0 +1 @@
en-US title
1 change: 1 addition & 0 deletions supply/spec/fixtures/metadata/android/en-US/video.txt
@@ -0,0 +1 @@
en-US video
Empty file.
@@ -0,0 +1 @@
fr-FR changelog 1
@@ -0,0 +1 @@
fr-FR changelog 2
@@ -0,0 +1 @@
fr-FR changelog -1
@@ -0,0 +1 @@
fr-FR full description
@@ -0,0 +1 @@
fr-FR short description
1 change: 1 addition & 0 deletions supply/spec/fixtures/metadata/android/fr-FR/title.txt
@@ -0,0 +1 @@
fr-FR title
1 change: 1 addition & 0 deletions supply/spec/fixtures/metadata/android/fr-FR/video.txt
@@ -0,0 +1 @@
fr-FR video
Empty file.
@@ -0,0 +1 @@
ja-JP changelog 1
@@ -0,0 +1 @@
ja-JP changelog 2
@@ -0,0 +1 @@
ja-JP changelog -1
@@ -0,0 +1 @@
ja-JP full description
@@ -0,0 +1 @@
ja-JP short description
1 change: 1 addition & 0 deletions supply/spec/fixtures/metadata/android/ja-JP/title.txt
@@ -0,0 +1 @@
ja-JP title
1 change: 1 addition & 0 deletions supply/spec/fixtures/metadata/android/ja-JP/video.txt
@@ -0,0 +1 @@
ja-JP video
46 changes: 41 additions & 5 deletions supply/spec/uploader_spec.rb
Expand Up @@ -203,25 +203,61 @@ def find_obbs
end
end

describe '#perform_upload' do
# add basic == functionality to LocalizedText class for testing purpose
class AndroidPublisher::LocalizedText
def ==(other)
self.language == other.language && self.text == other.text
end
end

shared_examples 'run supply to upload metadata' do |version_codes:, with_explicit_changelogs:|
let(:languages) { ['en-US', 'fr-FR', 'ja-JP'] }
subject(:release) { double('release', version_codes: version_codes) }
let(:client) { double('client') }
let(:config) { { apk: 'some/path/app.apk' } }
let(:config) { { apk_paths: version_codes.map { |v_code| "some/path/app-v#{v_code}.apk" }, metadata_path: 'supply/spec/fixtures/metadata/android', track: 'track-name' } }

before do
Supply.config = config
allow(Supply::Client).to receive(:make_from_config).and_return(client)
allow(client).to receive(:upload_apk).with(config[:apk]).and_return(1) # newly uploaded version code
version_codes.each do |version_code|
allow(client).to receive(:upload_apk).with("some/path/app-v#{version_code}.apk").and_return(version_code) # newly uploaded version code
end
allow(client).to receive(:upload_changelogs).and_return(nil)
allow(client).to receive(:tracks).with('track-name').and_return([double('tracks', releases: [ release ])])
languages.each do |lang|
allow(client).to receive(:listing_for_language).with(lang).and_return(Supply::Listing.new(client, lang))
end
allow(client).to receive(:begin_edit).and_return(nil)
allow(client).to receive(:commit_current_edit!).and_return(nil)
end

it 'should update track with correct version codes' do
it 'should update track with correct version codes and optional changelog' do
uploader = Supply::Uploader.new
expect(uploader).to receive(:update_track).with([1]).once
expect(uploader).to receive(:update_track).with(version_codes).once
version_codes.each do |version_code|
expected_notes = languages.map do |lang|
AndroidPublisher::LocalizedText.new(
language: lang,
text: "#{lang} changelog #{with_explicit_changelogs ? version_code : -1}"
)
end.uniq
# check if at least one of the assignments of release_notes is what we expect
expect(release).to receive(:release_notes=).with(match_array(expected_notes))
# check if the listings are updated for each language with text data from disk
languages.each do |lang|
expect(client).to receive(:update_listing_for_language).with({ language: lang, full_description: "#{lang} full description", short_description: "#{lang} short description", title: "#{lang} title", video: "#{lang} video" })
end
end

uploader.perform_upload
end
end

describe '#peform_upload with metadata' do
it_behaves_like 'run supply to upload metadata', version_codes: [1, 2], with_explicit_changelogs: true
it_behaves_like 'run supply to upload metadata', version_codes: [3], with_explicit_changelogs: false
end

context 'when sync_image_upload is set' do
let(:client) { double('client') }
let(:language) { 'pt-BR' }
Expand Down