class Spaceship::ConnectAPI::AppScreenshot

Attributes

asset_delivery_state[RW]
asset_token[RW]
asset_type[RW]
file_name[RW]
file_size[RW]
image_asset[RW]
source_file_checksum[RW]
upload_operations[RW]
uploaded[RW]

Public Class Methods

create(client: nil, app_screenshot_set_id: nil, path: nil, wait_for_processing: true) click to toggle source

API

# File spaceship/lib/spaceship/connect_api/models/app_screenshot.rb, line 82
def self.create(client: nil, app_screenshot_set_id: nil, path: nil, wait_for_processing: true)
  client ||= Spaceship::ConnectAPI
  require 'faraday'

  filename = File.basename(path)
  filesize = File.size(path)
  bytes = File.binread(path)

  post_attributes = {
    fileSize: filesize,
    fileName: filename
  }

  # Create placeholder to upload screenshot
  begin
    screenshot = client.post_app_screenshot(
      app_screenshot_set_id: app_screenshot_set_id,
      attributes: post_attributes
    ).first
  rescue => error
    # Sometimes creating a screenshot with the web session App Store Connect API
    # will result in a false failure. The response will return a 503 but the database
    # insert will eventually go through.
    #
    # When this is observed, we will poll until we find the matchin screenshot that
    # is awaiting for upload and file size
    #
    # https://github.com/fastlane/fastlane/pull/16842
    time = Time.now.to_i

    timeout_minutes = (ENV["SPACESHIP_SCREENSHOT_UPLOAD_TIMEOUT"] || 20).to_i

    loop do
      # This error handling needs to be revised since any error occurred can reach here.
      # It should handle errors based on what status code is.
      puts("Waiting for screenshots to appear before uploading. This is unlikely to be recovered unless it's 503 error. error=\"#{error}\"")
      sleep(30)

      screenshots = Spaceship::ConnectAPI::AppScreenshotSet
                    .get(client: client, app_screenshot_set_id: app_screenshot_set_id)
                    .app_screenshots

      screenshot = screenshots.find do |s|
        s.awaiting_upload? && s.file_size == filesize
      end

      break if screenshot

      time_diff = Time.now.to_i - time
      raise error if time_diff >= (60 * timeout_minutes)
    end
  end

  # Upload the file
  upload_operations = screenshot.upload_operations
  Spaceship::ConnectAPI::FileUploader.upload(upload_operations, bytes)

  # Update file uploading complete
  patch_attributes = {
    uploaded: true,
    sourceFileChecksum: Digest::MD5.hexdigest(bytes)
  }

  # Patch screenshot that file upload is complete
  # Catch error if patch retries due to 504. Origal patch
  # may go through by return response as 504.
  begin
    screenshot = Spaceship::ConnectAPI.patch_app_screenshot(
      app_screenshot_id: screenshot.id,
      attributes: patch_attributes
    ).first
  rescue => error
    puts("Failed to patch app screenshot. Update may have gone through so verifying") if Spaceship::Globals.verbose?

    screenshot = client.get_app_screenshot(app_screenshot_id: screenshot.id).first
    raise error unless screenshot.complete?
  end

  # Wait for processing
  if wait_for_processing
    loop do
      if screenshot.complete?
        puts("Screenshot processing complete!") if Spaceship::Globals.verbose?
        break
      elsif screenshot.error?
        messages = ["Error processing screenshot '#{screenshot.file_name}'"] + screenshot.error_messages
        raise messages.join(". ")
      end

      # Poll every 2 seconds
      sleep_time = 2
      puts("Waiting #{sleep_time} seconds before checking status of processing...") if Spaceship::Globals.verbose?
      sleep(sleep_time)

      screenshot = client.get_app_screenshot(app_screenshot_id: screenshot.id).first
    end
  end

  return screenshot
end
type() click to toggle source
# File spaceship/lib/spaceship/connect_api/models/app_screenshot.rb, line 35
def self.type
  return "appScreenshots"
end

Public Instance Methods

awaiting_upload?() click to toggle source
# File spaceship/lib/spaceship/connect_api/models/app_screenshot.rb, line 39
def awaiting_upload?
  (asset_delivery_state || {})["state"] == "AWAITING_UPLOAD"
end
complete?() click to toggle source
# File spaceship/lib/spaceship/connect_api/models/app_screenshot.rb, line 43
def complete?
  (asset_delivery_state || {})["state"] == "COMPLETE"
end
delete!(client: nil, filter: {}, includes: nil, limit: nil, sort: nil) click to toggle source
# File spaceship/lib/spaceship/connect_api/models/app_screenshot.rb, line 183
def delete!(client: nil, filter: {}, includes: nil, limit: nil, sort: nil)
  client ||= Spaceship::ConnectAPI
  client.delete_app_screenshot(app_screenshot_id: id)
end
error?() click to toggle source
# File spaceship/lib/spaceship/connect_api/models/app_screenshot.rb, line 47
def error?
  (asset_delivery_state || {})["state"] == "FAILED"
end
error_messages() click to toggle source
# File spaceship/lib/spaceship/connect_api/models/app_screenshot.rb, line 51
def error_messages
  errors = (asset_delivery_state || {})["errors"]
  (errors || []).map do |error|
    [error["code"], error["description"]].compact.join(" - ")
  end
end
image_asset_url(width: nil, height: nil, type: "png") click to toggle source

This does not download the source image (exact image that was uploaded) This downloads a modified version. This image won't have the same checksums as source_file_checksum.

There is an open radar for allowing downloading of source file. openradar.appspot.com/radar?id=4980344105205760

# File spaceship/lib/spaceship/connect_api/models/app_screenshot.rb, line 64
def image_asset_url(width: nil, height: nil, type: "png")
  return nil if image_asset.nil?

  template_url = image_asset["templateUrl"]
  width ||= image_asset["width"]
  height ||= image_asset["height"]

  return template_url
         .gsub("{w}", width.to_s)
         .gsub("{h}", height.to_s)
         .gsub("{f}", type)
end