Skip to content

Commit 453e786

Browse files
committed
[GCSI-567] feat: handle android build app to track build time and build path and + specs
1 parent 45dea53 commit 453e786

File tree

4 files changed

+289
-57
lines changed

4 files changed

+289
-57
lines changed

lib/fastlane/plugin/instabug_stores_upload/actions/instabug_build_android_app_action.rb

Lines changed: 41 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -6,47 +6,67 @@ module Actions
66
class InstabugBuildAndroidAppAction < Action
77
def self.run(params)
88
UI.message("Starting Instabug Android build...")
9-
9+
1010
# Extract Instabug-specific parameters
1111
branch_name = params.delete(:branch_name)
1212
instabug_api_key = params.delete(:instabug_api_key)
13-
13+
1414
# Validate required parameters
1515
if branch_name.nil? || branch_name.empty?
1616
UI.user_error!("branch_name is required for Instabug reporting")
1717
end
18-
18+
1919
begin
2020
# Report build start to Instabug
2121
Helper::InstabugStoresUploadHelper.report_status(
22-
branch_name: branch_name,
22+
branch_name:,
2323
api_key: instabug_api_key,
2424
status: "inprogress",
2525
step: "build_app"
2626
)
2727

28+
# Start timing the build
29+
build_start_time = Time.now
30+
2831
# Execute the actual Android build using gradle
2932
result = Actions::GradleAction.run(params)
3033

34+
# Calculate build time in seconds
35+
build_time = (Time.now - build_start_time).round
36+
37+
# Extract Android build path (APK or AAB)
38+
build_path = Helper::InstabugStoresUploadHelper.fetch_android_build_path(Actions.lane_context)
39+
40+
if build_path.nil? || build_path.empty?
41+
UI.user_error!("Could not find any generated APK or AAB. Please check your gradle settings.")
42+
else
43+
UI.success("Successfully found build artifact(s) at: #{build_path}")
44+
end
45+
3146
# Report build success to Instabug
3247
Helper::InstabugStoresUploadHelper.report_status(
33-
branch_name: branch_name,
48+
branch_name:,
3449
api_key: instabug_api_key,
3550
status: "success",
36-
step: "build_app"
51+
step: "build_app",
52+
extras: {
53+
build_time:,
54+
build_path:
55+
}
3756
)
3857

3958
UI.success("Android build completed successfully!")
4059
result
41-
rescue => e
60+
rescue StandardError => e
4261
UI.error("Android build failed: #{e.message}")
4362

4463
# Report build failure to Instabug
4564
Helper::InstabugStoresUploadHelper.report_status(
46-
branch_name: branch_name,
65+
branch_name:,
4766
api_key: instabug_api_key,
4867
status: "failure",
49-
step: "build_app"
68+
step: "build_app",
69+
error_message: e.message
5070
)
5171
raise e
5272
end
@@ -71,7 +91,7 @@ def self.details
7191
def self.available_options
7292
# Start with the original gradle options
7393
options = Actions::GradleAction.available_options
74-
94+
7595
# Add Instabug-specific options
7696
instabug_options = [
7797
FastlaneCore::ConfigItem.new(
@@ -88,9 +108,17 @@ def self.available_options
88108
optional: false,
89109
type: String,
90110
sensitive: true
91-
)
111+
),
112+
FastlaneCore::ConfigItem.new(
113+
key: :instabug_api_base_url,
114+
env_name: "INSTABUG_API_BASE_URL",
115+
description: "Instabug API base URL (defaults to https://api.instabug.com)",
116+
optional: true,
117+
type: String,
118+
skip_type_validation: true # Since we don't extract this param
119+
)
92120
]
93-
121+
94122
# Combine both sets of options
95123
options + instabug_options
96124
end
@@ -121,4 +149,4 @@ def self.category
121149
end
122150
end
123151
end
124-
end
152+
end

lib/fastlane/plugin/instabug_stores_upload/helper/instabug_stores_upload_helper.rb

Lines changed: 43 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -8,60 +8,82 @@ module Fastlane
88

99
module Helper
1010
class InstabugStoresUploadHelper
11-
# Base URL for Instabug API we will need to adjust it for STs
12-
INSTABUG_API_BASE_URL = "https://api.instabug.com".freeze
11+
# Default Base URL for Instabug API
12+
DEFAULT_INSTABUG_API_BASE_URL = "https://api.instabug.com".freeze
1313

1414
def self.show_message
1515
UI.message("Hello from the instabug_stores_upload plugin helper!")
1616
end
1717

18-
def self.report_status(branch_name:, api_key:, status:, step:)
18+
def self.report_status(branch_name:, api_key:, status:, step:, extras: {}, error_message: nil)
1919
return unless branch_name.start_with?('crash-fix/instabug-crash-')
20-
20+
2121
UI.message("📡 Reporting #{step} status to Instabug for #{branch_name}/#{status}")
22-
22+
2323
make_api_request(
24-
branch_name: branch_name,
25-
status: status,
26-
api_key: api_key,
27-
step: step
24+
branch_name:,
25+
status:,
26+
api_key:,
27+
step:,
28+
extras:,
29+
error_message:
2830
)
2931
end
3032

31-
private
33+
# This helper method provides a clean and prioritized way to get the Android build output.
34+
# It checks for the most common output types in a specific order.
35+
# This is used to get the build path for the Android build artifact.
36+
def self.fetch_android_build_path(lane_context)
37+
all_aab_paths = lane_context[Actions::SharedValues::GRADLE_ALL_AAB_OUTPUT_PATHS]
38+
return all_aab_paths if all_aab_paths && !all_aab_paths.empty?
39+
40+
aab_path = lane_context[Actions::SharedValues::GRADLE_AAB_OUTPUT_PATH]
41+
return aab_path if aab_path && !aab_path.empty?
42+
43+
all_apk_paths = lane_context[Actions::SharedValues::GRADLE_ALL_APK_OUTPUT_PATHS]
44+
return all_apk_paths if all_apk_paths && !all_apk_paths.empty?
45+
46+
apk_path = lane_context[Actions::SharedValues::GRADLE_APK_OUTPUT_PATH]
47+
return apk_path if apk_path && !apk_path.empty?
48+
49+
return nil
50+
end
3251

33-
def self.make_api_request(branch_name:, status:, api_key:, step:)
52+
def self.make_api_request(branch_name:, status:, api_key:, step:, extras: {}, error_message: nil)
3453
return unless api_key
3554

36-
uri = URI.parse("#{INSTABUG_API_BASE_URL}/api/web/public/agent_fastlane/status")
37-
55+
# Determine API base URL from env var or default
56+
base_url = ENV['INSTABUG_API_BASE_URL'] || DEFAULT_INSTABUG_API_BASE_URL
57+
uri = URI.parse("#{base_url}/api/web/public/agent_fastlane/status")
58+
3859
payload = {
39-
branch_name: branch_name,
40-
status: status,
41-
step: step
60+
branch_name:,
61+
status:,
62+
step:,
63+
extras:,
64+
error_message:
4265
}
43-
66+
4467
begin
4568
http = Net::HTTP.new(uri.host, uri.port)
4669
http.use_ssl = true
4770
http.read_timeout = 30
4871
http.open_timeout = 30
49-
72+
5073
request = Net::HTTP::Patch.new(uri.path)
5174
request['Content-Type'] = 'application/json'
5275
request['Authorization'] = "Bearer #{api_key}"
5376
request['User-Agent'] = "fastlane-plugin-instabug-stores-upload"
5477
request.body = payload.to_json
55-
78+
5679
response = http.request(request)
57-
80+
5881
case response.code.to_i
5982
when 200..299
6083
UI.success("✅ Successfully reported to Instabug")
6184
else
6285
UI.error("❌ Unknown error reporting to Instabug: #{response.code} #{response.message}")
6386
end
64-
6587
rescue Net::TimeoutError
6688
UI.error("❌ Timeout while reporting to Instabug")
6789
rescue Net::OpenTimeout

spec/instabug_build_android_app_action_spec.rb

Lines changed: 45 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,12 @@
2323

2424
describe '#run' do
2525
context 'when build succeeds' do
26-
it 'reports inprogress, calls build action, and reports success' do
26+
it 'reports inprogress, calls build action, and reports success with timing and path' do
27+
# Mock the lane context to return a build path
28+
allow(Fastlane::Actions).to receive(:lane_context).and_return({
29+
Fastlane::Actions::SharedValues::GRADLE_APK_OUTPUT_PATH => '/path/to/app.apk'
30+
})
31+
2732
expect(Fastlane::Actions::GradleAction).to receive(:run)
2833
.with(hash_including(task: 'assembleRelease', project_dir: 'android/'))
2934
.and_return('build_result')
@@ -36,7 +41,9 @@
3641
body: {
3742
branch_name: 'crash-fix/instabug-crash-456',
3843
status: 'inprogress',
39-
step: 'build_app'
44+
step: 'build_app',
45+
extras: {},
46+
error_message: nil
4047
}.to_json,
4148
headers: {
4249
'Content-Type' => 'application/json',
@@ -46,18 +53,26 @@
4653
).once
4754

4855
expect(WebMock).to have_requested(:patch, api_endpoint)
49-
.with(
50-
body: {
51-
branch_name: 'crash-fix/instabug-crash-456',
52-
status: 'success',
53-
step: 'build_app'
54-
}.to_json,
55-
headers: {
56-
'Content-Type' => 'application/json',
57-
'Authorization' => 'Bearer test-api-key',
58-
'User-Agent' => 'fastlane-plugin-instabug-stores-upload'
59-
}
60-
).once
56+
.with { |req|
57+
body = JSON.parse(req.body)
58+
body['status'] == 'success' &&
59+
body['branch_name'] == 'crash-fix/instabug-crash-456' &&
60+
body['step'] == 'build_app' &&
61+
body['extras']['build_path'] == '/path/to/app.apk' &&
62+
body['extras']['build_time'].kind_of?(Integer)
63+
}.once
64+
end
65+
66+
it 'fails when no build artifact is found' do
67+
# Mock empty lane context
68+
allow(Fastlane::Actions).to receive(:lane_context).and_return({})
69+
70+
expect(Fastlane::Actions::GradleAction).to receive(:run)
71+
.and_return('build_result')
72+
73+
expect do
74+
described_class.run(valid_params)
75+
end.to raise_error(FastlaneCore::Interface::FastlaneError, /Could not find any generated APK or AAB/)
6176
end
6277
end
6378

@@ -67,16 +82,18 @@
6782
expect(Fastlane::Actions::GradleAction).to receive(:run)
6883
.and_raise(error)
6984

70-
expect {
85+
expect do
7186
described_class.run(valid_params)
72-
}.to raise_error(StandardError, 'Build failed')
87+
end.to raise_error(StandardError, 'Build failed')
7388

7489
expect(WebMock).to have_requested(:patch, api_endpoint)
7590
.with(
7691
body: {
7792
branch_name: 'crash-fix/instabug-crash-456',
7893
status: 'failure',
79-
step: 'build_app'
94+
step: 'build_app',
95+
extras: {},
96+
error_message: 'Build failed'
8097
}.to_json
8198
)
8299
end
@@ -86,26 +103,31 @@
86103
it 'raises user error' do
87104
params = valid_params.merge(branch_name: nil)
88105

89-
expect {
106+
expect do
90107
described_class.run(params)
91-
}.to raise_error(FastlaneCore::Interface::FastlaneError, 'branch_name is required for Instabug reporting')
108+
end.to raise_error(FastlaneCore::Interface::FastlaneError, 'branch_name is required for Instabug reporting')
92109
end
93110
end
94111

95112
context 'when branch_name is empty' do
96113
it 'raises user error' do
97114
params = valid_params.merge(branch_name: '')
98115

99-
expect {
116+
expect do
100117
described_class.run(params)
101-
}.to raise_error(FastlaneCore::Interface::FastlaneError, 'branch_name is required for Instabug reporting')
118+
end.to raise_error(FastlaneCore::Interface::FastlaneError, 'branch_name is required for Instabug reporting')
102119
end
103120
end
104121

105122
context 'when branch name does not match instabug pattern' do
106123
it 'does not make API calls but still runs build' do
107124
params = valid_params.merge(branch_name: 'feature/new-feature')
108-
125+
126+
# Mock successful build with a valid build path to avoid validation error
127+
allow(Fastlane::Actions).to receive(:lane_context).and_return({
128+
Fastlane::Actions::SharedValues::GRADLE_APK_OUTPUT_PATH => '/path/to/app.apk'
129+
})
130+
109131
expect(Fastlane::Actions::GradleAction).to receive(:run)
110132
.and_return('build_result')
111133

@@ -132,4 +154,4 @@
132154
expect(described_class.category).to eq(:building)
133155
end
134156
end
135-
end
157+
end

0 commit comments

Comments
 (0)