class Supply::Client

Constants

SCOPE
SERVICE

Attributes

current_edit[RW]

Editing something Reference to the entry we're currently editing. Might be nil if don't have one open

current_package_name[RW]

Package name of the currently edited element

Public Class Methods

service_account_authentication(params: nil) click to toggle source

@!group Login

# File supply/lib/supply/client.rb, line 113
def self.service_account_authentication(params: nil)
  if params[:json_key] || params[:json_key_data]
    super(params: params)
  elsif params[:key] && params[:issuer]
    require 'google/api_client/auth/key_utils'
    UI.important("This type of authentication is deprecated. Please consider using JSON authentication instead")
    key = Google::APIClient::KeyUtils.load_from_pkcs12(File.expand_path(params[:key]), 'notasecret')
    cred_json = {
      private_key: key.to_s,
      client_email: params[:issuer]
    }
    service_account_json = StringIO.new(JSON.dump(cred_json))
    service_account_json
  else
    UI.user_error!("No authentication parameters were specified. These must be provided in order to authenticate with Google")
  end
end

Public Instance Methods

aab_version_codes() click to toggle source

Get a list of all AAB version codes - returns the list of version codes

# File supply/lib/supply/client.rb, line 254
def aab_version_codes
  ensure_active_edit!

  result = call_google_api { client.list_edit_bundles(current_package_name, current_edit.id) }

  return Array(result.bundles).map(&:version_code)
end
abort_current_edit() click to toggle source

Aborts the current edit deleting all pending changes

# File supply/lib/supply/client.rb, line 145
def abort_current_edit
  ensure_active_edit!

  call_google_api { client.delete_edit(current_package_name, current_edit.id) }

  self.current_edit = nil
  self.current_package_name = nil
end
apks_version_codes() click to toggle source

Get a list of all APK version codes - returns the list of version codes

# File supply/lib/supply/client.rb, line 245
def apks_version_codes
  ensure_active_edit!

  result = call_google_api { client.list_edit_apks(current_package_name, current_edit.id) }

  return Array(result.apks).map(&:version_code)
end
begin_edit(package_name: nil) click to toggle source

Begin modifying a certain package

# File supply/lib/supply/client.rb, line 136
def begin_edit(package_name: nil)
  UI.user_error!("You currently have an active edit") if @current_edit

  self.current_edit = call_google_api { client.insert_edit(package_name) }

  self.current_package_name = package_name
end
clear_screenshots(image_type: nil, language: nil) click to toggle source
# File supply/lib/supply/client.rb, line 557
def clear_screenshots(image_type: nil, language: nil)
  ensure_active_edit!

  call_google_api do
    client.deleteall_edit_image(
      current_package_name,
      current_edit.id,
      language,
      image_type
    )
  end
end
commit_current_edit!() click to toggle source

Commits the current edit saving all pending changes on Google Play

# File supply/lib/supply/client.rb, line 162
def commit_current_edit!
  ensure_active_edit!

  call_google_api do
    begin
      client.commit_edit(
        current_package_name,
        current_edit.id,
        changes_not_sent_for_review: Supply.config[:changes_not_sent_for_review]
      )
    rescue Google::Apis::ClientError => e
      unless Supply.config[:rescue_changes_not_sent_for_review]
        raise
      end

      error = begin
                JSON.parse(e.body)
              rescue
                nil
              end

      if error
        message = error["error"] && error["error"]["message"]
      else
        message = e.body
      end

      if message.include?("The query parameter changesNotSentForReview must not be set")
        client.commit_edit(
          current_package_name,
          current_edit.id
        )
      elsif message.include?("Please set the query parameter changesNotSentForReview to true")
        client.commit_edit(
          current_package_name,
          current_edit.id,
          changes_not_sent_for_review: true
        )
      else
        raise
      end
    end
  end

  self.current_edit = nil
  self.current_package_name = nil
end
fetch_images(image_type: nil, language: nil) click to toggle source

@!group Screenshots

# File supply/lib/supply/client.rb, line 507
def fetch_images(image_type: nil, language: nil)
  ensure_active_edit!

  result = call_google_api do
    client.list_edit_images(
      current_package_name,
      current_edit.id,
      language,
      image_type
    )
  end

  urls = (result.images || []).map(&:url)
  images = urls.map do |url|
    uri = URI.parse(url)
    clean_url = [
      uri.scheme,
      uri.userinfo,
      uri.host,
      uri.port,
      uri.path
    ].join

    UI.verbose("Initial URL received: '#{url}'")
    UI.verbose("Removed params ('#{uri.query}') from the URL")
    UI.verbose("URL after removing params: '#{clean_url}'")

    full_url = "#{url}=s0" # '=s0' param ensures full image size is returned (https://github.com/fastlane/fastlane/pull/14322#issuecomment-473012462)
    full_url
  end

  return images
end
latest_version(track) click to toggle source
# File supply/lib/supply/client.rb, line 300
def latest_version(track)
  latest_version = tracks.select { |t| t.track == Supply::Tracks::DEFAULT }.map(&:releases).flatten.reject { |r| r.name.nil? }.max_by(&:name)

  # Check if user specified '--track' option if version information from 'production' track is nil
  if latest_version.nil? && track == Supply::Tracks::DEFAULT
    UI.user_error!(%(Unable to find latest version information from "#{Supply::Tracks::DEFAULT}" track. Please specify track information by using the '--track' option.))
  else
    latest_version = tracks.select { |t| t.track == track }.map(&:releases).flatten.reject { |r| r.name.nil? }.max_by(&:name)
  end

  return latest_version
end
listing_for_language(language) click to toggle source

Returns the listing for the given language filled with the current values if it already exists

# File supply/lib/supply/client.rb, line 227
def listing_for_language(language)
  ensure_active_edit!

  begin
    result = client.get_edit_listing(
      current_package_name,
      current_edit.id,
      language
    )

    return Listing.new(self, language, result)
  rescue Google::Apis::ClientError => e
    return Listing.new(self, language) if e.status_code == 404 # create a new empty listing
    raise
  end
end
listings() click to toggle source

Get a list of all languages - returns the list make sure to have an active edit

# File supply/lib/supply/client.rb, line 216
def listings
  ensure_active_edit!

  result = call_google_api { client.list_edit_listings(current_package_name, current_edit.id) }

  return result.listings.map do |row|
    Listing.new(self, row.language, row)
  end
end
release_listings(version) click to toggle source
# File supply/lib/supply/client.rb, line 262
def release_listings(version)
  ensure_active_edit!

  # Verify that tracks have releases
  filtered_tracks = tracks.select { |t| !t.releases.nil? && t.releases.any? { |r| r.name == version } }

  if filtered_tracks.length > 1
    # Production track takes precedence if version is present in multiple tracks
    # E.g.: A release might've been promoted from Alpha/Beta track. This means the release will be present in two or more tracks
    if filtered_tracks.any? { |t| t.track == Supply::Tracks::DEFAULT }
      filtered_tracks = filtered_tracks.select { |t| t.track == Supply::Tracks::DEFAULT }
    else
      # E.g.: A release might be in both Alpha & Beta (not sure if this is possible, just catching if it ever happens), giving Beta precedence.
      filtered_tracks = filtered_tracks.select { |t| t.track == Supply::Tracks::BETA }
    end
  end

  filtered_track = filtered_tracks.first
  if filtered_track.nil?
    UI.user_error!("Unable to find version '#{version}' for '#{current_package_name}' in all tracks. Please double check the version number.")
    return nil
  else
    UI.message("Found '#{version}' in '#{filtered_track.track}' track.")
  end

  filtered_release = filtered_track.releases.first { |r| !r.name.nil? && r.name == version }

  # Since we can release on Internal/Alpha/Beta without release notes.
  if filtered_release.release_notes.nil?
    UI.message("Version '#{version}' for '#{current_package_name}' does not seem to have any release notes. Nothing to download.")
    return []
  end

  return filtered_release.release_notes.map do |row|
    Supply::ReleaseListing.new(filtered_track, filtered_release.name, filtered_release.version_codes, row.language, row.text)
  end
end
track_releases(track) click to toggle source

Get list of release names for track

# File supply/lib/supply/client.rb, line 457
def track_releases(track)
  ensure_active_edit!

  begin
    result = client.get_edit_track(
      current_package_name,
      current_edit.id,
      track
    )
    return result.releases || []
  rescue Google::Apis::ClientError => e
    return [] if e.status_code == 404 && e.to_s.include?("trackEmpty")
    raise
  end
end
track_version_codes(track) click to toggle source

Get list of version codes for track

# File supply/lib/supply/client.rb, line 440
def track_version_codes(track)
  ensure_active_edit!

  begin
    result = client.get_edit_track(
      current_package_name,
      current_edit.id,
      track
    )
    return result.releases.flat_map(&:version_codes) || []
  rescue Google::Apis::ClientError => e
    return [] if e.status_code == 404 && (e.to_s.include?("trackEmpty") || e.to_s.include?("Track not found"))
    raise
  end
end
tracks(*tracknames) click to toggle source

Get a list of all tracks - returns the list

# File supply/lib/supply/client.rb, line 413
def tracks(*tracknames)
  ensure_active_edit!

  all_tracks = call_google_api { client.list_edit_tracks(current_package_name, current_edit.id) }.tracks
  all_tracks = [] unless all_tracks

  if tracknames.length > 0
    all_tracks = all_tracks.select { |track| tracknames.include?(track.track) }
  end

  return all_tracks
end
update_listing_for_language(language: nil, title: nil, short_description: nil, full_description: nil, video: nil) click to toggle source

Updates or creates the listing for the specified language

# File supply/lib/supply/client.rb, line 318
def update_listing_for_language(language: nil, title: nil, short_description: nil, full_description: nil, video: nil)
  ensure_active_edit!

  listing = AndroidPublisher::Listing.new(
    language: language,
    title: title,
    full_description: full_description,
    short_description: short_description,
    video: video
  )

  call_google_api do
    client.update_edit_listing(
      current_package_name,
      current_edit.id,
      language,
      listing
    )
  end
end
update_obb(apk_version_code, expansion_file_type, references_version, file_size) click to toggle source
# File supply/lib/supply/client.rb, line 486
def update_obb(apk_version_code, expansion_file_type, references_version, file_size)
  ensure_active_edit!

  call_google_api do
    client.update_edit_expansionfile(
      current_package_name,
      current_edit.id,
      apk_version_code,
      expansion_file_type,
      AndroidPublisher::ExpansionFile.new(
        references_version: references_version,
        file_size: file_size
      )
    )
  end
end
update_track(track_name, track_object) click to toggle source
# File supply/lib/supply/client.rb, line 426
def update_track(track_name, track_object)
  ensure_active_edit!

  call_google_api do
    client.update_edit_track(
      current_package_name,
      current_edit.id,
      track_name,
      track_object
    )
  end
end
upload_apk(path_to_apk) click to toggle source
# File supply/lib/supply/client.rb, line 339
def upload_apk(path_to_apk)
  ensure_active_edit!

  result_upload = call_google_api do
    client.upload_edit_apk(
      current_package_name,
      current_edit.id,
      upload_source: path_to_apk
    )
  end

  return result_upload.version_code
end
upload_apk_to_internal_app_sharing(package_name, path_to_apk) click to toggle source
# File supply/lib/supply/client.rb, line 353
def upload_apk_to_internal_app_sharing(package_name, path_to_apk)
  # NOTE: This Google API is a little different. It doesn't require an active edit.
  result_upload = call_google_api do
    client.uploadapk_internalappsharingartifact(
      package_name,
      upload_source: path_to_apk,
      content_type: "application/octet-stream"
    )
  end

  return result_upload.download_url
end
upload_bundle(path_to_aab) click to toggle source
# File supply/lib/supply/client.rb, line 383
def upload_bundle(path_to_aab)
  ensure_active_edit!

  result_upload = call_google_api do
    client.upload_edit_bundle(
      current_package_name,
      self.current_edit.id,
      upload_source: path_to_aab,
      content_type: "application/octet-stream",
      ack_bundle_installation_warning: Supply.config[:ack_bundle_installation_warning]
    )
  end

  return result_upload.version_code
end
upload_bundle_to_internal_app_sharing(package_name, path_to_aab) click to toggle source
# File supply/lib/supply/client.rb, line 399
def upload_bundle_to_internal_app_sharing(package_name, path_to_aab)
  # NOTE: This Google API is a little different. It doesn't require an active edit.
  result_upload = call_google_api do
    client.uploadbundle_internalappsharingartifact(
      package_name,
      upload_source: path_to_aab,
      content_type: "application/octet-stream"
    )
  end

  return result_upload.download_url
end
upload_changelogs(track, track_name) click to toggle source
# File supply/lib/supply/client.rb, line 473
def upload_changelogs(track, track_name)
  ensure_active_edit!

  call_google_api do
    client.update_edit_track(
      current_package_name,
      self.current_edit.id,
      track_name,
      track
    )
  end
end
upload_image(image_path: nil, image_type: nil, language: nil) click to toggle source

@param image_type (e.g. phoneScreenshots, sevenInchScreenshots, …)

# File supply/lib/supply/client.rb, line 542
def upload_image(image_path: nil, image_type: nil, language: nil)
  ensure_active_edit!

  call_google_api do
    client.upload_edit_image(
      current_package_name,
      current_edit.id,
      language,
      image_type,
      upload_source: image_path,
      content_type: 'image/*'
    )
  end
end
upload_mapping(path_to_mapping, apk_version_code) click to toggle source
# File supply/lib/supply/client.rb, line 366
def upload_mapping(path_to_mapping, apk_version_code)
  ensure_active_edit!

  extension = File.extname(path_to_mapping).downcase

  call_google_api do
    client.upload_edit_deobfuscationfile(
      current_package_name,
      current_edit.id,
      apk_version_code,
      extension == ".zip" ? "nativeCode" : "proguard",
      upload_source: path_to_mapping,
      content_type: "application/octet-stream"
    )
  end
end
upload_obb(obb_file_path: nil, apk_version_code: nil, expansion_file_type: nil) click to toggle source
# File supply/lib/supply/client.rb, line 570
def upload_obb(obb_file_path: nil, apk_version_code: nil, expansion_file_type: nil)
  ensure_active_edit!

  call_google_api do
    client.upload_edit_expansionfile(
      current_package_name,
      current_edit.id,
      apk_version_code,
      expansion_file_type,
      upload_source: obb_file_path,
      content_type: 'application/octet-stream'
    )
  end
end
validate_current_edit!() click to toggle source

Validates the current edit - does not change data on Google Play

# File supply/lib/supply/client.rb, line 155
def validate_current_edit!
  ensure_active_edit!

  call_google_api { client.validate_edit(current_package_name, current_edit.id) }
end

Private Instance Methods

ensure_active_edit!() click to toggle source
# File supply/lib/supply/client.rb, line 587
def ensure_active_edit!
  UI.user_error!("You need to have an active edit, make sure to call `begin_edit`") unless @current_edit
end