fastlane-plugin-bugsnag 1.3.3 → 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 97cb1046d8bdd668186f6320ecc9895431caa33e27be40fee7244355afb31a80
4
- data.tar.gz: 7643a09dcf9d6370455b180f87a66e94f690c120c7ff9cc9054f176ae21ba512
3
+ metadata.gz: 0f2f91641496dae26549b47215b4cf137e6c03d7307f38b491903a8505cb26c1
4
+ data.tar.gz: eca880b9cd9aa3afaca45892e01ba63130fb29d069a40eb2f2a8fef98c5dee51
5
5
  SHA512:
6
- metadata.gz: 4ac614726269d702515c6bd2a38bbb20d26b405545936b894f52a68636898680807b7518862952f43d9f35e0699f56e1c564a4b219f8ed3c5b56985f24bb3efc
7
- data.tar.gz: 89eee8521282656e20539fcb65a1948ab6e8a8db0037d7753a10a1fadb1082404d47591d299df1a8f4dc28f631930a446801ae2e7e31bd0f6c813796d82c23ff
6
+ metadata.gz: 56875d0eb5b5d644030466ab85c80817524d953c3286593fdbc7c2d9db4e81d919f90d6875a40d6d4adce8d81846db0b85069fbf07cc470d927bc6530f4b2836
7
+ data.tar.gz: 456b9b1d0ece3dcedd9302654ac25be698b075a44bb108c6c11257f6b8c4d23ebd4e6c641bccf41d40aaabf2d83c074a13d92ceca9647dfffbfb0e7c488f496b
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2016 Bugsnag, Inc.
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,178 @@
1
+ #!/usr/bin/env bash
2
+ #
3
+ # Given a directory, uploads any *.dSYM bundles with the directory to
4
+ # Bugsnag. As a pre-upload step, bitcode symbol maps can be combined with
5
+ # dSYM files to ensure symbols are sent for bitcode-enabled binaries.
6
+ #
7
+ # Depends on:
8
+ # * curl
9
+ # * dwarfdump
10
+ # * dsymutil (for --symbol-maps, optional)
11
+ # * unzip (for uploading a .zip file, optional)
12
+
13
+ function print_usage() {
14
+ echo "Usage: $0 [--symbol-maps DIR] dSYMS_PATH"
15
+ echo
16
+ echo "-h, --help Displays this message"
17
+ echo "-v, --verbose Print verbose logging output during execution"
18
+ echo "--api-key API_KEY The API key of the project the dSYM should be applied to"
19
+ echo "--symbol-maps DIR Path to a directory of bitcode symbol maps. The"
20
+ echo " dSYM files will be restored with symbols prior to"
21
+ echo " upload. Requires dsymutil."
22
+ echo "--upload-server URL The server receiving dSYM files. Set this value if"
23
+ echo " using an on-premise Bugsnag installation"
24
+ echo "--project-root DIR The root directory of the project. This will help to"
25
+ echo " group error reports by project"
26
+ echo "dSYMS_PATH A directory or .zip file containing *.dSYM bundles to"
27
+ echo " upload"
28
+ }
29
+
30
+ function exit_with_usage() {
31
+ echo $1
32
+ echo
33
+ print_usage
34
+ exit 1
35
+ }
36
+
37
+ function log() {
38
+ if [[ $silent != 1 ]]; then
39
+ echo $@
40
+ fi
41
+ }
42
+
43
+ function log_verbose() {
44
+ if [[ $verbose == 1 ]]; then
45
+ log $@
46
+ fi
47
+ }
48
+
49
+ upload_server=https://upload.bugsnag.com
50
+ unset symbol_maps
51
+ unset dsym_dir
52
+ unset verbose
53
+ unset silent
54
+ unset project_root
55
+ unset api_key
56
+
57
+ while [[ $# -gt 0 ]]; do
58
+ case $1 in
59
+ -h|--help)
60
+ print_usage
61
+ exit 0;;
62
+ -s|--silent)
63
+ silent=1
64
+ shift;;
65
+ -v|--verbose)
66
+ verbose=1
67
+ shift;;
68
+ --symbol-maps)
69
+ symbol_maps=$2
70
+ shift
71
+ shift;;
72
+ --upload-server)
73
+ upload_server=$2
74
+ shift
75
+ shift;;
76
+ --api-key)
77
+ api_key=$2
78
+ shift
79
+ shift;;
80
+ --project-root)
81
+ project_root=$2
82
+ shift
83
+ shift;;
84
+ -*)
85
+ exit_with_usage "Invalid parameter provided: $1";;
86
+ *)
87
+ dsym_dir=$1
88
+ break;;
89
+ esac
90
+ done
91
+
92
+ # Set IFS to ensure that file paths with spaces in get processed correctly
93
+ IFS=$'\n'
94
+
95
+ if [[ ! -z $symbol_maps ]]; then
96
+ if [[ ! -d $symbol_maps ]]; then
97
+ exit_with_usage "Bitcode symbol map parameter is not a directory"
98
+ elif [[ ! -x "$(command -v dsymutil 2>/dev/null)" ]]; then
99
+ exit_with_usage "dsymutil command not found."
100
+ fi
101
+ fi
102
+ if [[ -z $dsym_dir ]]; then
103
+ exit_with_usage "No dSYM directory provided"
104
+ fi
105
+ if [[ ! -d $dsym_dir ]]; then
106
+ if [[ $dsym_dir == *".zip" ]]; then
107
+ if [[ ! -x "$(command -v unzip 2>/dev/null)" ]]; then
108
+ exit_with_usage "unzip command not found."
109
+ fi
110
+ temp_dir=$(mktemp -dt "bugsnag-dsym-upload.XXX")
111
+ unzip -qq $dsym_dir -d $temp_dir
112
+ dsym_dir=$temp_dir
113
+ else
114
+ exit_with_usage "'$dsym_dir' is not a directory or a zip file"
115
+ fi
116
+ fi
117
+
118
+ log_verbose "Uploading files to $upload_server"
119
+ success_count=0
120
+ fail_count=0
121
+
122
+ for dsym in $dsym_dir/*.dSYM; do
123
+ log_verbose "Preparing to upload $dsym"
124
+
125
+ if [[ -d $symbol_maps ]]; then
126
+ log_verbose "Updating file with bitcode symbol maps in $symbol_maps"
127
+ dsymutil "$dsym" --symbol-map "$symbol_maps"
128
+ fi
129
+
130
+ dwarf_data=$dsym/Contents/Resources/DWARF
131
+ if [[ ! -d $dwarf_data ]]; then
132
+ log_verbose "Skipping file missing DWARF data: $dsym"
133
+ fail_count=$((fail_count+1))
134
+ continue
135
+ fi
136
+ for file in $dwarf_data/*; do
137
+ uuid=$(dwarfdump -u $file 2>/dev/null)
138
+ if [[ $uuid == UUID* ]]; then
139
+ log Uploading $uuid
140
+
141
+ # Attach the api key and project root parameters if they have been provided
142
+ args=""
143
+ if [[ ! -z $project_root ]]; then
144
+ args="-F projectRoot=\"$project_root\" "
145
+ fi
146
+
147
+ if [[ ! -z $api_key ]]; then
148
+ args="$args-F apiKey=$api_key"
149
+ fi
150
+
151
+ # We need to shell out to perform the curl as there seems to be some indirect
152
+ # wrapping of this script which causes the command to fail if called directly.
153
+ curl_cmd="curl --fail --silent --show-error --http1.1 $upload_server -F dsym=@\"$file\" $args"
154
+ output=$(sh -c "$curl_cmd")
155
+
156
+ if [ $? -eq 0 ] && [ "$output" != "invalid apiKey" ]; then
157
+ success_count=$((success_count+1))
158
+ else
159
+ fail_count=$((fail_count+1))
160
+ log_verbose "Failed to upload file: $file"
161
+ fi
162
+ echo $output | grep -v '^OK$'
163
+ log
164
+ else
165
+ log_verbose "Skipping file without UUID: $file"
166
+ fail_count=$((fail_count+1))
167
+ fi
168
+ done
169
+ done
170
+
171
+ if [ $success_count -gt 0 ]; then
172
+ log "$success_count files uploaded successfully"
173
+ fi
174
+
175
+ if [ $fail_count -gt 0 ]; then
176
+ log "$fail_count files failed to upload"
177
+ exit 1
178
+ fi
@@ -9,32 +9,31 @@ module Fastlane
9
9
 
10
10
  def self.run(params)
11
11
  payload = {buildTool: BUILD_TOOL, sourceControl: {}}
12
- if lane_context[:PLATFORM_NAME] == :android
13
- payload.merge!(options_from_android_manifest(params[:config_file])) if params[:config_file]
14
- else
15
- payload.merge!(options_from_info_plist(params[:config_file])) if params[:config_file]
16
- end
17
12
 
18
- default_plist = default_info_plist_path
19
- default_manifest = default_android_manifest_path
20
- if (lane_context[:PLATFORM_NAME] == :android and params[:config_file] == default_manifest) or
21
- (lane_context[:PLATFORM_NAME] != :android and params[:config_file] == default_plist)
22
- # Load custom API key and version properties only if config file has not been overridden
23
- payload[:apiKey] = params[:api_key] unless params[:api_key].nil?
24
- payload[:appVersion] = params[:app_version] unless params[:app_version].nil?
25
- payload[:appVersionCode] = params[:android_version_code] unless params[:android_version_code].nil?
26
- payload[:appBundleVersion] = params[:ios_bundle_version] unless params[:ios_bundle_version].nil?
13
+ # If a configuration file was found or was specified, load in the options:
14
+ if params[:config_file]
15
+ UI.message("Loading build information from #{params[:config_file]}")
16
+ config_options = load_config_file_options(params[:config_file])
17
+
18
+ # for each of the config options, if it's not been overriden by any
19
+ # input to the lane, write it to the payload:
20
+ payload[:apiKey] = params[:api_key] || config_options[:apiKey]
21
+ payload[:appVersion] = params[:app_version] || config_options[:appVersion]
22
+ payload[:appVersionCode] = params[:android_version_code] || config_options[:appVersionCode]
23
+ payload[:appBundleVersion] = params[:ios_bundle_version] || config_options[:appBundleVersion]
24
+ payload[:releaseStage] = params[:release_stage] || config_options[:releaseStage] || "production"
27
25
  else
28
- # Print which file is populating version and API key information since the value has been
29
- # overridden
30
- UI.message("Loading API key and app version info from #{params[:config_file]}")
26
+ # No configuration file was found or specified, use the input parameters:
27
+ payload[:apiKey] = params[:api_key]
28
+ payload[:appVersion] = params[:app_version]
29
+ payload[:appVersionCode] = params[:android_version_code]
30
+ payload[:appBundleVersion] = params[:ios_bundle_version]
31
+ payload[:releaseStage] = params[:release_stage] || "production"
31
32
  end
32
- payload.delete(:config_file)
33
-
34
- # Overwrite automated options with configured if set
35
- payload[:releaseStage] = params[:release_stage] unless params[:release_stage].nil?
36
- payload[:builderName] = params[:builder]
37
33
 
34
+ # If builder, or source control information has been provided into
35
+ # Fastlane, apply it to the payload here.
36
+ payload[:builderName] = params[:builder] if params[:builder]
38
37
  payload[:sourceControl][:revision] = params[:revision] if params[:revision]
39
38
  payload[:sourceControl][:repository] = params[:repository] if params[:repository]
40
39
  payload[:sourceControl][:provider] = params[:provider] if params[:provider]
@@ -47,6 +46,13 @@ module Fastlane
47
46
  if payload[:appVersion].nil?
48
47
  UI.user_error! missing_app_version_message(params)
49
48
  end
49
+
50
+ # If verbose flag is enabled (`--verbose`), display the payload debug info
51
+ UI.verbose("Sending build to Bugsnag with payload:")
52
+ payload.each do |param|
53
+ UI.verbose(" #{param[0].to_s.rjust(18)}: #{param[1]}")
54
+ end
55
+
50
56
  send_notification(params[:endpoint], ::JSON.dump(payload))
51
57
  end
52
58
 
@@ -60,16 +66,16 @@ module Fastlane
60
66
  end
61
67
  else
62
68
  if params[:config_file]
63
- message << "Set BugsnagAPIKey in your Info.plist file to detect API key automatically."
69
+ message << "Set bugsnag.apiKey in your Info.plist file to detect API key automatically."
64
70
  else
65
- message << "Set the config_file option with the path to your Info.plist and set BugsnagAPIKey in it to detect API key automatically."
71
+ message << "Set the config_file option with the path to your Info.plist and set bugsnag.apiKey in it to detect API key automatically."
66
72
  end
67
73
  end
68
74
  message
69
75
  end
70
76
 
71
77
  def self.missing_app_version_message(params)
72
- message = "An app version must be specified release a build."
78
+ message = "An app version must be specified release a build. "
73
79
  if lane_context[:PLATFORM_NAME] == :android
74
80
  if params[:config_file]
75
81
  message << "Set com.bugsnag.android.APP_VERSION in your AndroidManifest.xml to detect this value automatically."
@@ -115,32 +121,27 @@ module Fastlane
115
121
  end
116
122
 
117
123
  def self.available_options
118
- options = load_default_values
124
+ git_options = load_git_remote_options
119
125
  [
120
126
  FastlaneCore::ConfigItem.new(key: :config_file,
121
127
  description: "AndroidManifest.xml/Info.plist location",
122
128
  optional: true,
123
- default_value: options[:config_file]),
129
+ default_value: default_config_file_path),
124
130
  FastlaneCore::ConfigItem.new(key: :api_key,
125
131
  description: "Bugsnag API Key",
126
- optional: true,
127
- default_value: options[:apiKey]),
132
+ optional: true),
128
133
  FastlaneCore::ConfigItem.new(key: :app_version,
129
134
  description: "App version being built",
130
- optional: true,
131
- default_value: options[:appVersion]),
135
+ optional: true),
132
136
  FastlaneCore::ConfigItem.new(key: :android_version_code,
133
137
  description: "Android app version code",
134
- optional: true,
135
- default_value: options[:appVersionCode]),
138
+ optional: true),
136
139
  FastlaneCore::ConfigItem.new(key: :ios_bundle_version,
137
140
  description: "iOS/macOS/tvOS bundle version",
138
- optional: true,
139
- default_value: options[:appBundleVersion]),
141
+ optional: true),
140
142
  FastlaneCore::ConfigItem.new(key: :release_stage,
141
143
  description: "Release stage being built, i.e. staging, production",
142
- optional: true,
143
- default_value: options[:releaseStage] || "production"),
144
+ optional: true),
144
145
  FastlaneCore::ConfigItem.new(key: :builder,
145
146
  description: "The name of the entity triggering the build",
146
147
  optional: true,
@@ -148,19 +149,19 @@ module Fastlane
148
149
  FastlaneCore::ConfigItem.new(key: :repository,
149
150
  description: "The source control repository URL for this application",
150
151
  optional: true,
151
- default_value: options[:repository]),
152
+ default_value: git_options[:repository]),
152
153
  FastlaneCore::ConfigItem.new(key: :revision,
153
154
  description: "The source control revision id",
154
155
  optional: true,
155
- default_value: options[:revision]),
156
+ default_value: git_options[:revision]),
156
157
  FastlaneCore::ConfigItem.new(key: :provider,
157
158
  description: "The source control provider, one of 'github-enterprise', 'gitlab-onpremise', or 'bitbucket-server', if any",
158
159
  optional: true,
159
160
  default_value: nil,
160
161
  verify_block: proc do |value|
161
- valid = ['github-enterprise', 'gitlab-onpremise', 'bitbucket-server'].include? value
162
+ valid = ['github', 'github-enterprise', 'gitlab', 'gitlab-onpremise', 'bitbucket', 'bitbucket-server'].include? value
162
163
  unless valid
163
- UI.user_error!("Provider must be one of 'github-enterprise', 'gitlab-onpremise', 'bitbucket-server', or unspecified")
164
+ UI.user_error!("Provider must be one of 'github', 'github-enterprise', 'gitlab', 'gitlab-onpremise', 'bitbucket', 'bitbucket-server', or unspecified")
164
165
  end
165
166
  end),
166
167
  FastlaneCore::ConfigItem.new(key: :endpoint,
@@ -172,69 +173,98 @@ module Fastlane
172
173
 
173
174
  private
174
175
 
175
- def self.load_default_values
176
- options = {releaseStage: "production", user: `whoami`.chomp}
176
+ # Get any Git options (remote repo, and revision) from the directory
177
+ def self.load_git_remote_options
178
+ git_options = {repository:nil, revision:nil}
179
+ require "git"
180
+ begin
181
+ repo = Git.open(Dir.pwd)
182
+ origin = repo.remotes.detect {|r| r.name == "origin"}
183
+ origin = repo.remotes.first unless origin
184
+ if origin
185
+ git_options[:repository] = origin.url
186
+ git_options[:revision] = repo.revparse("HEAD")
187
+ end
188
+ rescue
189
+ end
190
+ return git_options
191
+ end
192
+
193
+ # Used to get a default configuration file (AndroidManifest.xml or Info.plist)
194
+ def self.default_config_file_path
177
195
  case lane_context[:PLATFORM_NAME]
178
196
  when nil
179
197
  if file_path = default_android_manifest_path
180
- options.merge!(load_default_android_values(file_path))
198
+ return file_path
181
199
  elsif file_path = default_info_plist_path
182
- options.merge!(options_from_info_plist(file_path))
200
+ return file_path
183
201
  end
184
202
  when :android
185
203
  if file_path = default_android_manifest_path
186
- options.merge!(load_default_android_values(file_path))
204
+ return file_path
187
205
  end
188
206
  else
189
207
  if file_path = default_info_plist_path
190
- options.merge!(options_from_info_plist(file_path))
208
+ return file_path
191
209
  end
192
210
  end
211
+ end
193
212
 
194
- if git_opts = git_remote_options
195
- options.merge!(git_opts)
213
+ def self.load_config_file_options config_file
214
+ options = {}
215
+ case File.extname(config_file)
216
+ when ".xml"
217
+ options = load_options_from_xml(config_file)
218
+ return options
219
+ when ".plist"
220
+ options = load_options_from_plist(config_file)
221
+ return options
222
+ else
223
+ UI.user_error("File type of '#{config_file}' was not recognised. This should be .xml for Android and .plist for Cococa")
196
224
  end
197
- options
198
225
  end
199
226
 
200
- def self.load_default_android_values file_path
201
- options = options_from_android_manifest(file_path)
202
- build_gradle_path = Dir.glob("{android/,}app/build.gradle").first
203
- build_gradle_path ||= Dir.glob("build.gradle").first
204
- options.merge!(options_from_build_gradle(build_gradle_path)) if build_gradle_path
205
- options
227
+ def self.default_info_plist_path
228
+ Dir.glob("./{ios/,}*/Info.plist").reject {|path| path =~ /build|test/i }.first
206
229
  end
207
230
 
208
- def self.default_android_manifest_path
209
- Dir.glob("./{android/,}{app,}/src/main/AndroidManifest.xml").first
231
+ def self.load_options_from_plist file_path
232
+ options = {}
233
+ plist_getter = Fastlane::Actions::GetInfoPlistValueAction
234
+ bugsnag_dict = plist_getter.run(path: file_path, key: "bugsnag")
235
+ api_key = bugsnag_dict["apiKey"] unless bugsnag_dict.nil?
236
+ release_stage = bugsnag_dict["releaseStage"] unless bugsnag_dict.nil?
237
+ if api_key.nil?
238
+ api_key = plist_getter.run(path: file_path, key: "BugsnagAPIKey")
239
+ end
240
+ options[:apiKey] = api_key
241
+ options[:releaseStage] = release_stage
242
+ options[:appVersion] = plist_getter.run(path: file_path, key: "CFBundleShortVersionString")
243
+ options[:appBundleVersion] = plist_getter.run(path: file_path, key: "CFBundleVersion")
244
+ return options
210
245
  end
211
246
 
212
- def self.default_info_plist_path
213
- Dir.glob("./{ios/,}*/Info.plist").reject {|path| path =~ /build|test/i }.first
247
+ def self.default_android_manifest_path
248
+ Dir.glob("./{android/,}{app,}/src/main/AndroidManifest.xml").first
214
249
  end
215
250
 
216
- def self.options_from_info_plist file_path
217
- plist_getter = Fastlane::Actions::GetInfoPlistValueAction
218
- {
219
- apiKey: plist_getter.run(path: file_path, key: "BugsnagAPIKey"),
220
- appVersion: plist_getter.run(path: file_path, key: "CFBundleShortVersionString"),
221
- appBundleVersion: plist_getter.run(path: file_path, key: "CFBundleVersion"),
222
- config_file: file_path,
223
- }
251
+ def self.load_options_from_xml file_path
252
+ options = options_from_android_manifest(file_path)
253
+ build_gradle_path = Dir.glob("{android/,}app/build.gradle").first || Dir.glob("build.gradle").first
254
+ options.merge!(options_from_build_gradle(build_gradle_path)) if build_gradle_path
255
+ return options
224
256
  end
225
257
 
226
258
  def self.options_from_android_manifest file_path
227
259
  options = {}
228
260
  begin
229
261
  meta_data = parse_android_manifest_options(XmlSimple.xml_in(file_path))
230
-
231
262
  options[:apiKey] = meta_data["com.bugsnag.android.API_KEY"]
232
263
  options[:appVersion] = meta_data["com.bugsnag.android.APP_VERSION"]
233
264
  options[:releaseStage] = meta_data["com.bugsnag.android.RELEASE_STAGE"]
234
265
  rescue ArgumentError
235
266
  nil
236
267
  end
237
- options[:config_file] = file_path
238
268
  options
239
269
  end
240
270
 
@@ -253,23 +283,6 @@ module Fastlane
253
283
  options
254
284
  end
255
285
 
256
- def self.git_remote_options
257
- require "git"
258
- begin
259
- repo = Git.open(Dir.pwd)
260
- origin = repo.remotes.detect {|r| r.name == "origin"}
261
- origin = repo.remotes.first unless origin
262
- if origin
263
- return {
264
- repository: origin.url,
265
- revision: repo.revparse("HEAD"),
266
- }
267
- end
268
- rescue
269
- end
270
- nil
271
- end
272
-
273
286
  def self.parse_android_manifest_options config_hash
274
287
  map_meta_data(get_meta_data(config_hash))
275
288
  end
@@ -6,9 +6,24 @@ module Fastlane
6
6
  File.join(File.dirname(__FILE__), '..', '..', '..', '..', '..', 'bugsnag-dsym-upload'))
7
7
 
8
8
  def self.run(params)
9
+ # If we have not explicitly set an API key through env, or parameter
10
+ # input in Fastfile, find an API key in the Info.plist in config_file param
11
+ api_key = params[:api_key]
12
+ if params[:config_file] && params[:api_key] == nil
13
+ UI.message("Using the API Key from #{params[:config_file]}")
14
+ api_key = options_from_info_plist(params[:config_file])[:apiKey]
15
+ end
16
+
17
+ # If verbose flag is enabled (`--verbose`), display the plugin action debug info
18
+ # Store the verbose flag for use in the upload arguments.
19
+ verbose = UI.verbose("Uploading dSYMs to Bugsnag with the following parameters:")
20
+ params.values.each do |param|
21
+ UI.verbose(" #{param[0].to_s.rjust(18)}: #{param[1]}")
22
+ end
23
+
9
24
  parse_dsym_paths(params[:dsym_path]).each do |dsym_path|
10
25
  if dsym_path.end_with?(".zip") or File.directory?(dsym_path)
11
- args = upload_args(dsym_path, params[:symbol_maps_path], params[:upload_url], params[:project_root], params[:verbose])
26
+ args = upload_args(dsym_path, params[:symbol_maps_path], params[:upload_url], params[:project_root], api_key, verbose)
12
27
  success = Kernel.system(UPLOAD_SCRIPT_PATH, *args)
13
28
  if success
14
29
  UI.success("Uploaded dSYMs in #{dsym_path}")
@@ -22,7 +37,7 @@ module Fastlane
22
37
  end
23
38
 
24
39
  def self.description
25
- "Uploads symbol files to Bugsnag"
40
+ "Uploads dSYM debug symbol files to Bugsnag"
26
41
  end
27
42
 
28
43
  def self.authors
@@ -54,12 +69,26 @@ module Fastlane
54
69
  end
55
70
  validate_symbol_maps = proc do |path|
56
71
  return if path.nil?
57
-
58
72
  unless File.exist?(path) and File.directory?(path)
59
73
  UI.user_error!("Symbol maps file needs to be a directory containing symbol map files")
60
74
  end
61
75
  end
76
+ validate_api_key = proc do |key|
77
+ return if key.nil?
78
+ unless !key[/\H/] and key.length == 32
79
+ UI.user_error!("API key should be a 32 character hexadecimal string")
80
+ end
81
+ end
82
+
83
+ # If the Info.plist is in a default location, we'll get API key here
84
+ # This will be overwritten if you pass in an API key parameter in your
85
+ # Fastfile, or have an API key environment variable set.
62
86
  [
87
+ FastlaneCore::ConfigItem.new(key: :api_key,
88
+ env_name: "BUGSNAG_API_KEY",
89
+ description: "Bugsnag API Key",
90
+ optional: true,
91
+ verify_block: validate_api_key),
63
92
  FastlaneCore::ConfigItem.new(key: :dsym_path,
64
93
  type: Array,
65
94
  env_name: "BUGSNAG_DSYM_PATH",
@@ -83,18 +112,40 @@ module Fastlane
83
112
  description: "Root path of the project",
84
113
  default_value: Dir::pwd,
85
114
  optional: true),
86
- FastlaneCore::ConfigItem.new(key: :verbose,
87
- env_name: "BUGSNAG_VERBOSE",
88
- description: "Print helpful debug info",
89
- skip_type_validation: true,
90
- optional: true),
115
+ FastlaneCore::ConfigItem.new(key: :config_file,
116
+ env_name: "BUGSNAG_CONFIG_FILE",
117
+ description: "Info.plist location",
118
+ optional: true,
119
+ default_value: default_info_plist_path)
91
120
  ]
92
121
  end
93
122
 
94
123
  private
95
124
 
96
- def self.upload_args dir, symbol_maps_dir, upload_url, project_root, verbose
125
+ def self.default_info_plist_path
126
+ # Find first 'Info.plist' in the current working directory
127
+ # ignoring any in 'build', or 'test' folders
128
+ return Dir.glob("./{ios/,}*/Info.plist").reject{|path| path =~ /build|test/i }.first
129
+ end
130
+
131
+ def self.options_from_info_plist file_path
132
+ plist_getter = Fastlane::Actions::GetInfoPlistValueAction
133
+ bugsnag_dict = plist_getter.run(path: file_path, key: "bugsnag")
134
+ api_key = bugsnag_dict["apiKey"] unless bugsnag_dict.nil?
135
+ # From v6.0.0 of bugsnag-cocoa, the API key is in 'bugsnag.apiKey',
136
+ # use 'BugsnagAPIKey' as a fallback if it exists (<v6.x.x)
137
+ if api_key.nil?
138
+ api_key = plist_getter.run(path: file_path, key: "BugsnagAPIKey")
139
+ end
140
+ {
141
+ apiKey: api_key,
142
+ config_file: file_path,
143
+ }
144
+ end
145
+
146
+ def self.upload_args dir, symbol_maps_dir, upload_url, project_root, api_key, verbose
97
147
  args = [verbose ? "--verbose" : "--silent"]
148
+ args += ["--api-key", api_key] unless api_key.nil?
98
149
  args += ["--upload-server", upload_url] unless upload_url.nil?
99
150
  args += ["--symbol-maps", symbol_maps_dir] unless symbol_maps_dir.nil?
100
151
  args += ["--project-root", project_root] unless project_root.nil?
@@ -110,9 +161,11 @@ module Fastlane
110
161
  end
111
162
 
112
163
  def self.default_dsym_path
113
- Actions.lane_context[SharedValues::DSYM_OUTPUT_PATH] ||
114
- Actions.lane_context[SharedValues::DSYM_PATHS] ||
115
- Dir["./**/*.dSYM.zip"] + Dir["./**/*.dSYM"]
164
+ path = Dir["./**/*.dSYM.zip"] + Dir["./**/*.dSYM"]
165
+ dsym_paths = Actions.lane_context[SharedValues::DSYM_PATHS] if defined? SharedValues::DSYM_PATHS
166
+ dsyms_output_path = Actions.lane_context[SharedValues::DSYM_OUTPUT_PATH] if defined? SharedValues::DSYM_OUTPUT_PATH
167
+ default_value = dsyms_output_path || dsym_paths || path
168
+ parse_dsym_paths(default_value)
116
169
  end
117
170
  end
118
171
  end
@@ -1,5 +1,5 @@
1
1
  module Fastlane
2
2
  module Bugsnag
3
- VERSION = "1.3.3"
3
+ VERSION = "2.0.0"
4
4
  end
5
5
  end
@@ -3,65 +3,75 @@ require 'spec_helper'
3
3
  Action = Fastlane::Actions::UploadSymbolsToBugsnagAction
4
4
 
5
5
  describe Action do
6
+ def run_with args
7
+ Action.run(Fastlane::ConfigurationHelper.parse(Action, args))
8
+ end
9
+
10
+ context "the packaged gem" do
11
+ gem_name = "fastlane-plugin-bugsnag-#{Fastlane::Bugsnag::VERSION}"
12
+
13
+ after do
14
+ FileUtils.rm_rf(gem_name)
15
+ FileUtils.rm_rf("#{gem_name}.gem")
16
+ end
6
17
 
7
- it 'has an executable upload script' do
8
- expect(File.exist?(Action::UPLOAD_SCRIPT_PATH)).to be true
18
+ it 'has an executable upload script' do
19
+ system('rake build')
20
+ system("gem unpack #{gem_name}.gem")
21
+ expect(File.exist?(File.join("#{gem_name}/bugsnag-dsym-upload"))).to be true
22
+ end
9
23
  end
10
24
 
11
25
  describe '#run' do
12
26
  it 'silences script output by default' do
13
27
  expect(Kernel).to receive(:system).with(Action::UPLOAD_SCRIPT_PATH,
14
- "--silent", FIXTURE_PATH).and_return(true)
15
- Action.run({dsym_path: FIXTURE_PATH})
16
- end
17
-
18
- it 'prints verbose if verbose flag set' do
19
- expect(Kernel).to receive(:system).with(Action::UPLOAD_SCRIPT_PATH,
20
- "--verbose", FIXTURE_PATH).and_return(true)
21
- Action.run({dsym_path: FIXTURE_PATH, verbose: true})
28
+ "--silent",
29
+ "--project-root", Dir::pwd,
30
+ FIXTURE_PATH).and_return(true)
31
+ run_with({dsym_path: FIXTURE_PATH})
22
32
  end
23
33
 
24
34
  it 'UI.user_error when script fails' do
25
35
  expect(Fastlane::UI).to receive(:user_error!).with("Failed uploading #{FIXTURE_PATH}")
26
36
  expect(Kernel).to receive(:system).with(Action::UPLOAD_SCRIPT_PATH,
27
- "--silent", FIXTURE_PATH).and_return(false)
28
- Action.run({dsym_path: FIXTURE_PATH})
37
+ "--silent",
38
+ "--project-root", Dir::pwd,
39
+ FIXTURE_PATH).and_return(false)
40
+ run_with({dsym_path: FIXTURE_PATH})
29
41
  end
30
42
 
31
43
  it 'requires the dSYM file path to exist' do
32
- expect(Fastlane::UI).to receive(:user_error!)
33
-
34
- Action.run({dsym_path: 'fake/file/path'})
44
+ expect(Fastlane::UI).to receive(:user_error!).at_least(:once)
45
+ run_with({dsym_path: 'fake/file/path'})
35
46
  end
36
47
 
37
48
  it 'rejects dSYM files which are not a .zip or a directory' do
38
- expect(Fastlane::UI).to receive(:user_error!)
39
-
40
- Action.run({dsym_path: File.join(FIXTURE_PATH, 'invalid_file')})
49
+ expect(Fastlane::UI).to receive(:user_error!).at_least(:once)
50
+ run_with({dsym_path: File.join(FIXTURE_PATH, 'invalid_file')})
41
51
  end
42
52
 
43
53
  it 'uploads a single .dSYM file' do
44
54
  directory = File.join(FIXTURE_PATH, 'dSYMs')
45
55
  expect(Kernel).to receive(:system).with(Action::UPLOAD_SCRIPT_PATH,
46
- "--silent", directory).and_return(true)
47
- Action.run({dsym_path: File.join(FIXTURE_PATH, 'dSYMs/app.dSYM')})
56
+ "--silent", "--project-root", Dir::pwd, directory).and_return(true)
57
+ run_with({dsym_path: File.join(FIXTURE_PATH, 'dSYMs/app.dSYM')})
48
58
  end
49
59
 
50
60
  it 'uploads a .zip of .dSYM files' do
51
61
  path = File.join(FIXTURE_PATH, 'files.zip')
52
62
  expect(Kernel).to receive(:system).with(Action::UPLOAD_SCRIPT_PATH,
53
- "--silent", path).and_return(true)
54
- Action.run({dsym_path: path})
63
+ "--silent", "--project-root", Dir::pwd, path).and_return(true)
64
+ run_with({dsym_path: path})
55
65
  end
56
66
 
57
67
  it 'uploads multiple .zip files' do
58
68
  zip1 = File.join(FIXTURE_PATH, 'files.zip')
59
69
  zip2 = File.join(FIXTURE_PATH, 'more_files.zip')
60
70
  expect(Kernel).to receive(:system).with(Action::UPLOAD_SCRIPT_PATH,
61
- "--silent", zip1).and_return(true)
71
+ "--silent", "--project-root", Dir::pwd, zip1).and_return(true)
62
72
  expect(Kernel).to receive(:system).with(Action::UPLOAD_SCRIPT_PATH,
63
- "--silent", zip2).and_return(true)
64
- Action.run({dsym_path: [zip1, zip2]})
73
+ "--silent", "--project-root", Dir::pwd, zip2).and_return(true)
74
+ run_with({dsym_path: [zip1, zip2]})
65
75
  end
66
76
 
67
77
  it 'uploads multiple .dSYM files multiple directories' do
@@ -71,10 +81,10 @@ describe Action do
71
81
  dsym4 = File.join(FIXTURE_PATH, 'stuff/app2.dSYM')
72
82
  directories = [File.join(FIXTURE_PATH, 'dSYMs'), File.join(FIXTURE_PATH, 'stuff')]
73
83
  expect(Kernel).to receive(:system).with(Action::UPLOAD_SCRIPT_PATH,
74
- "--silent", directories[0]).and_return(true)
84
+ "--silent", "--project-root", Dir::pwd, directories[0]).and_return(true)
75
85
  expect(Kernel).to receive(:system).with(Action::UPLOAD_SCRIPT_PATH,
76
- "--silent", directories[1]).and_return(true)
77
- Action.run({dsym_path: [dsym1, dsym2, dsym3, dsym4]})
86
+ "--silent", "--project-root", Dir::pwd, directories[1]).and_return(true)
87
+ run_with({dsym_path: [dsym1, dsym2, dsym3, dsym4]})
78
88
  end
79
89
 
80
90
  it 'uploads multiple .dSYM files in a single directory' do
@@ -82,8 +92,8 @@ describe Action do
82
92
  dsym2 = File.join(FIXTURE_PATH, 'dSYMs/app2.dSYM')
83
93
  directory = File.join(FIXTURE_PATH, 'dSYMs')
84
94
  expect(Kernel).to receive(:system).with(Action::UPLOAD_SCRIPT_PATH,
85
- "--silent", directory).and_return(true)
86
- Action.run({dsym_path: [dsym1, dsym2]})
95
+ "--silent", "--project-root", Dir::pwd, directory).and_return(true)
96
+ run_with({dsym_path: [dsym1, dsym2]})
87
97
  end
88
98
 
89
99
  it 'accepts a project root argument' do
@@ -92,7 +102,76 @@ describe Action do
92
102
  "--silent",
93
103
  "--project-root", root_path,
94
104
  FIXTURE_PATH).and_return(true)
95
- Action.run({dsym_path: FIXTURE_PATH, project_root: root_path})
105
+ run_with({dsym_path: FIXTURE_PATH, project_root: root_path})
106
+ end
107
+
108
+ it 'accepts an API key argument' do
109
+ api_key = "123456789123456789001234567890FF"
110
+ expect(Kernel).to receive(:system).with(Action::UPLOAD_SCRIPT_PATH,
111
+ "--silent",
112
+ "--api-key", api_key,
113
+ "--project-root", Dir::pwd,
114
+ FIXTURE_PATH).and_return(true)
115
+ run_with({dsym_path: FIXTURE_PATH, api_key: api_key})
116
+ end
117
+
118
+ it 'accepts an API key argument with no project root' do
119
+ api_key = "123456789012345678901234567890FF"
120
+ expect(Kernel).to receive(:system).with(Action::UPLOAD_SCRIPT_PATH,
121
+ "--silent",
122
+ "--api-key", api_key,
123
+ "--project-root", `pwd`.chomp,
124
+ FIXTURE_PATH).and_return(true)
125
+ run_with({dsym_path: FIXTURE_PATH, api_key: api_key, project_root: nil})
126
+ end
127
+
128
+ it 'uses default API key argument from plist' do
129
+ root_path = "/test/test/test"
130
+ api_key = "12345678901234567890123456789AAA" # Uses the API Key from ./spec/fixtures/ios_proj/FirstRealFolder/Info.plist
131
+ expect(Kernel).to receive(:system).with(Action::UPLOAD_SCRIPT_PATH,
132
+ "--silent",
133
+ "--api-key", api_key,
134
+ "--project-root", root_path,
135
+ FIXTURE_PATH).and_return(true)
136
+ Dir.chdir(File.join(FIXTURE_PATH, 'ios_proj')) do
137
+ run_with({dsym_path: FIXTURE_PATH, project_root: root_path})
138
+ end
139
+ end
140
+
141
+ it 'uses legacy API key argument from plist' do
142
+ root_path = "/test/test/test"
143
+ api_key = "12345678901234567890123456789BBB" # Uses the API Key from ./spec/fixtures/ios_proj_legacy/Project/Info.plist
144
+ expect(Kernel).to receive(:system).with(Action::UPLOAD_SCRIPT_PATH,
145
+ "--silent",
146
+ "--api-key", api_key,
147
+ "--project-root", root_path,
148
+ FIXTURE_PATH).and_return(true)
149
+ Dir.chdir(File.join(FIXTURE_PATH, 'ios_proj_legacy')) do
150
+ run_with({dsym_path: FIXTURE_PATH, project_root: root_path})
151
+ end
152
+ end
153
+
154
+ it 'allows option input to overwrite the config file api key' do
155
+ # The order of precedence is 1. option input, 2. env variable, 3. default or config file input (for api key only)
156
+ # The API key in ./spec/fixtures/ios_proj_legacy/Project/Info.plist is 12345678912345678900123456789AAA.
157
+ api_key = "12345678912345678900123456789CCC"
158
+ expect(Kernel).to receive(:system).with(Action::UPLOAD_SCRIPT_PATH,
159
+ "--silent",
160
+ "--api-key", api_key,
161
+ "--project-root", File.join(FIXTURE_PATH, 'ios_proj'),
162
+ FIXTURE_PATH).and_return(true)
163
+ Dir.chdir(File.join(FIXTURE_PATH, 'ios_proj')) do
164
+ run_with({dsym_path: FIXTURE_PATH, api_key: api_key, config_file: File.join('Project', 'Info.plist')})
165
+ end
166
+ end
167
+
168
+ it 'reject an invalid API key' do
169
+ api_key = "this-is-not-a-hex-key"
170
+ expect(Fastlane::UI).to receive(:user_error!).with("API key should be a 32 character hexadecimal string")
171
+ expect(Fastlane::UI).to receive(:user_error!).with("Failed uploading #{FIXTURE_PATH}")
172
+ Dir.chdir(File.join(FIXTURE_PATH, 'ios_proj')) do
173
+ run_with({dsym_path: FIXTURE_PATH, api_key: api_key, config_file: File.join('Project', 'Info.plist')})
174
+ end
96
175
  end
97
176
 
98
177
  context 'using a private server' do
@@ -100,9 +179,9 @@ describe Action do
100
179
  expect(Kernel).to receive(:system).with(Action::UPLOAD_SCRIPT_PATH,
101
180
  "--silent",
102
181
  "--upload-server", "http://myserver.example.com",
182
+ "--project-root", Dir::pwd,
103
183
  FIXTURE_PATH).and_return(true)
104
- Action.run({dsym_path: FIXTURE_PATH,
105
- upload_url: "http://myserver.example.com"})
184
+ run_with({dsym_path: FIXTURE_PATH, upload_url: "http://myserver.example.com"})
106
185
  end
107
186
  end
108
187
 
@@ -112,8 +191,9 @@ describe Action do
112
191
  expect(Kernel).to receive(:system).with(Action::UPLOAD_SCRIPT_PATH,
113
192
  "--silent",
114
193
  "--symbol-maps", path,
194
+ "--project-root", Dir::pwd,
115
195
  FIXTURE_PATH).and_return(true)
116
- Action.run({dsym_path: FIXTURE_PATH, symbol_maps_path: path})
196
+ run_with({dsym_path: FIXTURE_PATH, symbol_maps_path: path})
117
197
  end
118
198
  end
119
199
  end
@@ -2,8 +2,11 @@
2
2
  <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
3
3
  <plist version="1.0">
4
4
  <dict>
5
- <key>BugsnagAPIKey</key>
6
- <string>other-key</string>
5
+ <key>bugsnag</key>
6
+ <dict>
7
+ <key>apiKey</key>
8
+ <string>12345678901234567890123456789AAA</string>
9
+ </dict>
7
10
  <key>CFBundleDevelopmentRegion</key>
8
11
  <string>$(DEVELOPMENT_LANGUAGE)</string>
9
12
  <key>CFBundleExecutable</key>
@@ -17,9 +20,9 @@
17
20
  <key>CFBundlePackageType</key>
18
21
  <string>APPL</string>
19
22
  <key>CFBundleShortVersionString</key>
20
- <string>3.0-other</string>
23
+ <string>2.0-other</string>
21
24
  <key>CFBundleVersion</key>
22
- <string>56</string>
25
+ <string>22</string>
23
26
  <key>LSRequiresIPhoneOS</key>
24
27
  <true/>
25
28
  <key>UILaunchStoryboardName</key>
@@ -45,5 +48,3 @@
45
48
  </array>
46
49
  </dict>
47
50
  </plist>
48
-
49
-
@@ -2,8 +2,11 @@
2
2
  <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
3
3
  <plist version="1.0">
4
4
  <dict>
5
- <key>BugsnagAPIKey</key>
6
- <string>project-key</string>
5
+ <key>bugsnag</key>
6
+ <dict>
7
+ <key>apiKey</key>
8
+ <string>12345678901234567890123456789DDD</string>
9
+ </dict>
7
10
  <key>CFBundleDevelopmentRegion</key>
8
11
  <string>$(DEVELOPMENT_LANGUAGE)</string>
9
12
  <key>CFBundleExecutable</key>
@@ -17,9 +20,9 @@
17
20
  <key>CFBundlePackageType</key>
18
21
  <string>APPL</string>
19
22
  <key>CFBundleShortVersionString</key>
20
- <string>2.0-project</string>
23
+ <string>3.0-project</string>
21
24
  <key>CFBundleVersion</key>
22
- <string>6</string>
25
+ <string>33</string>
23
26
  <key>LSRequiresIPhoneOS</key>
24
27
  <true/>
25
28
  <key>UILaunchStoryboardName</key>
@@ -45,4 +48,3 @@
45
48
  </array>
46
49
  </dict>
47
50
  </plist>
48
-
@@ -2,8 +2,11 @@
2
2
  <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
3
3
  <plist version="1.0">
4
4
  <dict>
5
- <key>BugsnagAPIKey</key>
6
- <string>test-key</string>
5
+ <key>bugsnag</key>
6
+ <dict>
7
+ <key>apiKey</key>
8
+ <string>12345678901234567890123456789EEE</string>
9
+ </dict>
7
10
  <key>CFBundleDevelopmentRegion</key>
8
11
  <string>$(DEVELOPMENT_LANGUAGE)</string>
9
12
  <key>CFBundleExecutable</key>
@@ -45,4 +48,3 @@
45
48
  </array>
46
49
  </dict>
47
50
  </plist>
48
-
@@ -0,0 +1,47 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
3
+ <plist version="1.0">
4
+ <dict>
5
+ <key>BugsnagAPIKey</key>
6
+ <string>12345678901234567890123456789BBB</string>
7
+ <key>CFBundleDevelopmentRegion</key>
8
+ <string>$(DEVELOPMENT_LANGUAGE)</string>
9
+ <key>CFBundleExecutable</key>
10
+ <string>$(EXECUTABLE_NAME)</string>
11
+ <key>CFBundleIdentifier</key>
12
+ <string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
13
+ <key>CFBundleInfoDictionaryVersion</key>
14
+ <string>6.0</string>
15
+ <key>CFBundleName</key>
16
+ <string>$(PRODUCT_NAME)</string>
17
+ <key>CFBundlePackageType</key>
18
+ <string>APPL</string>
19
+ <key>CFBundleShortVersionString</key>
20
+ <string>4.0-project</string>
21
+ <key>CFBundleVersion</key>
22
+ <string>44</string>
23
+ <key>LSRequiresIPhoneOS</key>
24
+ <true/>
25
+ <key>UILaunchStoryboardName</key>
26
+ <string>LaunchScreen</string>
27
+ <key>UIMainStoryboardFile</key>
28
+ <string>Main</string>
29
+ <key>UIRequiredDeviceCapabilities</key>
30
+ <array>
31
+ <string>armv7</string>
32
+ </array>
33
+ <key>UISupportedInterfaceOrientations</key>
34
+ <array>
35
+ <string>UIInterfaceOrientationPortrait</string>
36
+ <string>UIInterfaceOrientationLandscapeLeft</string>
37
+ <string>UIInterfaceOrientationLandscapeRight</string>
38
+ </array>
39
+ <key>UISupportedInterfaceOrientations~ipad</key>
40
+ <array>
41
+ <string>UIInterfaceOrientationPortrait</string>
42
+ <string>UIInterfaceOrientationPortraitUpsideDown</string>
43
+ <string>UIInterfaceOrientationLandscapeLeft</string>
44
+ <string>UIInterfaceOrientationLandscapeRight</string>
45
+ </array>
46
+ </dict>
47
+ </plist>
@@ -5,53 +5,66 @@ require 'fastlane/actions/get_info_plist_value'
5
5
  BuildAction = Fastlane::Actions::SendBuildToBugsnagAction
6
6
 
7
7
  describe BuildAction do
8
- def load_default_opts
9
- BuildAction.available_options.map do |x|
10
- [x.key, x.default_value]
11
- end.to_h
8
+ def run_with args
9
+ BuildAction.run(Fastlane::ConfigurationHelper.parse(BuildAction, args))
12
10
  end
13
11
 
14
12
  context 'building an iOS project' do
15
13
  it 'detects default Info.plist file excluding test dirs' do
16
14
  expect(BuildAction).to receive(:send_notification) do |url, body|
17
15
  payload = ::JSON.load(body)
18
- expect(payload['appVersion']).to eq '3.0-other'
19
- expect(payload['appBundleVersion']).to eq '56'
20
- expect(payload['apiKey']).to eq 'other-key'
16
+ expect(payload['appVersion']).to eq '2.0-other'
17
+ expect(payload['appBundleVersion']).to eq '22'
18
+ expect(payload['apiKey']).to eq '12345678901234567890123456789AAA'
21
19
  end
22
20
 
23
21
  Dir.chdir(File.join(FIXTURE_PATH, 'ios_proj')) do
24
- BuildAction.run(load_default_opts)
22
+ run_with({})
23
+ end
24
+ end
25
+
26
+ it 'reads api key from legacy location' do
27
+ # the API key is now in `bugsnag.apiKey`, it used to be in 'BugsnagAPIKey',
28
+ # test this can be extracted correctly from the `ios_proj_legacy`
29
+ expect(BuildAction).to receive(:send_notification) do |url, body|
30
+ payload = ::JSON.load(body)
31
+ expect(payload['appVersion']).to eq '4.0-project'
32
+ expect(payload['appBundleVersion']).to eq '44'
33
+ expect(payload['apiKey']).to eq '12345678901234567890123456789BBB'
34
+ end
35
+
36
+ Dir.chdir(File.join(FIXTURE_PATH, 'ios_proj_legacy')) do
37
+ run_with({})
25
38
  end
26
39
  end
27
40
 
28
41
  context 'using default config_file option' do
29
- context 'override API key option' do
42
+ context 'override API key from config' do
30
43
  it 'reads API key from the api_key option' do
31
44
  expect(BuildAction).to receive(:send_notification) do |url, body|
32
45
  payload = ::JSON.load(body)
33
- expect(payload['apiKey']).to eq 'baobab'
46
+ expect(payload['apiKey']).to eq '12345678901234567890123456789FFF'
34
47
  end
35
48
 
36
49
  Dir.chdir(File.join(FIXTURE_PATH, 'ios_proj')) do
37
- BuildAction.run(load_default_opts.merge({
38
- api_key: 'baobab'
39
- }))
50
+ run_with({
51
+ api_key: '12345678901234567890123456789FFF'
52
+ })
40
53
  end
41
54
  end
42
55
 
43
- it 'reads version info from the config file' do
56
+ it 'uses input versions from options' do
44
57
  expect(BuildAction).to receive(:send_notification) do |url, body|
45
58
  payload = ::JSON.load(body)
46
- expect(payload['appVersion']).to eq '4.0.0'
47
- expect(payload['appBundleVersion']).to eq '400'
59
+ expect(payload['appVersion']).to eq '8.0.0'
60
+ expect(payload['appBundleVersion']).to eq '800'
48
61
  end
49
62
 
50
63
  Dir.chdir(File.join(FIXTURE_PATH, 'ios_proj')) do
51
- BuildAction.run(load_default_opts.merge({
52
- app_version: '4.0.0',
53
- ios_bundle_version: '400'
54
- }))
64
+ run_with({
65
+ app_version: '8.0.0',
66
+ ios_bundle_version: '800'
67
+ })
55
68
  end
56
69
  end
57
70
  end
@@ -61,46 +74,49 @@ describe BuildAction do
61
74
  it 'reads API key and version info from the config file' do
62
75
  expect(BuildAction).to receive(:send_notification) do |url, body|
63
76
  payload = ::JSON.load(body)
64
- expect(payload['appVersion']).to eq '2.0-project'
65
- expect(payload['appBundleVersion']).to eq '6'
66
- expect(payload['apiKey']).to eq 'project-key'
77
+ expect(payload['appVersion']).to eq '3.0-project'
78
+ expect(payload['appBundleVersion']).to eq '33'
79
+ expect(payload['apiKey']).to eq '12345678901234567890123456789DDD'
67
80
  end
68
81
 
69
82
  Dir.chdir(File.join(FIXTURE_PATH, 'ios_proj')) do
70
- BuildAction.run(load_default_opts.merge({
83
+ run_with({
71
84
  config_file: File.join('Project', 'Info.plist')
72
- }))
85
+ })
73
86
  end
74
87
  end
75
88
 
76
- context 'override API key option' do
77
- it 'reads API key from the config file' do
89
+ context 'override API key, and config file' do
90
+ it 'uses the input api_key to override a non default config' do
78
91
  expect(BuildAction).to receive(:send_notification) do |url, body|
79
92
  payload = ::JSON.load(body)
80
- expect(payload['apiKey']).to eq 'project-key'
93
+ expect(payload['appVersion']).to eq '3.0-project'
94
+ expect(payload['appBundleVersion']).to eq '33'
95
+ expect(payload['apiKey']).to eq '12345678901234567890123456789EEE'
81
96
  end
82
97
 
83
98
  Dir.chdir(File.join(FIXTURE_PATH, 'ios_proj')) do
84
- BuildAction.run(load_default_opts.merge({
99
+ run_with({
85
100
  config_file: File.join('Project', 'Info.plist'),
86
- api_key: 'baobab'
87
- }))
101
+ api_key: '12345678901234567890123456789EEE'
102
+ })
88
103
  end
89
104
  end
90
105
 
91
- it 'reads version info from the config file' do
106
+ it 'uses the input versions to override a non default config' do
92
107
  expect(BuildAction).to receive(:send_notification) do |url, body|
93
108
  payload = ::JSON.load(body)
94
- expect(payload['appVersion']).to eq '2.0-project'
95
- expect(payload['appBundleVersion']).to eq '6'
109
+ expect(payload['appVersion']).to eq '9.0.0'
110
+ expect(payload['appBundleVersion']).to eq '900'
111
+ expect(payload['apiKey']).to eq '12345678901234567890123456789DDD'
96
112
  end
97
113
 
98
114
  Dir.chdir(File.join(FIXTURE_PATH, 'ios_proj')) do
99
- BuildAction.run(load_default_opts.merge({
115
+ run_with({
100
116
  config_file: File.join('Project', 'Info.plist'),
101
- app_version: '4.0.0',
102
- ios_bundle_version: '400'
103
- }))
117
+ app_version: '9.0.0',
118
+ ios_bundle_version: '900'
119
+ })
104
120
  end
105
121
  end
106
122
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: fastlane-plugin-bugsnag
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.3.3
4
+ version: 2.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Delisa Mason
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2018-07-11 00:00:00.000000000 Z
11
+ date: 2020-08-13 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: xml-simple
@@ -143,12 +143,13 @@ files:
143
143
  - spec/fixtures/ios_proj/FirstRealFolder/Info.plist
144
144
  - spec/fixtures/ios_proj/Project/Info.plist
145
145
  - spec/fixtures/ios_proj/aaTests/Info.plist
146
+ - spec/fixtures/ios_proj_legacy/Project/Info.plist
146
147
  - spec/fixtures/more_files.zip
147
148
  - spec/fixtures/stuff/app.dSYM/Contents/Resources/DWARF/app
148
149
  - spec/fixtures/stuff/app2.dSYM/Contents/Resources/DWARF/app2
149
150
  - spec/send_build_to_bugsnag_spec.rb
150
151
  - spec/spec_helper.rb
151
- homepage: https://github.com/bugsnag/bugsnag-upload
152
+ homepage: https://github.com/bugsnag/bugsnag-dsym-upload
152
153
  licenses:
153
154
  - MIT
154
155
  metadata: {}
@@ -167,23 +168,23 @@ required_rubygems_version: !ruby/object:Gem::Requirement
167
168
  - !ruby/object:Gem::Version
168
169
  version: '0'
169
170
  requirements: []
170
- rubyforge_project:
171
- rubygems_version: 2.7.7
171
+ rubygems_version: 3.0.3
172
172
  signing_key:
173
173
  specification_version: 4
174
174
  summary: Uploads dSYM files to Bugsnag
175
175
  test_files:
176
+ - spec/spec_helper.rb
176
177
  - spec/bugsnag_upload_dsym_action_spec.rb
178
+ - spec/send_build_to_bugsnag_spec.rb
179
+ - spec/fixtures/ios_proj_legacy/Project/Info.plist
180
+ - spec/fixtures/more_files.zip
177
181
  - spec/fixtures/BCSymbolMaps/real.bcsymbolmap
178
- - spec/fixtures/dSYMs/app.dSYM/Contents/Resources/DWARF/app
179
- - spec/fixtures/dSYMs/app2.dSYM/Contents/Resources/DWARF/app2
180
- - spec/fixtures/files.zip
181
- - spec/fixtures/invalid_file
182
- - spec/fixtures/ios_proj/aaTests/Info.plist
183
182
  - spec/fixtures/ios_proj/FirstRealFolder/Info.plist
183
+ - spec/fixtures/ios_proj/aaTests/Info.plist
184
184
  - spec/fixtures/ios_proj/Project/Info.plist
185
- - spec/fixtures/more_files.zip
186
- - spec/fixtures/stuff/app.dSYM/Contents/Resources/DWARF/app
187
185
  - spec/fixtures/stuff/app2.dSYM/Contents/Resources/DWARF/app2
188
- - spec/send_build_to_bugsnag_spec.rb
189
- - spec/spec_helper.rb
186
+ - spec/fixtures/stuff/app.dSYM/Contents/Resources/DWARF/app
187
+ - spec/fixtures/invalid_file
188
+ - spec/fixtures/files.zip
189
+ - spec/fixtures/dSYMs/app2.dSYM/Contents/Resources/DWARF/app2
190
+ - spec/fixtures/dSYMs/app.dSYM/Contents/Resources/DWARF/app
@@ -1 +0,0 @@
1
- ./../../LICENSE.txt
@@ -1 +0,0 @@
1
- ./../../bin/bugsnag-dsym-upload