Skip to content
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
140 changes: 140 additions & 0 deletions lib/commands/upload/build.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
require 'dry/cli'
require 'json'
require 'uri'
require 'async'
require 'async/barrier'
require 'async/semaphore'
require 'async/http/internet/instance'

module EmergeCLI
module Commands
module Upload
class Build < EmergeCLI::Commands::GlobalOptions
desc 'Upload a build to Emerge'

option :path, type: :string, required: true, desc: 'Path to the build artifact'

# Optional options
option :api_token, type: :string, required: false,
desc: 'API token for authentication, defaults to ENV[EMERGE_API_TOKEN]'
option :sha, type: :string, required: false, desc: 'SHA of the commit'
option :branch, type: :string, required: false, desc: 'Branch name'
option :repo_name, type: :string, required: false, desc: 'Repository name'
option :base_sha, type: :string, required: false, desc: 'Base SHA'
option :previous_sha, type: :string, required: false, desc: 'Previous SHA'
option :pr_number, type: :string, required: false, desc: 'PR number'

def initialize(network: nil, git_info_provider: nil)
@network = network
@git_info_provider = git_info_provider
end

def call(**options)
@options = options
@profiler = EmergeCLI::Profiler.new(enabled: options[:profile])
before(options)

start_time = Time.now

file_path = options[:path]
file_exists = File.exist?(file_path)
raise "File not found at path: #{file_path}" unless file_exists

file_extension = File.extname(file_path)
raise "Unsupported file type: #{file_extension}" unless ['.ipa', '.apk', '.aab',
'.zip'].include?(file_extension)

api_token = @options[:api_token] || ENV.fetch('EMERGE_API_TOKEN', nil)
raise 'API token is required and cannot be blank' if api_token.nil? || api_token.strip.empty?

@network ||= EmergeCLI::Network.new(api_token:)
@git_info_provider ||= GitInfoProvider.new

Sync do
upload_url, upload_id = fetch_upload_url

file_size = File.size(file_path)
Logger.info("Uploading file... (#{file_size} bytes)")

File.open(file_path, 'rb') do |file|
headers = {
'Content-Type' => 'application/zip',
'Content-Length' => file_size.to_s
}

response = @network.put(
path: upload_url,
body: file.read,
headers: headers
)

unless response.status == 200
Logger.error("Upload failed with status #{response.status}")
Logger.error("Response body: #{response.body}")
raise "Uploading file failed with status #{response.status}"
end
end

Logger.info('Upload complete successfully!')
Logger.info "Time taken: #{(Time.now - start_time).round(2)} seconds"
Logger.info("✅ You can view the build analysis at https://emergetools.com/build/#{upload_id}")
end
end

private

def fetch_upload_url
git_result = @git_info_provider.fetch_git_info
sha = @options[:sha] || git_result.sha
branch = @options[:branch] || git_result.branch
base_sha = @options[:base_sha] || git_result.base_sha
previous_sha = @options[:previous_sha] || git_result.previous_sha
pr_number = @options[:pr_number] || git_result.pr_number

# TODO: Make optional
raise 'SHA is required' unless sha
raise 'Branch is required' unless branch

payload = {
sha:,
branch:,
repo_name: @options[:repo_name],
# Optional
base_sha:,
previous_sha:,
pr_number: pr_number&.to_s
}.compact

upload_response = @network.post(
path: '/upload',
body: payload,
headers: { 'Content-Type' => 'application/json' }
)
upload_json = parse_response(upload_response)
upload_id = upload_json.fetch('upload_id')
upload_url = upload_json.fetch('uploadURL')
Logger.debug("Got upload ID: #{upload_id}")

warning = upload_json['warning']
Logger.warn(warning) if warning

[upload_url, upload_id]
end

def parse_response(response)
case response.status
when 200
JSON.parse(response.read)
when 400
error_message = JSON.parse(response.read)['errorMessage']
raise "Invalid parameters: #{error_message}"
when 401, 403
raise 'Invalid API token'
else
raise "Creating upload failed with status #{response.status}"
end
end
end
end
end
end
3 changes: 3 additions & 0 deletions lib/emerge_cli.rb
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
require_relative 'commands/order_files/download_order_files'
require_relative 'commands/order_files/validate_linkmaps'
require_relative 'commands/order_files/validate_xcode_project'
require_relative 'commands/upload/build'

require_relative 'reaper/ast_parser'
require_relative 'reaper/code_deleter'
Expand All @@ -30,11 +31,13 @@
require_relative 'utils/version_check'

require 'dry/cli'
require 'pry-byebug'

module EmergeCLI
extend Dry::CLI::Registry

register 'upload', aliases: ['u'] do |prefix|
prefix.register 'build', Commands::Upload::Build
prefix.register 'snapshots', Commands::Upload::Snapshots
end

Expand Down
8 changes: 8 additions & 0 deletions lib/utils/git.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
module EmergeCLI
module Git
def self.branch
Logger.debug 'Getting current branch name'
command = 'git rev-parse --abbrev-ref HEAD'
Logger.debug command
stdout, _, status = Open3.capture3(command)
Expand Down Expand Up @@ -39,13 +40,15 @@ def self.branch
end

def self.sha
Logger.debug 'Getting current SHA'
command = 'git rev-parse HEAD'
Logger.debug command
stdout, _, status = Open3.capture3(command)
stdout.strip if status.success?
end

def self.base_sha
Logger.debug 'Getting base SHA'
current_branch = branch
remote_head = remote_head_branch
return nil if current_branch.nil? || remote_head.nil?
Expand All @@ -59,6 +62,7 @@ def self.base_sha
end

def self.previous_sha
Logger.debug 'Getting previous SHA'
command = 'git rev-list --count HEAD'
Logger.debug command
count_stdout, _, count_status = Open3.capture3(command)
Expand All @@ -78,12 +82,14 @@ def self.previous_sha
end

def self.primary_remote
Logger.debug 'Getting primary remote'
remote = remote()
return nil if remote.nil?
remote.include?('origin') ? 'origin' : remote.first
end

def self.remote_head_branch(remote = primary_remote)
Logger.debug 'Getting remote head branch'
return nil if remote.nil?
command = "git remote show #{remote}"
Logger.debug command
Expand All @@ -98,6 +104,7 @@ def self.remote_head_branch(remote = primary_remote)
end

def self.remote_url(remote = primary_remote)
Logger.debug 'Getting remote URL'
return nil if remote.nil?
command = "git config --get remote.#{remote}.url"
Logger.debug command
Expand All @@ -106,6 +113,7 @@ def self.remote_url(remote = primary_remote)
end

def self.remote
Logger.debug 'Getting remote'
command = 'git remote'
Logger.debug command
stdout, _, status = Open3.capture3(command)
Expand Down
Loading