Skip to content

Commit 35da8d4

Browse files
authored
Add command to upload build (#41)
1 parent e0e70f6 commit 35da8d4

File tree

3 files changed

+151
-0
lines changed

3 files changed

+151
-0
lines changed

lib/commands/upload/build.rb

Lines changed: 140 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,140 @@
1+
require 'dry/cli'
2+
require 'json'
3+
require 'uri'
4+
require 'async'
5+
require 'async/barrier'
6+
require 'async/semaphore'
7+
require 'async/http/internet/instance'
8+
9+
module EmergeCLI
10+
module Commands
11+
module Upload
12+
class Build < EmergeCLI::Commands::GlobalOptions
13+
desc 'Upload a build to Emerge'
14+
15+
option :path, type: :string, required: true, desc: 'Path to the build artifact'
16+
17+
# Optional options
18+
option :api_token, type: :string, required: false,
19+
desc: 'API token for authentication, defaults to ENV[EMERGE_API_TOKEN]'
20+
option :sha, type: :string, required: false, desc: 'SHA of the commit'
21+
option :branch, type: :string, required: false, desc: 'Branch name'
22+
option :repo_name, type: :string, required: false, desc: 'Repository name'
23+
option :base_sha, type: :string, required: false, desc: 'Base SHA'
24+
option :previous_sha, type: :string, required: false, desc: 'Previous SHA'
25+
option :pr_number, type: :string, required: false, desc: 'PR number'
26+
27+
def initialize(network: nil, git_info_provider: nil)
28+
@network = network
29+
@git_info_provider = git_info_provider
30+
end
31+
32+
def call(**options)
33+
@options = options
34+
@profiler = EmergeCLI::Profiler.new(enabled: options[:profile])
35+
before(options)
36+
37+
start_time = Time.now
38+
39+
file_path = options[:path]
40+
file_exists = File.exist?(file_path)
41+
raise "File not found at path: #{file_path}" unless file_exists
42+
43+
file_extension = File.extname(file_path)
44+
raise "Unsupported file type: #{file_extension}" unless ['.ipa', '.apk', '.aab',
45+
'.zip'].include?(file_extension)
46+
47+
api_token = @options[:api_token] || ENV.fetch('EMERGE_API_TOKEN', nil)
48+
raise 'API token is required and cannot be blank' if api_token.nil? || api_token.strip.empty?
49+
50+
@network ||= EmergeCLI::Network.new(api_token:)
51+
@git_info_provider ||= GitInfoProvider.new
52+
53+
Sync do
54+
upload_url, upload_id = fetch_upload_url
55+
56+
file_size = File.size(file_path)
57+
Logger.info("Uploading file... (#{file_size} bytes)")
58+
59+
File.open(file_path, 'rb') do |file|
60+
headers = {
61+
'Content-Type' => 'application/zip',
62+
'Content-Length' => file_size.to_s
63+
}
64+
65+
response = @network.put(
66+
path: upload_url,
67+
body: file.read,
68+
headers: headers
69+
)
70+
71+
unless response.status == 200
72+
Logger.error("Upload failed with status #{response.status}")
73+
Logger.error("Response body: #{response.body}")
74+
raise "Uploading file failed with status #{response.status}"
75+
end
76+
end
77+
78+
Logger.info('Upload complete successfully!')
79+
Logger.info "Time taken: #{(Time.now - start_time).round(2)} seconds"
80+
Logger.info("✅ You can view the build analysis at https://emergetools.com/build/#{upload_id}")
81+
end
82+
end
83+
84+
private
85+
86+
def fetch_upload_url
87+
git_result = @git_info_provider.fetch_git_info
88+
sha = @options[:sha] || git_result.sha
89+
branch = @options[:branch] || git_result.branch
90+
base_sha = @options[:base_sha] || git_result.base_sha
91+
previous_sha = @options[:previous_sha] || git_result.previous_sha
92+
pr_number = @options[:pr_number] || git_result.pr_number
93+
94+
# TODO: Make optional
95+
raise 'SHA is required' unless sha
96+
raise 'Branch is required' unless branch
97+
98+
payload = {
99+
sha:,
100+
branch:,
101+
repo_name: @options[:repo_name],
102+
# Optional
103+
base_sha:,
104+
previous_sha:,
105+
pr_number: pr_number&.to_s
106+
}.compact
107+
108+
upload_response = @network.post(
109+
path: '/upload',
110+
body: payload,
111+
headers: { 'Content-Type' => 'application/json' }
112+
)
113+
upload_json = parse_response(upload_response)
114+
upload_id = upload_json.fetch('upload_id')
115+
upload_url = upload_json.fetch('uploadURL')
116+
Logger.debug("Got upload ID: #{upload_id}")
117+
118+
warning = upload_json['warning']
119+
Logger.warn(warning) if warning
120+
121+
[upload_url, upload_id]
122+
end
123+
124+
def parse_response(response)
125+
case response.status
126+
when 200
127+
JSON.parse(response.read)
128+
when 400
129+
error_message = JSON.parse(response.read)['errorMessage']
130+
raise "Invalid parameters: #{error_message}"
131+
when 401, 403
132+
raise 'Invalid API token'
133+
else
134+
raise "Creating upload failed with status #{response.status}"
135+
end
136+
end
137+
end
138+
end
139+
end
140+
end

lib/emerge_cli.rb

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
require_relative 'commands/order_files/download_order_files'
1515
require_relative 'commands/order_files/validate_linkmaps'
1616
require_relative 'commands/order_files/validate_xcode_project'
17+
require_relative 'commands/upload/build'
1718

1819
require_relative 'reaper/ast_parser'
1920
require_relative 'reaper/code_deleter'
@@ -30,11 +31,13 @@
3031
require_relative 'utils/version_check'
3132

3233
require 'dry/cli'
34+
require 'pry-byebug'
3335

3436
module EmergeCLI
3537
extend Dry::CLI::Registry
3638

3739
register 'upload', aliases: ['u'] do |prefix|
40+
prefix.register 'build', Commands::Upload::Build
3841
prefix.register 'snapshots', Commands::Upload::Snapshots
3942
end
4043

lib/utils/git.rb

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
module EmergeCLI
44
module Git
55
def self.branch
6+
Logger.debug 'Getting current branch name'
67
command = 'git rev-parse --abbrev-ref HEAD'
78
Logger.debug command
89
stdout, _, status = Open3.capture3(command)
@@ -39,13 +40,15 @@ def self.branch
3940
end
4041

4142
def self.sha
43+
Logger.debug 'Getting current SHA'
4244
command = 'git rev-parse HEAD'
4345
Logger.debug command
4446
stdout, _, status = Open3.capture3(command)
4547
stdout.strip if status.success?
4648
end
4749

4850
def self.base_sha
51+
Logger.debug 'Getting base SHA'
4952
current_branch = branch
5053
remote_head = remote_head_branch
5154
return nil if current_branch.nil? || remote_head.nil?
@@ -59,6 +62,7 @@ def self.base_sha
5962
end
6063

6164
def self.previous_sha
65+
Logger.debug 'Getting previous SHA'
6266
command = 'git rev-list --count HEAD'
6367
Logger.debug command
6468
count_stdout, _, count_status = Open3.capture3(command)
@@ -78,12 +82,14 @@ def self.previous_sha
7882
end
7983

8084
def self.primary_remote
85+
Logger.debug 'Getting primary remote'
8186
remote = remote()
8287
return nil if remote.nil?
8388
remote.include?('origin') ? 'origin' : remote.first
8489
end
8590

8691
def self.remote_head_branch(remote = primary_remote)
92+
Logger.debug 'Getting remote head branch'
8793
return nil if remote.nil?
8894
command = "git remote show #{remote}"
8995
Logger.debug command
@@ -98,6 +104,7 @@ def self.remote_head_branch(remote = primary_remote)
98104
end
99105

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

108115
def self.remote
116+
Logger.debug 'Getting remote'
109117
command = 'git remote'
110118
Logger.debug command
111119
stdout, _, status = Open3.capture3(command)

0 commit comments

Comments
 (0)