class Fastlane::Actions::FlurryUploadDsymAction

Constants

METADATA_BASE_URL
UPLOAD_BASE_URL

Public Class Methods

authors() click to toggle source
# File lib/fastlane/plugin/flurry/actions/flurry_upload_dsym.rb, line 210
def self.authors
  ["duseja2"]
end
available_options() click to toggle source
# File lib/fastlane/plugin/flurry/actions/flurry_upload_dsym.rb, line 173
def self.available_options
  [
      FastlaneCore::ConfigItem.new(key: :api_key,
                                   env_name: 'FLURRY_API_KEY',
                                   description: 'Flurry API Key',
                                   verify_block: proc do |value|
                                     UI.user_error!("No API Key for Flurry given, pass using `api_key: 'apiKey'`") if value.to_s.length == 0
                                   end),
      FastlaneCore::ConfigItem.new(key: :auth_token,
                                   env_name: 'FLURRY_AUTH_TOKEN',
                                   description: 'Flurry Auth Token',
                                   verify_block: proc do |value|
                                     UI.user_error!("No Auth Token for Flurry given, pass using `auth_token: 'token'`") if value.to_s.length == 0
                                   end),
      FastlaneCore::ConfigItem.new(key: :dsym_path,
                                   env_name: 'FLURRY_DSYM_PATH',
                                   description: 'Path to the DSYM file to upload',
                                   default_value: Actions.lane_context[SharedValues::DSYM_OUTPUT_PATH],
                                   optional: true,
                                   verify_block: proc do |value|
                                     UI.user_error!("Couldn't find file at path '#{File.expand_path(value)}'") unless File.exist?(value)
                                     UI.user_error!('Symbolication file needs to be dSYM or zip') unless value.end_with?('.dSYM', '.zip')
                                   end),
      FastlaneCore::ConfigItem.new(key: :dsym_paths,
                                   env_name: 'FLURRY_DSYM_PATHS',
                                   description: 'Path to an array of your symbols file. For iOS and Mac provide path to app.dSYM.zip',
                                   default_value: Actions.lane_context[SharedValues::DSYM_PATHS],
                                   is_string: false,
                                   optional: true),
      FastlaneCore::ConfigItem.new(key: :timeout_in_s,
                                   env_name: 'TIMEOUT_IN_S',
                                   description: 'Upload Timeout in Seconds',
                                   optional: true,
                                   default_value: '600')
  ]
end
category() click to toggle source
# File lib/fastlane/plugin/flurry/actions/flurry_upload_dsym.rb, line 228
def self.category
  :misc
end
check_upload_status(project_id, upload_id, auth_token, max_duration_seconds) click to toggle source
# File lib/fastlane/plugin/flurry/actions/flurry_upload_dsym.rb, line 130
def self.check_upload_status(project_id, upload_id, auth_token, max_duration_seconds)
  time_elapsed = 0
  while time_elapsed < max_duration_seconds.to_i do
    response = RestClient.get "#{METADATA_BASE_URL}/project/#{project_id}/uploads/#{upload_id}?fields[upload]=uploadStatus,failureReason", get_metadata_headers(auth_token)
    json_response = JSON.parse(response.body)
    upload_status = json_response["data"]["attributes"]["uploadStatus"]
    if upload_status == "COMPLETED"
      return
    elsif upload_status == "FAILED"
      reason = json_response["data"]["attributes"]["failureReason"]
      UI.user_error! "Failed to upload the provided dSYMs to Flurry with the following reason: #{reason}"
    end
    sleep 2
    time_elapsed += 2
  end
  UI.user_error! "Timed out after #{time_elapsed} seconds while uploading the provided dSYMs to Flurry"
end
create_upload(size, project_id, auth_token) click to toggle source
# File lib/fastlane/plugin/flurry/actions/flurry_upload_dsym.rb, line 110
def self.create_upload(size, project_id, auth_token)
  payload = "{\"data\": {\"type\": \"upload\", \"attributes\": {\"uploadType\": \"IOS\", \"contentLength\": #{size}}, \"relationships\": {\"project\": {\"data\": {\"id\": #{project_id},\"type\": \"project\"}}}}}"
  response = RestClient.post "#{METADATA_BASE_URL}/project/#{project_id}/uploads", payload, get_metadata_headers(auth_token)
  if response.code != 201
    UI.user_error! "Failed to create Upload with Status Code: #{response.code}"
  end
  jsonResponse = JSON.parse(response.body)
  return jsonResponse["data"]["id"]
end
description() click to toggle source

@!group Documentation

# File lib/fastlane/plugin/flurry/actions/flurry_upload_dsym.rb, line 161
def self.description
  "Upload dSYM symbolication files to Flurry"
end
details() click to toggle source
# File lib/fastlane/plugin/flurry/actions/flurry_upload_dsym.rb, line 165
def self.details
  [
      "This action allows you to upload symbolication files to Flurry.",
      "It's extra useful if you use it to download the latest dSYM files from Apple when you",
      "use Bitcode"
  ].join(" ")
end
example_code() click to toggle source
# File lib/fastlane/plugin/flurry/actions/flurry_upload_dsym.rb, line 218
def self.example_code
  [
      'flurry_upload_dsym(
      api_key: "...",
      auth_token: "...",
      dsym_path: "./App.dSYM.zip"
    )'
  ]
end
find_project(api_key, auth_token) click to toggle source
# File lib/fastlane/plugin/flurry/actions/flurry_upload_dsym.rb, line 59
def self.find_project(api_key, auth_token)
  begin
    response = RestClient.get "#{METADATA_BASE_URL}/project?fields[project]=apiKey&filter[project.apiKey]=#{api_key}", get_metadata_headers(auth_token)
  rescue => e
    UI.user_error! "Invalid/Expired Auth Token Provided. Please obtain a new token and try again."
  end

  json_response_data = JSON.parse(response.body)["data"]
  if json_response_data.count == 0
    UI.user_error! "No project found for the provided API Key. Make sure the provided API key is valid and the user has access to that project."
  end
  return json_response_data[0]["id"]
end
get_metadata_headers(auth_token) click to toggle source
# File lib/fastlane/plugin/flurry/actions/flurry_upload_dsym.rb, line 148
def self.get_metadata_headers(auth_token)
  return {:Authorization => "Bearer #{auth_token}", :accept => 'application/vnd.api+json', :content_type => 'application/vnd.api+json'}
end
get_upload_headers(size, auth_token) click to toggle source
# File lib/fastlane/plugin/flurry/actions/flurry_upload_dsym.rb, line 152
def self.get_upload_headers(size, auth_token)
  range_header = 'bytes 0-' + (size - 1).to_s
  return {:content_type => 'application/octet-stream', :Range => range_header, :Authorization => "Bearer #{auth_token}"}
end
gzip_file(tar_file) click to toggle source
# File lib/fastlane/plugin/flurry/actions/flurry_upload_dsym.rb, line 102
def self.gzip_file(tar_file)
  gz = StringIO.new("")
  z = Zlib::GzipWriter.new(gz)
  z.write tar_file.string
  z.close
  StringIO.new gz.string
end
is_supported?(platform) click to toggle source
# File lib/fastlane/plugin/flurry/actions/flurry_upload_dsym.rb, line 214
def self.is_supported?(platform)
  platform == :ios
end
run(params) click to toggle source
# File lib/fastlane/plugin/flurry/actions/flurry_upload_dsym.rb, line 12
def self.run(params)
  Actions.verify_gem!('rest-client')
  require 'rest-client'
  require 'rubygems/package'

  # Params - API
  api_key = params[:api_key]
  auth_token = params[:auth_token]
  timeout_in_s = params[:timeout_in_s]
  project_id = find_project(api_key, auth_token)

  # Params - dSYM
  dsym_paths = []
  dsym_paths += [params[:dsym_path]] if params[:dsym_path]
  dsym_paths += params[:dsym_paths] if params[:dsym_paths]

  if dsym_paths.count == 0
    UI.user_error! "Couldn't find any DSYMs. Please pass them using the dsym_path option)"
  end

  dsym_paths.compact.map do | single_dsym_path |
    if single_dsym_path.end_with?('.zip')
      UI.message("Extracting '#{single_dsym_path}'...")
      single_dsym_path = unzip_file(single_dsym_path)
    end

    tar_zip_file = tar_zip_file(single_dsym_path)
    upload_id = create_upload(tar_zip_file.size, project_id, auth_token)
    send_to_upload_service(tar_zip_file.path, project_id, upload_id, auth_token)
    check_upload_status(project_id, upload_id, auth_token, timeout_in_s)
  end

  UI.message "Successfully Uploaded the provided dSYMs to Flurry."
end
send_to_upload_service(file_path, project_id, upload_id, auth_token) click to toggle source
# File lib/fastlane/plugin/flurry/actions/flurry_upload_dsym.rb, line 120
def self.send_to_upload_service(file_path, project_id, upload_id, auth_token)
  file = File.new(file_path, 'rb')
  file_size = file.size.to_i
  UI.message "Uploading..."
  response = RestClient.post "#{UPLOAD_BASE_URL}/upload/#{project_id}/#{upload_id}", file, get_upload_headers(file_size, auth_token)
  if response.code != 201 && response.code != 202
    UI.user_error! "Failed to send files to upload service with Status Code: #{response.code}"
  end
end
tar_file(dsym_path) click to toggle source
# File lib/fastlane/plugin/flurry/actions/flurry_upload_dsym.rb, line 82
def self.tar_file(dsym_path)
  tarfile = StringIO.new("")
  Gem::Package::TarWriter.new(tarfile) do |tar|
    Dir[File.join(dsym_path, "**/*")].each do |file|
      mode = File.stat(file).mode
      relative_file = file.sub /^#{Regexp::escape dsym_path}\/?/, ''

      if File.directory?(file)
        tar.mkdir relative_file, mode
      else
        tar.add_file relative_file, mode do |tf|
          File.open(file, "rb") { |f| tf.write f.read }
        end
      end
    end
  end
  tarfile.rewind
  return tarfile
end
tar_zip_file(dsym_path) click to toggle source
# File lib/fastlane/plugin/flurry/actions/flurry_upload_dsym.rb, line 73
def self.tar_zip_file(dsym_path)
  tar_zip_file = Tempfile.new(['temp','.tar.gz'])
  io = gzip_file(tar_file(dsym_path))
  tar_zip_file.binmode
  tar_zip_file.write io.read
  tar_zip_file.close
  return tar_zip_file
end
unzip_file(file) click to toggle source
# File lib/fastlane/plugin/flurry/actions/flurry_upload_dsym.rb, line 47
def self.unzip_file (file)
  dir = Dir.mktmpdir
  Zip::File.open(file) do |zip_file|
    zip_file.each do |f|
      f_path=File.join(dir, f.name)
      FileUtils.mkdir_p(File.dirname(f_path))
      zip_file.extract(f, f_path) unless File.exist?(f_path)
    end
  end
  dir
end