Skip to content

Commit c7b1df4

Browse files
committed
update send build tests to work with the cli
1 parent 3a30a51 commit c7b1df4

File tree

3 files changed

+108
-148
lines changed

3 files changed

+108
-148
lines changed

tools/fastlane-plugin/lib/fastlane/plugin/bugsnag/actions/send_build_to_bugsnag.rb

Lines changed: 75 additions & 86 deletions
Original file line numberDiff line numberDiff line change
@@ -8,63 +8,91 @@ module Actions
88
class SendBuildToBugsnagAction < Action
99
def self.run(params)
1010
bugsnag_cli_path = BugsnagCli.get_bugsnag_cli_path(params)
11-
UI.verbose("Using bugsnag-cli from path: #{bugsnag_cli_path}")
12-
13-
payload = {}
11+
verbose = UI.verbose("Using bugsnag-cli from path: #{bugsnag_cli_path}")
1412

1513
# If a configuration file was found or was specified, load in the options:
14+
config_options = {}
1615
if params[:config_file]
1716
UI.message("Loading build information from #{params[:config_file]}")
1817
config_options = load_config_file_options(params[:config_file])
19-
20-
# for each of the config options, if it's not been overriden by any
21-
# input to the lane, write it to the payload:
22-
payload[:apiKey] = params[:api_key] || config_options[:apiKey]
23-
payload[:versionName] = params[:app_version] || config_options[:appVersion]
24-
payload[:versionCode] = params[:android_version_code] || config_options[:appVersionCode]
25-
payload[:bundleVersion] = params[:ios_bundle_version] || config_options[:appBundleVersion]
26-
payload[:releaseStage] = params[:release_stage] || config_options[:releaseStage] || "production"
27-
else
28-
# No configuration file was found or specified, use the input parameters:
29-
payload[:apiKey] = params[:api_key]
30-
payload[:versionName] = params[:app_version]
31-
payload[:versionCode] = params[:android_version_code]
32-
payload[:bundleVersion] = params[:ios_bundle_version]
33-
payload[:releaseStage] = params[:release_stage] || "production"
3418
end
3519

36-
# If builder, or source control information has been provided into
37-
# Fastlane, apply it to the payload here.
38-
payload[:builderName] = params[:builder] if params[:builder]
39-
payload[:revision] = params[:revision] if params[:revision]
40-
payload[:repository] = params[:repository] if params[:repository]
41-
payload[:provider] = params[:provider] if params[:provider]
42-
43-
payload[:autoAssignRelease] = params[:auto_assign_release] if params[:auto_assign_release]
44-
45-
# If provided apply metadata to payload.
46-
payload[:metadata] = params[:metadata]
47-
48-
payload[:retries] = params[:retries] if params[:retries]
49-
payload[:timeout] = params[:timeout] if params[:timeout]
50-
payload[:buildApiRootUrl] = params[:endpoint] if params[:endpoint]
51-
52-
payload.reject! {|k,v| v == nil || (v.is_a?(Hash) && v.empty?)}
53-
54-
if payload[:apiKey].nil? || !payload[:apiKey].is_a?(String)
20+
api_key = params[:api_key] || config_options[:apiKey] unless (params[:api_key].nil? && config_options[:apiKey].nil?)
21+
version_name = params[:app_version] || config_options[:appVersion] unless (params[:app_version].nil? && config_options[:appVersion].nil?)
22+
version_code = params[:android_version_code] || config_options[:appVersionCode] unless (params[:android_version_code].nil? && config_options[:appVersionCode].nil?)
23+
bundle_version = params[:ios_bundle_version] || config_options[:appBundleVersion] unless (params[:ios_bundle_version].nil? && config_options[:appBundleVersion].nil?)
24+
release_stage = params[:release_stage] || config_options[:releaseStage] || "production" unless (params[:release_stage].nil? && config_options[:releaseStage].nil?)
25+
builder = params[:builder] unless params[:builder].nil?
26+
revision = params[:revision] unless params[:revision].nil?
27+
repository = params[:repository] unless params[:repository].nil?
28+
provider = params[:provider] unless params[:provider].nil?
29+
auto_assign_release = params[:auto_assign_release] unless params[:auto_assign_release].nil?
30+
metadata = params[:metadata] unless params[:metadata].nil?
31+
retries = params[:retries] unless params[:retries].nil?
32+
timeout = params[:timeout] unless params[:timeout].nil?
33+
endpoint = params[:endpoint] unless params[:endpoint].nil?
34+
35+
36+
if api_key.nil? || !api_key.is_a?(String)
5537
UI.user_error! missing_api_key_message(params)
5638
end
57-
if payload[:versionName].nil?
39+
if version_name.nil?
5840
UI.user_error! missing_app_version_message(params)
5941
end
6042

61-
# If verbose flag is enabled (`--verbose`), display the payload debug info
62-
UI.verbose("Sending build to Bugsnag with payload:")
63-
payload.each do |param|
64-
UI.verbose(" #{param[0].to_s.rjust(18)}: #{param[1]}")
43+
args = create_build_args(
44+
api_key,
45+
version_name,
46+
version_code,
47+
bundle_version,
48+
release_stage,
49+
builder,
50+
revision,
51+
repository,
52+
provider,
53+
auto_assign_release,
54+
metadata,
55+
retries,
56+
timeout,
57+
endpoint,
58+
verbose
59+
)
60+
bugsnag_cli_command = "#{bugsnag_cli_path} create-build #{args.join(' ')}"
61+
UI.verbose("Running command: #{bugsnag_cli_command}")
62+
success = Kernel.system(bugsnag_cli_command)
63+
if success
64+
UI.success("Build successfully sent to Bugsnag")
65+
else
66+
UI.user_error!("Failed to send build to Bugsnag.")
6567
end
68+
end
6669

67-
send_notification(bugsnag_cli_path, ::JSON.dump(payload))
70+
def self.create_build_args(api_key, version_name, version_code, bundle_version, release_stage, builder, revision, repository, provider, auto_assign_release, metadata, retries, timeout, endpoint, verbose)
71+
args = []
72+
args += ["--api-key", api_key] unless api_key.nil?
73+
args += ["--version-name", version_name] unless version_name.nil?
74+
args += ["--version-code", version_code] unless version_code.nil?
75+
args += ["--bundle-version", bundle_version] unless bundle_version.nil?
76+
args += ["--release-stage", release_stage] unless release_stage.nil?
77+
args += ["--builder-name", builder] unless builder.nil?
78+
args += ["--revision", revision] unless revision.nil?
79+
args += ["--repository", repository] unless repository.nil?
80+
args += ["--provider", provider] unless provider.nil?
81+
args += ["--auto-assign-release"] if auto_assign_release
82+
unless metadata.nil?
83+
if metadata.is_a?(String)
84+
#
85+
args += ["--metadata", metadata]
86+
elsif metadata.is_a?(Hash)
87+
formatted_metadata = metadata.map { |k, v| %Q{"#{k}"="#{v}"} }.join(",")
88+
args += ["--metadata", formatted_metadata]
89+
end
90+
end
91+
args += ["--retries", retries] unless retries.nil?
92+
args += ["--timeout", timeout] unless timeout.nil?
93+
args += ["--build-api-root-url", endpoint] unless endpoint.nil?
94+
args += ["--verbose"] if verbose
95+
args
6896
end
6997

7098
def self.missing_api_key_message(params)
@@ -182,8 +210,8 @@ def self.available_options
182210
end),
183211
FastlaneCore::ConfigItem.new(key: :endpoint,
184212
description: "Bugsnag deployment endpoint",
185-
optional: true,
186-
default_value: "https://build.bugsnag.com"),
213+
default_value: nil,
214+
optional: true),
187215
FastlaneCore::ConfigItem.new(key: :metadata,
188216
description: "Metadata",
189217
optional:true,
@@ -221,7 +249,8 @@ def self.load_git_remote_options
221249
git_options[:repository] = origin.url
222250
git_options[:revision] = repo.revparse("HEAD")
223251
end
224-
rescue
252+
rescue => e
253+
UI.verbose("Could not load git options: #{e.message}")
225254
end
226255
return git_options
227256
end
@@ -343,46 +372,6 @@ def self.map_meta_data(meta_data)
343372
end
344373
output
345374
end
346-
347-
def self.parse_response_body(response)
348-
begin
349-
JSON.load(response.body)
350-
rescue
351-
nil
352-
end
353-
end
354-
355-
def self.to_kebab_case(str)
356-
str.gsub(/([a-z])([A-Z])/, '\1-\2').downcase
357-
end
358-
359-
def self.json_to_cli_args(json_payload)
360-
data = JSON.parse(json_payload)
361-
362-
data.map do |k, v|
363-
key = to_kebab_case(k)
364-
if v.is_a?(Hash)
365-
# Convert nested hash into key=value pairs joined by commas
366-
nested = v.map { |nk, nv| "#{to_kebab_case(nk)}=#{nv}" }.join(",")
367-
"--#{key}=#{nested}"
368-
else
369-
"--#{key}=#{v}"
370-
end
371-
end.join(" ")
372-
end
373-
374-
def self.send_notification(cli_path, body)
375-
args = self.json_to_cli_args(body)
376-
bugsnag_cli_command = "#{cli_path} create-build #{args}"
377-
378-
UI.verbose("Running command: #{bugsnag_cli_command}")
379-
success = Kernel.system(bugsnag_cli_command)
380-
if success
381-
UI.success("Build successfully sent to Bugsnag")
382-
else
383-
UI.user_error!("Failed to send build to Bugsnag.")
384-
end
385-
end
386375
end
387376
end
388377
end

tools/fastlane-plugin/spec/send_build_to_bugsnag_spec.rb

Lines changed: 25 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -15,13 +15,7 @@ def run_with args
1515

1616
context 'building an iOS project' do
1717
it 'detects default Info.plist file excluding test dirs' do
18-
expect(BuildAction).to receive(:send_notification) do |cli_path, body|
19-
args = ::JSON.load(body)
20-
expect(args['versionName']).to eq '2.0-other'
21-
expect(args['bundleVersion']).to eq '22'
22-
expect(args['apiKey']).to eq '12345678901234567890123456789AAA'
23-
end
24-
18+
expect(Kernel).to receive(:system).with("#{BUGSNAG_CLI_PATH} create-build --api-key 12345678901234567890123456789AAA --version-name 2.0-other --bundle-version 22 --builder-name josh.edney --revision 3a30a510ba898341ff8631da49dc7021fb28c40e --repository [email protected]:bugsnag/bugsnag-dsym-upload.git").and_return(true)
2519
Dir.chdir(File.join(FIXTURE_PATH, 'ios_proj')) do
2620
run_with({})
2721
end
@@ -30,13 +24,7 @@ def run_with args
3024
it 'reads api key from legacy location' do
3125
# the API key is now in `bugsnag.apiKey`, it used to be in 'BugsnagAPIKey',
3226
# test this can be extracted correctly from the `ios_proj_legacy`
33-
expect(BuildAction).to receive(:send_notification) do |cli_path, body|
34-
args = ::JSON.load(body)
35-
expect(args['versionName']).to eq '4.0-project'
36-
expect(args['bundleVersion']).to eq '44'
37-
expect(args['apiKey']).to eq '12345678901234567890123456789BBB'
38-
end
39-
27+
expect(Kernel).to receive(:system).with("#{BUGSNAG_CLI_PATH} create-build --api-key 12345678901234567890123456789BBB --version-name 4.0-project --bundle-version 44 --builder-name josh.edney --revision 3a30a510ba898341ff8631da49dc7021fb28c40e --repository [email protected]:bugsnag/bugsnag-dsym-upload.git").and_return(true)
4028
Dir.chdir(File.join(FIXTURE_PATH, 'ios_proj_legacy')) do
4129
run_with({})
4230
end
@@ -45,11 +33,7 @@ def run_with args
4533
context 'using default config_file option' do
4634
context 'override API key from config' do
4735
it 'reads API key from the api_key option' do
48-
expect(BuildAction).to receive(:send_notification) do |cli_path, body|
49-
args = ::JSON.load(body)
50-
expect(args['apiKey']).to eq '12345678901234567890123456789FFF'
51-
end
52-
36+
expect(Kernel).to receive(:system).with("#{BUGSNAG_CLI_PATH} create-build --api-key 12345678901234567890123456789FFF --version-name 2.0-other --bundle-version 22 --builder-name josh.edney --revision 3a30a510ba898341ff8631da49dc7021fb28c40e --repository [email protected]:bugsnag/bugsnag-dsym-upload.git").and_return(true)
5337
Dir.chdir(File.join(FIXTURE_PATH, 'ios_proj')) do
5438
run_with({
5539
api_key: '12345678901234567890123456789FFF'
@@ -58,12 +42,7 @@ def run_with args
5842
end
5943

6044
it 'uses input versions from options' do
61-
expect(BuildAction).to receive(:send_notification) do |cli_path, body|
62-
args = ::JSON.load(body)
63-
expect(args['versionName']).to eq '8.0.0'
64-
expect(args['bundleVersion']).to eq '800'
65-
end
66-
45+
expect(Kernel).to receive(:system).with("#{BUGSNAG_CLI_PATH} create-build --api-key 12345678901234567890123456789AAA --version-name 8.0.0 --bundle-version 800 --builder-name josh.edney --revision 3a30a510ba898341ff8631da49dc7021fb28c40e --repository [email protected]:bugsnag/bugsnag-dsym-upload.git").and_return(true)
6746
Dir.chdir(File.join(FIXTURE_PATH, 'ios_proj')) do
6847
run_with({
6948
app_version: '8.0.0',
@@ -76,13 +55,7 @@ def run_with args
7655

7756
context 'override config_file option' do
7857
it 'reads API key and version info from the config file' do
79-
expect(BuildAction).to receive(:send_notification) do |cli_path, body|
80-
args = ::JSON.load(body)
81-
expect(args['versionName']).to eq '3.0-project'
82-
expect(args['bundleVersion']).to eq '33'
83-
expect(args['apiKey']).to eq '12345678901234567890123456789DDD'
84-
end
85-
58+
expect(Kernel).to receive(:system).with("#{BUGSNAG_CLI_PATH} create-build --api-key 12345678901234567890123456789DDD --version-name 3.0-project --bundle-version 33 --builder-name josh.edney --revision 3a30a510ba898341ff8631da49dc7021fb28c40e --repository [email protected]:bugsnag/bugsnag-dsym-upload.git").and_return(true)
8659
Dir.chdir(File.join(FIXTURE_PATH, 'ios_proj')) do
8760
run_with({
8861
config_file: File.join('Project', 'Info.plist')
@@ -92,13 +65,7 @@ def run_with args
9265

9366
context 'override API key, and config file' do
9467
it 'uses the input api_key to override a non default config' do
95-
expect(BuildAction).to receive(:send_notification) do |cli_path, body|
96-
args = ::JSON.load(body)
97-
expect(args['versionName']).to eq '3.0-project'
98-
expect(args['bundleVersion']).to eq '33'
99-
expect(args['apiKey']).to eq '12345678901234567890123456789EEE'
100-
end
101-
68+
expect(Kernel).to receive(:system).with("#{BUGSNAG_CLI_PATH} create-build --api-key 12345678901234567890123456789EEE --version-name 3.0-project --bundle-version 33 --builder-name josh.edney --revision 3a30a510ba898341ff8631da49dc7021fb28c40e --repository [email protected]:bugsnag/bugsnag-dsym-upload.git").and_return(true)
10269
Dir.chdir(File.join(FIXTURE_PATH, 'ios_proj')) do
10370
run_with({
10471
config_file: File.join('Project', 'Info.plist'),
@@ -108,13 +75,7 @@ def run_with args
10875
end
10976

11077
it 'uses the input versions to override a non default config' do
111-
expect(BuildAction).to receive(:send_notification) do |cli_path, body|
112-
args = ::JSON.load(body)
113-
expect(args['versionName']).to eq '9.0.0'
114-
expect(args['bundleVersion']).to eq '900'
115-
expect(args['apiKey']).to eq '12345678901234567890123456789DDD'
116-
end
117-
78+
expect(Kernel).to receive(:system).with("#{BUGSNAG_CLI_PATH} create-build --api-key 12345678901234567890123456789DDD --version-name 9.0.0 --bundle-version 900 --builder-name josh.edney --revision 3a30a510ba898341ff8631da49dc7021fb28c40e --repository [email protected]:bugsnag/bugsnag-dsym-upload.git").and_return(true)
11879
Dir.chdir(File.join(FIXTURE_PATH, 'ios_proj')) do
11980
run_with({
12081
config_file: File.join('Project', 'Info.plist'),
@@ -128,13 +89,7 @@ def run_with args
12889

12990
context 'metadata added to args' do
13091
it "single key:value pair added" do
131-
expect(BuildAction).to receive(:send_notification) do |cli_path, body|
132-
args = ::JSON.load(body)
133-
expect(args['versionName']).to eq '4.0-project'
134-
expect(args['apiKey']).to eq '12345678901234567890123456789DDD'
135-
expect(args['metadata']).to eq '"test1": "First test"'
136-
end
137-
92+
expect(Kernel).to receive(:system).with("#{BUGSNAG_CLI_PATH} create-build --api-key 12345678901234567890123456789DDD --version-name 4.0-project --bundle-version 22 --builder-name josh.edney --revision 3a30a510ba898341ff8631da49dc7021fb28c40e --repository [email protected]:bugsnag/bugsnag-dsym-upload.git --metadata \"test1\": \"First test\"").and_return(true)
13893
Dir.chdir(File.join(FIXTURE_PATH, 'ios_proj')) do
13994
run_with({
14095
app_version: '4.0-project',
@@ -145,19 +100,27 @@ def run_with args
145100
end
146101

147102
it "multiple key:value pairs added" do
148-
expect(BuildAction).to receive(:send_notification) do |cli_path, body|
149-
args = ::JSON.load(body)
150-
expect(args['versionName']).to eq '4.0-project'
151-
expect(args['apiKey']).to eq '12345678901234567890123456789DDD'
152-
expect(args['metadata']).to eq '"test1": "First test", "test2": "Second test", "test3": "Third test"'
103+
expect(Kernel).to receive(:system).with("#{BUGSNAG_CLI_PATH} create-build --api-key 12345678901234567890123456789DDD --version-name 4.0-project --bundle-version 22 --builder-name josh.edney --revision 3a30a510ba898341ff8631da49dc7021fb28c40e --repository [email protected]:bugsnag/bugsnag-dsym-upload.git --metadata \"test1\": \"First test\", \"test2\": \"Second test\", \"test3\": \"Third test\"").and_return(true)
104+
Dir.chdir(File.join(FIXTURE_PATH, 'ios_proj')) do
105+
run_with({
106+
app_version: '4.0-project',
107+
api_key: '12345678901234567890123456789DDD',
108+
metadata: '"test1": "First test", "test2": "Second test", "test3": "Third test"'
109+
})
153110
end
111+
end
154112

113+
it "multiple key:value pairs added as a hash" do
114+
expect(Kernel).to receive(:system).with("#{BUGSNAG_CLI_PATH} create-build --api-key 12345678901234567890123456789DDD --version-name 4.0-project --bundle-version 22 --builder-name josh.edney --revision 3a30a510ba898341ff8631da49dc7021fb28c40e --repository [email protected]:bugsnag/bugsnag-dsym-upload.git --metadata \"custom_field_1\"=\"value1\", \"custom_field_2\"=\"value2\"").and_return(true)
155115
Dir.chdir(File.join(FIXTURE_PATH, 'ios_proj')) do
156116
run_with({
157-
app_version: '4.0-project',
158-
api_key: '12345678901234567890123456789DDD',
159-
metadata: '"test1": "First test", "test2": "Second test", "test3": "Third test"'
160-
})
117+
app_version: '4.0-project',
118+
api_key: '12345678901234567890123456789DDD',
119+
metadata: {
120+
"custom_field_1": "value1",
121+
"custom_field_2": "value2"
122+
}
123+
})
161124
end
162125
end
163126
end

tools/fastlane-plugin/spec/spec_helper.rb

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,3 +8,11 @@ module SpecHelper
88
require 'fastlane/plugin/bugsnag' # import the actual plugin
99

1010
FIXTURE_PATH = File.expand_path(File.join(File.dirname(__FILE__), 'fixtures'))
11+
12+
13+
# expands the `got` and `expected` output in the RSpec output
14+
RSpec.configure do |config|
15+
config.expect_with :rspec do |expectations|
16+
expectations.max_formatted_output_length = nil # unlimited
17+
end
18+
end

0 commit comments

Comments
 (0)