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

Add action to generate snapshot builds #19

Merged
merged 6 commits into from
Mar 19, 2024
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.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
81 changes: 12 additions & 69 deletions lib/fastlane/plugin/emerge/actions/emerge_action.rb
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ def self.run(params)
FileUtils.cp(l, linkmap_folder)
end
end
copy_config(config_path, "#{d}/archive.xcarchive")
Helper::EmergeHelper.copy_config(config_path, "#{d}/archive.xcarchive")
FileUtils.cp_r(file_path, application_folder)
copy_dsyms("#{absolute_path.dirname}/*.dsym", dsym_folder)
copy_dsyms("#{absolute_path.dirname}/*/*.dsym", dsym_folder)
Expand All @@ -73,7 +73,7 @@ def self.run(params)
FileUtils.cp(l, linkmap_folder)
end
end
copy_config(config_path, file_path)
Helper::EmergeHelper.copy_config(config_path, file_path)
Actions::ZipAction.run(
path: file_path,
output_path: zip_path,
Expand All @@ -88,62 +88,18 @@ def self.run(params)
return
end

filename = File.basename(file_path)
url = 'https://api.emergetools.com/upload'
params = {
filename: filename
prNumber: pr_number,
branch: branch,
sha: sha,
baseSha: base_sha,
repoName: repo_name,
gitlabProjectId: gitlab_project_id,
orderFileVersion: order_file_version,
tag: tag || "default"
}
if pr_number
params[:prNumber] = pr_number
end
if branch
params[:branch] = branch
end
if sha
params[:sha] = sha
end
if base_sha
params[:baseSha] = base_sha
end
if repo_name
params[:repoName] = repo_name
end
if gitlab_project_id
params[:gitlabProjectId] = gitlab_project_id
end
if order_file_version
params[:orderFileVersion] = order_file_version
end
params[:tag] = tag || "default"
FastlaneCore::PrintTable.print_values(
config: params,
hide_keys: [],
title: "Summary for Emerge #{Fastlane::Emerge::VERSION}"
)
resp = Faraday.post(
url,
params.to_json,
'Content-Type' => 'application/json', 'X-API-Token' => api_token, 'User-Agent' => "fastlane-plugin-emerge/#{Fastlane::Emerge::VERSION}"
)
case resp.status
when 200
json = JSON.parse(resp.body)
upload_id = json["upload_id"]
upload_url = json["uploadURL"]
warning = json["warning"]
if warning
Copy link
Member

Choose a reason for hiding this comment

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

I'm not seeing this in the new response handling code, where did it go?

UI.important(warning)
end
return Helper::EmergeHelper.perform_upload(upload_url, upload_id, file_path)
when 403
UI.error("Invalid API token")
when 400
UI.error("Invalid parameters")
json = JSON.parse(resp.body)
UI.error("Error: #{json['errorMessage']}")
else
UI.error("Upload failed")
end
upload_id = Helper::EmergeHelper.perform_upload(api_token, params, file_path)
UI.success("🎉 Your app is processing, you can find the results at https://emergetools.com/build/#{upload_id}")
end

def self.copy_dsyms(from, to)
Expand All @@ -153,19 +109,6 @@ def self.copy_dsyms(from, to)
end
end

def self.copy_config(config_path, tmp_dir)
return if config_path.nil?

expanded_path = File.expand_path(config_path)
unless File.exist?(expanded_path)
UI.error("No config file found at path '#{expanded_path}'.\nUploading without config file")
return
end

emerge_config_path = "#{tmp_dir}/emerge_config.yaml"
FileUtils.cp(expanded_path, emerge_config_path)
end

def self.description
"Fastlane plugin for Emerge"
end
Expand Down
155 changes: 155 additions & 0 deletions lib/fastlane/plugin/emerge/actions/emerge_snapshot_action.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,155 @@
require 'fastlane/action'
require 'fastlane_core/print_table'
require_relative '../helper/emerge_helper'
require_relative '../helper/git'
require_relative '../helper/github'
require 'pathname'
require 'tmpdir'
require 'json'
require 'fileutils'

module Fastlane
module Actions
class EmergeSnapshotAction < Action
def self.run(params)
api_token = params[:api_token]

git_params = Helper::EmergeHelper.make_git_params
pr_number = params[:pr_number] || git_params.pr_number
branch = params[:branch] || git_params.branch
sha = params[:sha] || git_params.sha
base_sha = params[:base_sha] || git_params.base_sha
repo_name = params[:repo_name] || git_params.repo_name
gitlab_project_id = params[:gitlab_project_id]
tag = params[:tag]
config_path = params[:config_path]
scheme = params[:scheme]
configuration = params[:configuration]
team_id = params[:team_id] || CredentialsManager::AppfileConfig.try_fetch_value(:team_id)

Dir.mktmpdir do |temp_dir|
archive_name = "#{scheme}-Emerge-Snapshots"
archive_path = "#{temp_dir}/build/#{archive_name}.xcarchive"
make_debug_build(
scheme: scheme,
configuration: configuration,
team_id: team_id,
archive_path: archive_path
)
Helper::EmergeHelper.copy_config(config_path, archive_path)
Xcodeproj::Plist.write_to_path({ "NAME" => "Emerge Upload" }, "#{archive_path}/Info.plist")

zip_file_path = "#{temp_dir}/build/#{archive_name}.xcarchive.zip"
ZipAction.run(
path: archive_path,
output_path: zip_file_path,
exclude: [],
include: []
)

params = {
appIdSuffix: 'snapshots',
prNumber: pr_number,
branch: branch,
sha: sha,
baseSha: base_sha,
repoName: repo_name,
gitlabProjectId: gitlab_project_id,
tag: tag || "default"
}
upload_id = Helper::EmergeHelper.perform_upload(api_token, params, zip_file_path)
UI.success("🎉 Your app is processing, you can find the results at https://emergetools.com/snapshot/#{upload_id}")
end
end

def self.make_debug_build(scheme:, configuration:, team_id:, archive_path:)
other_action.gym(
scheme: scheme,
configuration: configuration,
skip_codesigning: true,
clean: true,
export_method: "development",
export_team_id: team_id,
skip_package_ipa: true,
archive_path: archive_path
)
end

def self.description
"Fastlane plugin for Emerge to generate iOS snapshots"
end

def self.authors
["Emerge Tools"]
end

def self.return_value
"If successful, returns the upload id of the generated snapshot build"
end

def self.details
""
end

def self.available_options
[
FastlaneCore::ConfigItem.new(key: :api_token,
env_name: "EMERGE_API_TOKEN",
description: "An API token for Emerge",
optional: false,
type: String),
FastlaneCore::ConfigItem.new(key: :scheme,
description: "The scheme of your app to build",
optional: false,
type: String),
FastlaneCore::ConfigItem.new(key: :configuration,
description: "The configuration of your app to use",
optional: false,
default_value: "Debug",
type: String),
FastlaneCore::ConfigItem.new(key: :team_id,
env_name: "EXPORT_TEAM_ID",
description: "The Apple Team ID to use for exporting the archive. If not provided, we will try to use the team_id from the Appfile",
optional: true,
type: String),
FastlaneCore::ConfigItem.new(key: :config_path,
description: "Path to Emerge YAML config path",
optional: true,
type: String),
FastlaneCore::ConfigItem.new(key: :pr_number,
description: "The PR number that triggered this upload",
optional: true,
type: String),
FastlaneCore::ConfigItem.new(key: :branch,
description: "The current git branch",
optional: true,
type: String),
FastlaneCore::ConfigItem.new(key: :sha,
description: "The git SHA that triggered this build",
optional: true,
type: String),
FastlaneCore::ConfigItem.new(key: :base_sha,
description: "The git SHA of the base build",
optional: true,
type: String),
FastlaneCore::ConfigItem.new(key: :repo_name,
description: "Full name of the respository this upload was triggered from. For example: EmergeTools/Emerge",
optional: true,
type: String),
FastlaneCore::ConfigItem.new(key: :gitlab_project_id,
description: "Id of the gitlab project this upload was triggered from",
optional: true,
type: Integer),
FastlaneCore::ConfigItem.new(key: :tag,
description: "String to label the build. Useful for grouping builds together in our dashboard, like development, default, or pull-request",
optional: true,
type: String)
]
end

def self.is_supported?(platform)
platform == :ios
end
end
end
end
103 changes: 88 additions & 15 deletions lib/fastlane/plugin/emerge/helper/emerge_helper.rb
Original file line number Diff line number Diff line change
Expand Up @@ -18,21 +18,16 @@ def initialize(sha:, base_sha:, branch:, pr_number: nil, repo_name: nil)

module Helper
class EmergeHelper
def self.perform_upload(upload_url, upload_id, file_path)
UI.message("Starting upload")
response = Faraday.put(upload_url) do |req|
req.headers['Content-Type'] = 'application/zip'
req.headers['Content-Length'] = File.size(file_path).to_s
req.body = Faraday::UploadIO.new(file_path, 'application/zip')
end
case response.status
when 200
UI.success("🎉 Your app is processing, you can find the results at https://emergetools.com/build/#{upload_id}")
return upload_id
else
UI.error("Upload failed")
end
return nil
API_URL = 'https://api.emergetools.com/upload'.freeze

def self.perform_upload(api_token, params, file_path)
cleaned_params = clean_params(params)
print_summary(cleaned_params)

upload_response = create_upload(api_token, cleaned_params)
handle_upload_response(api_token, upload_response, file_path)
rescue StandardError => e
UI.user_error!(e.message)
end

def self.make_git_params
Expand All @@ -56,6 +51,84 @@ def self.make_git_params
UI.message("Got git result #{git_result.inspect}")
git_result
end

def self.copy_config(config_path, tmp_dir)
return if config_path.nil?

expanded_path = File.expand_path(config_path)
unless File.exist?(expanded_path)
UI.error("No config file found at path '#{expanded_path}'.\nUploading without config file")
return
end

emerge_config_path = "#{tmp_dir}/emerge_config.yaml"
FileUtils.cp(expanded_path, emerge_config_path)
end

private_class_method

def self.clean_params(params)
params.reject { |_, v| v.nil? }
end

def self.print_summary(params)
FastlaneCore::PrintTable.print_values(
config: params,
hide_keys: [],
title: "Summary for Emerge Upload #{Fastlane::Emerge::VERSION}"
)
end

def self.create_upload(api_token, params)
response = Faraday.post(API_URL, params.to_json, headers(api_token, params, 'application/json'))
parse_response(response)
end

def self.headers(api_token, params, content_type)
{
'Content-Type' => content_type,
'X-API-Token' => api_token,
'User-Agent' => "fastlane-plugin-emerge/#{Fastlane::Emerge::VERSION}"
}
end

def self.parse_response(response)
case response.status
when 200
JSON.parse(response.body)
when 400
error_message = JSON.parse(response.body)['errorMessage']
raise "Invalid parameters: #{error_message}"
when 401, 403
raise 'Invalid API token'
else
raise "Creating upload failed with status #{response.status}"
end
end

def self.handle_upload_response(api_token, response, file_path)
upload_url = response.fetch('uploadURL')
upload_id = response.fetch('upload_id')

warning = response.dig('warning')
if warning
UI.important(warning)
end

UI.message('Starting zip file upload')
upload_file(api_token, upload_url, file_path)
upload_id
end

def self.upload_file(api_token, upload_url, file_path)
response = Faraday.put(upload_url) do |req|
req.headers = headers(api_token, nil, 'application/zip')
req.headers['Content-Length'] = File.size(file_path).to_s
req.body = Faraday::UploadIO.new(file_path, 'application/zip')
end

raise "Uploading zip file failed #{response.status}" unless response.status == 200
end
end
end
end
2 changes: 1 addition & 1 deletion lib/fastlane/plugin/emerge/version.rb
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
module Fastlane
module Emerge
VERSION = "0.8.0"
VERSION = "0.9.0"
end
end