class Deliver::SyncScreenshots
Constants
- DeleteScreenshotJob
- UploadScreenshotJob
Public Class Methods
new(app:, platform:)
click to toggle source
# File deliver/lib/deliver/sync_screenshots.rb, line 32 def initialize(app:, platform:) @app = app @platform = platform end
Public Instance Methods
do_replace_screenshots(iterator, screenshots, delete_worker, upload_worker)
click to toggle source
This is a testable method that focuses on figuring out what to update
# File deliver/lib/deliver/sync_screenshots.rb, line 101 def do_replace_screenshots(iterator, screenshots, delete_worker, upload_worker) remote_screenshots = iterator.each_app_screenshot.map do |localization, app_screenshot_set, app_screenshot| ScreenshotComparable.create_from_remote(app_screenshot: app_screenshot, locale: localization.locale) end local_screenshots = iterator.each_local_screenshot(screenshots.group_by(&:language)).map do |localization, app_screenshot_set, screenshot, index| if index >= 10 UI.user_error!("Found #{localization.locale} has more than 10 screenshots for #{app_screenshot_set.screenshot_display_type}. "\ "Make sure containts only necessary screenshots.") end ScreenshotComparable.create_from_local(screenshot: screenshot, app_screenshot_set: app_screenshot_set) end # Thanks to `Array#-` API and `ScreenshotComparable`, working out diffs between local screenshot directory and App Store Connect # is as easy as you can see below. The former one finds what is missing in local and the latter one is visa versa. screenshots_to_delete = remote_screenshots - local_screenshots screenshots_to_upload = local_screenshots - remote_screenshots delete_jobs = screenshots_to_delete.map { |x| DeleteScreenshotJob.new(x.context[:app_screenshot], x.context[:locale]) } delete_worker.batch_enqueue(delete_jobs) delete_worker.start upload_jobs = screenshots_to_upload.map { |x| UploadScreenshotJob.new(x.context[:app_screenshot_set], x.context[:screenshot].path) } upload_worker.batch_enqueue(upload_jobs) upload_worker.start end
enable_localizations(locales)
click to toggle source
# File deliver/lib/deliver/sync_screenshots.rb, line 71 def enable_localizations(locales) localizations = fetch_localizations locales_to_enable = locales - localizations.map(&:locale) Helper.show_loading_indicator("Activating localizations for #{locales_to_enable.join(', ')}...") locales_to_enable.each do |locale| version.create_app_store_version_localization(attributes: { locale: locale }) end Helper.hide_loading_indicator end
replace_screenshots(iterator, screenshots, retries = 3)
click to toggle source
# File deliver/lib/deliver/sync_screenshots.rb, line 81 def replace_screenshots(iterator, screenshots, retries = 3) # delete and upload screenshots to get App Store Connect in sync do_replace_screenshots(iterator, screenshots, create_delete_worker, create_upload_worker) # wait for screenshots to be processed on App Store Connect end and # ensure the number of uploaded screenshots matches the one in local result = wait_for_complete(iterator) return if !result.processing? && result.screenshot_count == screenshots.count if retries.zero? UI.crash!("Retried uploading screenshots #{retries} but there are still failures of processing screenshots." \ "Check App Store Connect console to work out which screenshots processed unsuccessfully.") end # retry with deleting failing screenshots result.failing_screenshots.each(&:delete!) replace_screenshots(iterator, screenshots, retries - 1) end
sort_screenshots(iterator)
click to toggle source
# File deliver/lib/deliver/sync_screenshots.rb, line 153 def sort_screenshots(iterator) Helper.show_loading_indicator("Sorting screenshots uploaded...") sort_worker = create_sort_worker sort_worker.batch_enqueue(iterator.each_app_screenshot_set.to_a.map { |_, set| set }) sort_worker.start Helper.hide_loading_indicator end
sync(screenshots)
click to toggle source
# File deliver/lib/deliver/sync_screenshots.rb, line 43 def sync(screenshots) UI.important('This is currently a beta feature in fastlane. This may cause some errors on your environment.') unless FastlaneCore::Feature.enabled?('FASTLANE_ENABLE_BETA_DELIVER_SYNC_SCREENSHOTS') UI.user_error!('Please set a value to "FASTLANE_ENABLE_BETA_DELIVER_SYNC_SCREENSHOTS" environment variable ' \ 'if you acknowleage the risk and try this out.') end UI.important("Will begin uploading snapshots for '#{version.version_string}' on App Store Connect") # enable localizations that will be used screenshots_per_language = screenshots.group_by(&:language) enable_localizations(screenshots_per_language.keys) # create iterator localizations = fetch_localizations iterator = Deliver::AppScreenshotIterator.new(localizations) # sync local screenshots with remote settings by deleting and uploading UI.message("Starting with the upload of screenshots...") replace_screenshots(iterator, screenshots) # ensure screenshots within screenshot sets are sorted in right order sort_screenshots(iterator) UI.important('Screenshots are synced successfully!') end
sync_from_path(screenshots_path)
click to toggle source
# File deliver/lib/deliver/sync_screenshots.rb, line 37 def sync_from_path(screenshots_path) # load local screenshots screenshots = Deliver::Loader.load_app_screenshots(screenshots_path, true) sync(screenshots) end
wait_for_complete(iterator)
click to toggle source
# File deliver/lib/deliver/sync_screenshots.rb, line 128 def wait_for_complete(iterator) retry_count = 0 Helper.show_loading_indicator("Waiting for all the screenshots processed...") loop do failing_screenshots = [] state_counts = iterator.each_app_screenshot.map { |_, _, app_screenshot| app_screenshot }.each_with_object({}) do |app_screenshot, hash| state = app_screenshot.asset_delivery_state['state'] hash[state] ||= 0 hash[state] += 1 failing_screenshots << app_screenshot if app_screenshot.error? end result = UploadResult.new(asset_delivery_state_counts: state_counts, failing_screenshots: failing_screenshots) return result unless result.processing? # sleep with exponential backoff interval = 5 + (2**retry_count) UI.message("There are still incomplete screenshots. Will check the states again in #{interval} secs - #{state_counts}") sleep(interval) retry_count += 1 end ensure Helper.hide_loading_indicator end
Private Instance Methods
create_delete_worker()
click to toggle source
# File deliver/lib/deliver/sync_screenshots.rb, line 180 def create_delete_worker FastlaneCore::QueueWorker.new do |job| target = "id=#{job.app_screenshot.id} #{job.locale} #{job.app_screenshot.file_name}" UI.verbose("Deleting '#{target}'") start_time = Time.now job.app_screenshot.delete! UI.message("Deleted '#{target}' - (#{Time.now - start_time} secs)") end end
create_sort_worker()
click to toggle source
# File deliver/lib/deliver/sync_screenshots.rb, line 190 def create_sort_worker FastlaneCore::QueueWorker.new do |app_screenshot_set| original_ids = app_screenshot_set.app_screenshots.map(&:id) sorted_ids = Naturally.sort(app_screenshot_set.app_screenshots, by: :file_name).map(&:id) if original_ids != sorted_ids app_screenshot_set.reorder_screenshots(app_screenshot_ids: sorted_ids) end end end
create_upload_worker()
click to toggle source
# File deliver/lib/deliver/sync_screenshots.rb, line 171 def create_upload_worker FastlaneCore::QueueWorker.new do |job| UI.verbose("Uploading '#{job.path}'...") start_time = Time.now job.app_screenshot_set.upload_screenshot(path: job.path, wait_for_processing: false) UI.message("Uploaded '#{job.path}'... (#{Time.now - start_time} secs)") end end
fetch_localizations()
click to toggle source
# File deliver/lib/deliver/sync_screenshots.rb, line 167 def fetch_localizations version.get_app_store_version_localizations end
version()
click to toggle source
# File deliver/lib/deliver/sync_screenshots.rb, line 163 def version @version ||= @app.get_edit_app_store_version(platform: @platform) end