fastlane-plugin-waldo 1.2.2 → 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
- SHA1:
3
- metadata.gz: 056a17e44467bd00b33113d8cf52829a6b849c29
4
- data.tar.gz: 38c5bdbe260672b4ad39c59fdcbc3498118350e5
2
+ SHA256:
3
+ metadata.gz: 2fe9bf2266ddb25b5f97e60900275c9619e8dedd8723e1ac14bbb6c37939ae2a
4
+ data.tar.gz: dae94679633cfcafc9a71bf5e683ed9097af91619df4443d00b6bf879b927089
5
5
  SHA512:
6
- metadata.gz: 58a2fc1db402ef97db5a7215fb23d5ee61ad017cbfb4d963e8c661ded128e4894da651ba783911f3fd5d0459a68a72f7ec5756d3a009111d460439d450aa3f08
7
- data.tar.gz: bdb76754572891b23d5ad91a5627e1245ad9a0acae7eb157903c61e5873a1f9fbc70d01fae55c51dc538b5d55d9c2a3097df9e688c2bbedba2d3f20da1289fe8
6
+ metadata.gz: e93282d73cf4d764db41e40727265447b1b5feb7830bda0b2d7d4643826595a748f186336efa3cf5f30a890e637054a042283f78edd865e8c5cb569608b1db27
7
+ data.tar.gz: e22adde22bef309cd6cb43ed6b9bd58b80f3ff43785c0c28cfa04b1bf70d5d111f78dea00b104df6bea3105b8023854fcbf101570cd0e5e520dd1c3b4f104efa
data/README.md CHANGED
@@ -22,26 +22,6 @@ which allows you to upload an iOS or Android build to Waldo for processing.
22
22
  To get started, first obtain an upload token from Waldo for your app. These are
23
23
  used to authenticate with the Waldo backend on each call.
24
24
 
25
- ### Uploading an iOS Device Build
26
-
27
- Build a new IPA for your app. If you use `gym` (aka `build_ios_app`) to build
28
- your IPA, `waldo` will automatically find and upload the generated IPA.
29
-
30
- ```ruby
31
- gym(export_method: 'development') # or 'ad-hoc'
32
- waldo(upload_token: '0123456789abcdef0123456789abcdef')
33
- ```
34
-
35
- > **Note:** You _must_ specify the Waldo upload token.
36
-
37
- If you do _not_ use `gym` to build your IPA, you will need to explicitly
38
- specify the IPA path to `waldo`:
39
-
40
- ```ruby
41
- waldo(ipa_path: '/path/to/YourApp.ipa',
42
- upload_token: '0123456789abcdef0123456789abcdef')
43
- ```
44
-
45
25
  ### Uploading an iOS Simulator Build
46
26
 
47
27
  Create a new simulator build for your app.
@@ -58,19 +38,53 @@ gym(configuration: 'Release',
58
38
  destination: 'generic/platform=iOS Simulator')
59
39
  ```
60
40
 
61
- You can then find your app relative to the derived data path in the
62
- `./Build/Products/Release-iphonesimulator` directory.
41
+ You can then find your app (and associated symbols) relative to the derived
42
+ data path:
43
+
44
+ ```ruby
45
+ app_path = File.join(derived_data_path,
46
+ 'Build',
47
+ 'Products',
48
+ 'ReleaseSim-iphonesimulator',
49
+ 'YourApp.app')
50
+ ```
63
51
 
64
52
  Regardless of how you create the actual simulator build for your app, the
65
53
  upload itself is very simple:
66
54
 
67
55
  ```ruby
68
- waldo(app_path: '/path/to/YourApp.app',
69
- upload_token: '0123456789abcdef0123456789abcdef')
56
+ waldo(upload_token: '0123456789abcdef0123456789abcdef',
57
+ app_path: '/path/to/YourApp.app',
58
+ include_symbols: true)
59
+ ```
60
+
61
+ > **Note:** You _must_ specify _both_ the Waldo upload token _and_ the path of
62
+ > the `.app`. The `include_symbols` parameter is optional but we highly
63
+ > recommend supplying it.
64
+
65
+ ### Uploading an iOS Device Build
66
+
67
+ Build a new IPA for your app. If you use `gym` (aka `build_ios_app`) to build
68
+ your IPA, `waldo` will automatically find and upload the generated IPA.
69
+
70
+ ```ruby
71
+ gym(export_method: 'ad-hoc') # or 'development'
72
+
73
+ waldo(upload_token: '0123456789abcdef0123456789abcdef',
74
+ dsym_path: lane_context[SharedValues::DSYM_OUTPUT_PATH])
70
75
  ```
71
76
 
72
- > **Note:** You _must_ specify _both_ the path of the `.app` _and_ the Waldo
73
- > upload token.
77
+ > **Note:** You _must_ specify the Waldo upload token. The `dsym_path`
78
+ > parameter is optional but we highly recommend supplying it.
79
+
80
+ If you do _not_ use `gym` to build your IPA, you will need to explicitly
81
+ specify the IPA path to `waldo`:
82
+
83
+ ```ruby
84
+ waldo(upload_token: '0123456789abcdef0123456789abcdef',
85
+ ipa_path: '/path/to/YourApp.ipa',
86
+ dsym_path: '/path/to/YourApp.app.dSYM.zip')
87
+ ```
74
88
 
75
89
  ### Uploading an Android Build
76
90
 
@@ -80,6 +94,7 @@ will automatically find and upload the generated APK.
80
94
  ```ruby
81
95
  gradle(task: 'assemble',
82
96
  build_type: 'Release')
97
+
83
98
  waldo(upload_token: '0123456789abcdef0123456789abcdef')
84
99
  ```
85
100
 
@@ -89,8 +104,8 @@ If you do _not_ use `gradle` to build your APK, you will need to explicitly
89
104
  specify the APK path to `waldo`:
90
105
 
91
106
  ```ruby
92
- waldo(apk_path: '/path/to/YourApp.apk',
93
- upload_token: '0123456789abcdef0123456789abcdef')
107
+ waldo(upload_token: '0123456789abcdef0123456789abcdef',
108
+ apk_path: '/path/to/YourApp.apk')
94
109
  ```
95
110
 
96
111
  ## Issues and Feedback
@@ -4,12 +4,10 @@ module Fastlane
4
4
  def self.run(params)
5
5
  mparams = Helper::WaldoHelper.filter_parameters(params)
6
6
 
7
- return unless Helper::WaldoHelper.validate_parameters(mparams)
8
-
9
7
  FastlaneCore::PrintTable.print_values(config: mparams,
10
8
  title: "Summary for waldo #{Fastlane::Waldo::VERSION.to_s}")
11
9
 
12
- Helper::WaldoHelper.upload_build
10
+ Helper::WaldoHelper.upload_build_with_symbols(mparams)
13
11
  end
14
12
 
15
13
  def self.authors
@@ -39,6 +37,16 @@ module Fastlane
39
37
  default_value: Actions.lane_context[Actions::SharedValues::IPA_OUTPUT_PATH] || ipa_path_default,
40
38
  default_value_dynamic: true,
41
39
  optional: true),
40
+ FastlaneCore::ConfigItem.new(key: :dsym_path,
41
+ env_name: 'WALDO_DSYM_PATH',
42
+ description: 'Path to your dSYM file(s)',
43
+ optional: true),
44
+ FastlaneCore::ConfigItem.new(key: :include_symbols,
45
+ env_name: 'WALDO_INCLUDE_SYMBOLS',
46
+ description: 'Include symbols in upload if true',
47
+ optional: true,
48
+ default_value: false,
49
+ is_string: false),
42
50
  # Android-specific
43
51
  FastlaneCore::ConfigItem.new(key: :apk_path,
44
52
  env_name: 'WALDO_APK_PATH',
@@ -0,0 +1,672 @@
1
+ #!/usr/bin/env bash
2
+
3
+ set -eu -o pipefail
4
+
5
+ waldo_api_build_endpoint=${WALDO_API_BUILD_ENDPOINT:-https://api.waldo.io/versions}
6
+ waldo_api_error_endpoint=${WALDO_API_ERROR_ENDPOINT:-https://api.waldo.io/uploadError}
7
+ waldo_api_symbols_endpoint=${WALDO_API_SYMBOLS_ENDPOINT:-https://api.waldo.io/versions/__ID__/symbols}
8
+ waldo_user_agent_override=${WALDO_USER_AGENT_OVERRIDE:-}
9
+
10
+ waldo_cli_version="1.6.6"
11
+
12
+ waldo_build_flavor=""
13
+ waldo_build_path=""
14
+ waldo_build_payload_path=""
15
+ waldo_build_suffix=""
16
+ waldo_build_upload_id=""
17
+ waldo_extra_args="--show-error --silent"
18
+ waldo_history=""
19
+ waldo_history_error=""
20
+ waldo_include_symbols=false
21
+ waldo_platform=""
22
+ waldo_symbols_path=""
23
+ waldo_symbols_payload_path=""
24
+ waldo_symbols_suffix=""
25
+ waldo_upload_token=""
26
+ waldo_variant_name=""
27
+ waldo_working_path=""
28
+
29
+ function abs_path() {
30
+ local _rel_path=$1
31
+
32
+ [[ -n $_rel_path ]] || _rel_path="."
33
+
34
+ case "$_rel_path" in
35
+ .) pwd ;;
36
+ ..) (unset CDPATH && cd .. &>/dev/null && pwd) ;;
37
+ /*) echo $_rel_path ;;
38
+ *) local _dirname=$(dirname "$_rel_path")
39
+
40
+ _dirname=$(unset CDPATH && cd "$_dirname" &>/dev/null && pwd)
41
+
42
+ if [[ -n $_dirname ]]; then
43
+ echo ${_dirname}/$(basename "$_rel_path")
44
+ else
45
+ echo $_rel_path
46
+ fi
47
+ ;;
48
+ esac
49
+ }
50
+
51
+ function check_build_path() {
52
+ [[ -n $waldo_build_path ]] || fail_usage "Missing required argument: ‘path’"
53
+
54
+ waldo_build_path=$(abs_path "$waldo_build_path")
55
+ waldo_build_suffix=${waldo_build_path##*.}
56
+
57
+ case $waldo_build_suffix in
58
+ apk) waldo_build_flavor="Android" ;;
59
+ app|ipa) waldo_build_flavor="iOS" ;;
60
+ *) fail "File extension of build at ‘${waldo_build_path}’ is not recognized" ;;
61
+ esac
62
+ }
63
+
64
+ function check_build_status() {
65
+ local _response=$1
66
+
67
+ local _status_regex='"status":([0-9]+)'
68
+
69
+ if [[ $_response =~ $_status_regex ]]; then
70
+ local _status=${BASH_REMATCH[1]}
71
+
72
+ if (( $_status == 401 )); then
73
+ fail "Upload token is invalid or missing!"
74
+ elif (( $_status < 200 || $_status > 299 )); then
75
+ fail "Unable to upload build to Waldo, HTTP status: $_status"
76
+ fi
77
+ fi
78
+
79
+ local _id_regex='"id":"(appv-[0-9a-f]+)"'
80
+
81
+ if [[ $_response =~ $_id_regex ]]; then
82
+ waldo_build_upload_id=${BASH_REMATCH[1]}
83
+ fi
84
+ }
85
+
86
+ function check_history() {
87
+ if [[ -z $(which base64) ]]; then
88
+ waldo_history_error="noBase64CommandFound"
89
+ elif [[ -z $(which git) ]]; then
90
+ waldo_history_error="noGitCommandFound"
91
+ elif [[ -z $(which grep) ]]; then
92
+ waldo_history_error="noGrepCommandFound"
93
+ elif [[ -z $(which sed) ]]; then
94
+ waldo_history_error="noSedCommandFound"
95
+ elif [[ -z $(which tr) ]]; then
96
+ waldo_history_error="noTrCommandFound"
97
+ elif ! git rev-parse >& /dev/null; then
98
+ waldo_history_error="notGitRepository"
99
+ else
100
+ waldo_history=$(get_history)
101
+ fi
102
+ }
103
+
104
+ function check_platform() {
105
+ if [[ -z $(which curl) ]]; then
106
+ fail "No ‘curl’ command found"
107
+ fi
108
+ }
109
+
110
+ function check_symbols_path() {
111
+ case $waldo_build_suffix in
112
+ app)
113
+ if [[ -z $waldo_symbols_path && $waldo_include_symbols == true ]]; then
114
+ waldo_symbols_path=$(find_symbols_path)
115
+ fi
116
+ ;;
117
+ ipa) ;;
118
+ *) waldo_symbols_path="" ;; # not applicable
119
+ esac
120
+
121
+ [[ -n $waldo_symbols_path ]] || return 0
122
+
123
+ waldo_symbols_path=$(abs_path "$waldo_symbols_path")
124
+ waldo_symbols_suffix=${waldo_symbols_path##*.}
125
+
126
+ case $waldo_symbols_suffix in
127
+ dSYM|xcarchive|zip) ;; # OK
128
+ *) fail "File extension of symbols at ‘${waldo_symbols_path}’ is not recognized" ;;
129
+ esac
130
+ }
131
+
132
+ function check_symbols_status() {
133
+ local _response=$1
134
+
135
+ local _status_regex='"status":([0-9]+)'
136
+
137
+ if [[ $_response =~ $_status_regex ]]; then
138
+ local _status=${BASH_REMATCH[1]}
139
+
140
+ if (( $_status == 401 )); then
141
+ fail "Upload token is invalid or missing!"
142
+ elif (( $_status < 200 || $_status > 299 )); then
143
+ fail "Unable to upload symbols to Waldo, HTTP status: $_status"
144
+ fi
145
+ fi
146
+ }
147
+
148
+ function check_upload_token() {
149
+ [[ -n $waldo_upload_token ]] || waldo_upload_token=${WALDO_UPLOAD_TOKEN:-}
150
+ [[ -n $waldo_upload_token ]] || fail_usage "Missing required option: ‘--upload_token’"
151
+ }
152
+
153
+ function check_variant_name() {
154
+ [[ -n $waldo_variant_name ]] || waldo_variant_name=${WALDO_VARIANT_NAME:-}
155
+ }
156
+
157
+ function convert_sha() {
158
+ local _full_sha=$1
159
+ local _full_name=$(git name-rev --refs='heads/*' --name-only "$_full_sha")
160
+ local _abbr_sha=${_full_sha:0:7}
161
+ local _abbr_name=$_full_name
162
+ local _prefix="remotes/origin/"
163
+
164
+ if [[ ${_full_name:0:${#_prefix}} == $_prefix ]]; then
165
+ _abbr_name=${_full_name#$_prefix}
166
+ else
167
+ _abbr_name="local:${_full_name}"
168
+ fi
169
+
170
+ echo "${_abbr_sha}-${_abbr_name}"
171
+ }
172
+
173
+ function convert_shas() {
174
+ local _list=
175
+
176
+ while (( $# )); do
177
+ local _item=$(convert_sha "$1")
178
+
179
+ _list+=",\"${_item}\""
180
+
181
+ shift
182
+ done
183
+
184
+ echo ${_list#?}
185
+ }
186
+
187
+ function create_build_payload() {
188
+ local _parent_path=$(dirname "$waldo_build_path")
189
+ local _build_name=$(basename "$waldo_build_path")
190
+
191
+ case $waldo_build_suffix in
192
+ app)
193
+ ([[ -d $waldo_build_path && -r $waldo_build_path ]]) \
194
+ || fail "Unable to read build at ‘${waldo_build_path}’"
195
+
196
+ if [[ -z $(which zip) ]]; then
197
+ fail "No ‘zip’ command found"
198
+ fi
199
+
200
+ waldo_build_payload_path="$waldo_working_path"/"$_build_name".zip
201
+
202
+ (cd "$_parent_path" &>/dev/null && zip -qry "$waldo_build_payload_path" "$_build_name") || return
203
+ ;;
204
+
205
+ *)
206
+ ([[ -f $waldo_build_path && -r $waldo_build_path ]]) \
207
+ || fail "Unable to read build at ‘${waldo_build_path}’"
208
+
209
+ waldo_build_payload_path=$waldo_build_path
210
+ ;;
211
+ esac
212
+ }
213
+
214
+ function create_symbols_payload() {
215
+ [[ -n $waldo_symbols_path ]] || return 0
216
+
217
+ local _parent_path=$(dirname "$waldo_symbols_path")
218
+ local _symbols_name=$(basename "$waldo_symbols_path")
219
+
220
+ case $waldo_symbols_suffix in
221
+ dSYM)
222
+ ([[ -d $waldo_symbols_path && -r $waldo_symbols_path ]]) \
223
+ || fail "Unable to read symbols at ‘${waldo_symbols_path}’"
224
+
225
+ if [[ -z $(which zip) ]]; then
226
+ fail "No ‘zip’ command found"
227
+ fi
228
+
229
+ waldo_symbols_payload_path="$waldo_working_path"/"$_symbols_name".zip
230
+
231
+ (cd "$_parent_path" &>/dev/null && zip -qry "$waldo_symbols_payload_path" "$_symbols_name") || return
232
+ ;;
233
+
234
+ xcarchive)
235
+ ([[ -d $waldo_symbols_path && -r $waldo_symbols_path ]]) \
236
+ || fail "Unable to read symbols at ‘${waldo_symbols_path}’"
237
+
238
+ if [[ -z $(which zip) ]]; then
239
+ fail "No ‘zip’ command found"
240
+ fi
241
+
242
+ local _tmp_symbols_path="$waldo_working_path"/"$_symbols_name"
243
+
244
+ mkdir -p "$_tmp_symbols_path"
245
+
246
+ cp -r "$waldo_symbols_path"/BCSymbolMaps "$_tmp_symbols_path"
247
+ cp -r "$waldo_symbols_path"/dSYMs "$_tmp_symbols_path"
248
+
249
+ waldo_symbols_payload_path="$_tmp_symbols_path".zip
250
+
251
+ (cd "$waldo_working_path" &>/dev/null && zip -qry "$waldo_symbols_payload_path" "$_symbols_name") || return
252
+ ;;
253
+
254
+ *)
255
+ ([[ -f $waldo_symbols_path && -r $waldo_symbols_path ]]) \
256
+ || fail "Unable to read symbols at ‘${waldo_symbols_path}’"
257
+
258
+ waldo_symbols_payload_path=$waldo_symbols_path
259
+ ;;
260
+ esac
261
+ }
262
+
263
+ function create_working_path() {
264
+ waldo_working_path=/tmp/WaldoCLI-$$
265
+
266
+ rm -rf "$waldo_working_path"
267
+ mkdir -p "$waldo_working_path"
268
+ }
269
+
270
+ function curl_upload_build() {
271
+ local _output_path="$1"
272
+ local _authorization=$(get_authorization)
273
+ local _content_type=$(get_build_content_type)
274
+ local _user_agent=$(get_user_agent)
275
+ local _url=$(make_build_url)
276
+
277
+ curl $waldo_extra_args \
278
+ --data-binary @"$waldo_build_payload_path" \
279
+ --header "Authorization: $_authorization" \
280
+ --header "Content-Type: $_content_type" \
281
+ --header "User-Agent: $_user_agent" \
282
+ --output "$_output_path" \
283
+ "$_url"
284
+
285
+ local _curl_status=$?
286
+
287
+ if (( $_curl_status != 0 )); then
288
+ fail "Unable to upload build to Waldo, curl error: ${_curl_status}, url: ${_url}"
289
+ fi
290
+ }
291
+
292
+ function curl_upload_error() {
293
+ local _message=$(json_escape "$1")
294
+ local _ci=$(get_ci)
295
+ local _authorization=$(get_authorization)
296
+ local _content_type=$(get_error_content_type)
297
+ local _user_agent=$(get_user_agent)
298
+ local _url=$(make_error_url)
299
+
300
+ curl --silent \
301
+ --data "{\"message\":\"${_message}\",\"ci\":\"${_ci}\"}" \
302
+ --header "Authorization: $_authorization" \
303
+ --header "Content-Type: $_content_type" \
304
+ --header "User-Agent: $_user_agent" \
305
+ "$_url" &>/dev/null
306
+ }
307
+
308
+ function curl_upload_symbols() {
309
+ local _output_path="$1"
310
+ local _authorization=$(get_authorization)
311
+ local _content_type=$(get_symbols_content_type)
312
+ local _user_agent=$(get_user_agent)
313
+ local _url=$(make_symbols_url)
314
+
315
+ curl $waldo_extra_args \
316
+ --data-binary @"$waldo_symbols_payload_path" \
317
+ --header "Authorization: $_authorization" \
318
+ --header "Content-Type: $_content_type" \
319
+ --header "User-Agent: $_user_agent" \
320
+ --output "$_output_path" \
321
+ "$_url"
322
+
323
+ local _curl_status=$?
324
+
325
+ if (( $_curl_status != 0 )); then
326
+ fail "Unable to upload symbols to Waldo, curl error: ${_curl_status}, url: ${_url}"
327
+ fi
328
+ }
329
+
330
+ function delete_working_path() {
331
+ if [[ -n $waldo_working_path ]]; then
332
+ rm -rf "$waldo_working_path"
333
+ fi
334
+ }
335
+
336
+ function display_summary() {
337
+ echo ""
338
+ echo "Build path: $(summarize "$waldo_build_path")"
339
+ echo "Symbols path: $(summarize "$waldo_symbols_path")"
340
+ echo "Variant name: $(summarize "$waldo_variant_name")"
341
+ echo "Upload token: $(summarize_secure "$waldo_upload_token")"
342
+ echo ""
343
+
344
+ if [[ $waldo_extra_args == "--verbose" ]]; then
345
+ echo "Build payload path: $(summarize "$waldo_build_payload_path")"
346
+ echo "Symbols payload path: $(summarize "$waldo_symbols_payload_path")"
347
+ echo ""
348
+ fi
349
+ }
350
+
351
+ function display_usage() {
352
+ cat <<EOF
353
+
354
+ OVERVIEW: Upload build to Waldo
355
+
356
+ USAGE: waldo [options] <build-path> [<symbols-path>]
357
+
358
+ OPTIONS:
359
+
360
+ --help Display available options
361
+ --include_symbols Include symbols with the build upload
362
+ --upload_token <value> Waldo upload token (overrides WALDO_UPLOAD_TOKEN)
363
+ --variant_name <value> Waldo variant name (overrides WALDO_VARIANT_NAME)
364
+ --verbose Display extra verbiage
365
+ EOF
366
+ }
367
+
368
+ function display_version() {
369
+ waldo_platform=$(get_platform)
370
+
371
+ echo "Waldo CLI $waldo_cli_version ($waldo_platform)"
372
+ }
373
+
374
+ function fail() {
375
+ local _message="waldo: $1"
376
+
377
+ if [[ -n $waldo_upload_token ]]; then
378
+ curl_upload_error "$1"
379
+
380
+ local _curl_status=$?
381
+
382
+ if (( $_curl_status == 0)); then
383
+ _message+=" -- Waldo team has been informed"
384
+ fi
385
+ fi
386
+
387
+ echo "" # flush stdout
388
+ echo "$_message" 1>&2
389
+ exit 1
390
+ }
391
+
392
+ function fail_usage() {
393
+ [[ -z $waldo_upload_token ]] || curl_upload_error "$1"
394
+
395
+ echo "" # flush stdout
396
+ echo "waldo: $1" 1>&2
397
+ display_usage
398
+ exit 1
399
+ }
400
+
401
+ function find_symbols_path() {
402
+ if [[ -e ${waldo_build_path}.dSYM.zip ]]; then
403
+ echo "${waldo_build_path}.dSYM.zip"
404
+ elif [[ -e ${waldo_build_path}.dSYM ]]; then
405
+ echo "${waldo_build_path}.dSYM"
406
+ fi
407
+ }
408
+
409
+ function get_authorization() {
410
+ echo "Upload-Token $waldo_upload_token"
411
+ }
412
+
413
+ function get_build_content_type() {
414
+ case $waldo_build_suffix in
415
+ app) echo "application/zip" ;;
416
+ *) echo "application/octet-stream" ;;
417
+ esac
418
+ }
419
+
420
+ function get_ci() {
421
+ if [[ -n ${APPCENTER_BUILD_ID:-} ]]; then
422
+ echo "App Center"
423
+ elif [[ ${BITRISE_IO:-false} == true ]]; then
424
+ echo "Bitrise"
425
+ elif [[ -n ${BUDDYBUILD_BUILD_ID:-} ]]; then
426
+ echo "buddybuild"
427
+ elif [[ ${CIRCLECI:-false} == true ]]; then
428
+ echo "CircleCI"
429
+ elif [[ ${GITHUB_ACTIONS:-false} == true ]]; then
430
+ echo "GitHub Actions"
431
+ elif [[ ${TRAVIS:-false} == true ]]; then
432
+ echo "Travis CI"
433
+ else
434
+ echo "CLI"
435
+ fi
436
+ }
437
+
438
+ function get_error_content_type() {
439
+ echo "application/json"
440
+ }
441
+
442
+ function get_history() {
443
+ local _shas=$(git log --format='%H' --skip=$(get_skip_count) -50)
444
+ local _history=$(convert_shas $_shas)
445
+
446
+ echo "[${_history}]" | websafe_base64_encode
447
+ }
448
+
449
+ function get_platform() {
450
+ local _os_name=$(uname -s)
451
+
452
+ case $_os_name in
453
+ Darwin) echo "macOS" ;;
454
+ *) echo "$_os_name" ;;
455
+ esac
456
+ }
457
+
458
+ function get_skip_count() {
459
+ if [[ ${GITHUB_ACTIONS:-false} == true && ${GITHUB_EVENT_NAME:-} == "pull_request" ]]; then
460
+ echo "1"
461
+ else
462
+ echo "0"
463
+ fi
464
+ }
465
+
466
+ function get_symbols_content_type() {
467
+ echo "application/zip"
468
+ }
469
+
470
+ function get_user_agent() {
471
+ if [[ -n $waldo_user_agent_override ]]; then
472
+ echo "$waldo_user_agent_override"
473
+ else
474
+ echo "Waldo $(get_ci)/${waldo_build_flavor} v${waldo_cli_version}"
475
+ fi
476
+ }
477
+
478
+ function json_escape() {
479
+ local _result=${1//\\/\\\\} # \
480
+
481
+ _result=${_result//\//\\\/} # /
482
+ _result=${_result//\'/\\\'} # '
483
+ _result=${_result//\"/\\\"} # "
484
+
485
+ echo "$_result"
486
+ }
487
+
488
+ function make_build_url() {
489
+ local _query=
490
+
491
+ if [[ -n $waldo_history ]]; then
492
+ _query+="&history=$waldo_history"
493
+ fi
494
+
495
+ if [[ -n $waldo_history_error ]]; then
496
+ _query+="&historyError=$waldo_history_error"
497
+ fi
498
+
499
+ if [[ -n $waldo_variant_name ]]; then
500
+ _query+="&variantName=$waldo_variant_name"
501
+ fi
502
+
503
+ if [[ -n $_query ]]; then
504
+ echo "${waldo_api_build_endpoint}?${_query:1}"
505
+ else
506
+ echo "${waldo_api_build_endpoint}"
507
+ fi
508
+ }
509
+
510
+ function make_error_url() {
511
+ echo "${waldo_api_error_endpoint}"
512
+ }
513
+
514
+ function make_symbols_url() {
515
+ echo "${waldo_api_symbols_endpoint/__ID__/$waldo_build_upload_id}"
516
+ }
517
+
518
+ function summarize() {
519
+ local _value=$1
520
+
521
+ if [[ -n $_value ]]; then
522
+ echo "‘${_value}’"
523
+ else
524
+ echo "(none)"
525
+ fi
526
+ }
527
+
528
+ function summarize_secure() {
529
+ local _value=$1
530
+
531
+ if [[ $waldo_extra_args != "--verbose" ]]; then
532
+ local _prefix=${_value:0:6}
533
+ local _suffix_len=$(( ${#_value} - ${#_prefix} ))
534
+ local _secure='********************************'
535
+
536
+ _value="${_prefix}${_secure:0:$_suffix_len}"
537
+ fi
538
+
539
+ summarize "$_value"
540
+ }
541
+
542
+ function upload_build() {
543
+ local _build_name=$(basename "$waldo_build_path")
544
+
545
+ local _response_path=$waldo_working_path/build_response.json
546
+
547
+ echo "Uploading build to Waldo"
548
+
549
+ [[ $waldo_extra_args == "--verbose" ]] && echo ""
550
+
551
+ curl_upload_build "$_response_path"
552
+
553
+ local _curl_status=$?
554
+ local _response=$(cat "$_response_path" 2>/dev/null)
555
+
556
+ if [[ $waldo_extra_args == "--verbose" ]]; then
557
+ echo "$_response"
558
+ echo ""
559
+ fi
560
+
561
+ check_build_status "$_response"
562
+
563
+ if (( $_curl_status == 0 )); then
564
+ echo "Build ‘${_build_name}’ successfully uploaded to Waldo!"
565
+ fi
566
+ }
567
+
568
+ function upload_symbols() {
569
+ [[ -n $waldo_symbols_path ]] || return 0
570
+
571
+ local _symbols_name=$(basename "$waldo_symbols_path")
572
+
573
+ local _response_path=$waldo_working_path/symbols_response.json
574
+
575
+ echo "Uploading symbols to Waldo"
576
+
577
+ [[ $waldo_extra_args == "--verbose" ]] && echo ""
578
+
579
+ curl_upload_symbols "$_response_path"
580
+
581
+ local _curl_status=$?
582
+ local _response=$(cat "$_response_path" 2>/dev/null)
583
+
584
+ if [[ $waldo_extra_args == "--verbose" ]]; then
585
+ echo "$_response"
586
+ echo ""
587
+ fi
588
+
589
+ check_symbols_status "$_response"
590
+
591
+ if (( $_curl_status == 0 )); then
592
+ echo "Symbols in ‘${_symbols_name}’ successfully uploaded to Waldo!"
593
+ fi
594
+ }
595
+
596
+ function websafe_base64_encode() {
597
+ base64 | tr -d '\n' | tr '/+' '_-' | sed 's/=/%3D/g'
598
+ }
599
+
600
+ display_version
601
+
602
+ while (( $# )); do
603
+ case $1 in
604
+ --help)
605
+ display_usage
606
+ exit
607
+ ;;
608
+
609
+ --include_symbols)
610
+ waldo_include_symbols=true
611
+ ;;
612
+
613
+ --upload_token)
614
+ if (( $# < 2 )) || [[ -z $2 || ${2:0:1} == "-" ]]; then
615
+ fail_usage "Missing required value for option: ‘${1}’"
616
+ else
617
+ waldo_upload_token=$2
618
+ shift
619
+ fi
620
+ ;;
621
+
622
+ --variant_name)
623
+ if (( $# < 2 )) || [[ -z $2 || ${2:0:1} == "-" ]]; then
624
+ fail_usage "Missing required value for option: ‘${1}’"
625
+ else
626
+ waldo_variant_name=$2
627
+ shift
628
+ fi
629
+ ;;
630
+
631
+ --verbose)
632
+ waldo_extra_args="--verbose"
633
+ ;;
634
+
635
+ -*)
636
+ fail_usage "Unknown option: ‘${1}’"
637
+ ;;
638
+
639
+ *)
640
+ if [[ -z $waldo_build_path ]]; then
641
+ waldo_build_path=$1
642
+ elif [[ -z $waldo_symbols_path ]]; then
643
+ waldo_symbols_path=$1
644
+ else
645
+ fail_usage "Unknown argument: ‘${1}’"
646
+ fi
647
+ ;;
648
+ esac
649
+
650
+ shift
651
+ done
652
+
653
+ check_platform || exit
654
+ check_build_path || exit
655
+ check_symbols_path || exit
656
+ check_history || exit
657
+ check_upload_token || exit
658
+ check_variant_name || exit
659
+
660
+ create_working_path || exit
661
+
662
+ create_build_payload || exit
663
+ create_symbols_payload || exit
664
+
665
+ display_summary
666
+
667
+ upload_build || exit
668
+ upload_symbols || exit
669
+
670
+ delete_working_path # failure is OK
671
+
672
+ exit
@@ -1,41 +1,20 @@
1
- require 'net/http'
2
-
3
1
  module Fastlane
4
2
  module Helper
5
3
  class WaldoHelper
6
- def self.dump_request(request)
7
- len = request.body ? request.body.length : 0
8
-
9
- puts "Request: #{request.method} #{request.path} (#{len} bytes)"
10
-
11
- request.each_capitalized do |key, value|
12
- puts " #{key}: #{value}"
13
- end
14
-
15
- puts '-------'
16
- end
17
-
18
- def self.dump_response(response)
19
- puts "Response: #{response.code} #{response.message} (#{response.body.length} bytes)"
20
-
21
- response.each_capitalized do |key, value|
22
- puts " #{key}: #{value}"
23
- end
24
-
25
- puts "#{response.body}"
26
- end
27
-
28
4
  def self.filter_parameters(in_params)
29
5
  out_params = {}
30
6
 
31
7
  apk_path = in_params[:apk_path]
32
8
  app_path = in_params[:app_path]
9
+ dsym_path = in_params[:dsym_path]
10
+ include_symbols = in_params[:include_symbols]
33
11
  ipa_path = in_params[:ipa_path]
34
12
  upload_token = in_params[:upload_token]
35
- variant_name = in_params[:variant_name]
13
+ variant_name = in_params[:variant_name] || Actions.lane_context[Actions::SharedValues::GRADLE_BUILD_TYPE]
36
14
 
37
15
  apk_path.gsub!("\\ ", ' ') if apk_path
38
16
  app_path.gsub!("\\ ", ' ') if app_path
17
+ dsym_path.gsub!("\\ ", ' ') if dsym_path
39
18
  ipa_path.gsub!("\\ ", ' ') if ipa_path
40
19
 
41
20
  out_params[:apk_path] = apk_path if apk_path
@@ -43,36 +22,47 @@ module Fastlane
43
22
  if app_path && ipa_path
44
23
  if !File.exist?(app_path)
45
24
  out_params[:ipa_path] = ipa_path
25
+
26
+ app_path = nil
46
27
  elsif !File.exist?(ipa_path)
47
28
  out_params[:app_path] = app_path
29
+
30
+ ipa_path = nil
48
31
  elsif File.mtime(app_path) < File.mtime(ipa_path)
49
32
  out_params[:ipa_path] = ipa_path
33
+
34
+ app_path = nil
50
35
  else
51
36
  out_params[:app_path] = app_path
37
+
38
+ ipa_path = nil
52
39
  end
53
40
  else
54
41
  out_params[:app_path] = app_path if app_path
55
42
  out_params[:ipa_path] = ipa_path if ipa_path
56
43
  end
57
44
 
58
- out_params[:upload_token] = upload_token if upload_token && !upload_token.empty?
45
+ if app_path
46
+ out_params[:dsym_path] = dsym_path if dsym_path
47
+ out_params[:include_symbols] = include_symbols if include_symbols
48
+ else
49
+ out_params[:dsym_path] = dsym_path if dsym_path && ipa_path
50
+ end
51
+
52
+ out_params[:upload_token] = upload_token if upload_token
59
53
  out_params[:variant_name] = variant_name if variant_name
60
54
 
61
55
  out_params
62
56
  end
63
57
 
64
- def self.get_authorization
65
- "Upload-Token #{@upload_token}"
66
- end
67
-
68
58
  def self.get_flavor
69
59
  case get_platform
70
60
  when :android
71
- "Android"
61
+ 'Android'
72
62
  when :ios
73
- "iOS"
63
+ 'iOS'
74
64
  else
75
- "unknown"
65
+ 'unknown'
76
66
  end
77
67
  end
78
68
 
@@ -80,268 +70,50 @@ module Fastlane
80
70
  Actions.lane_context[Actions::SharedValues::PLATFORM_NAME] || :ios
81
71
  end
82
72
 
83
- def self.get_user_agent
84
- "Waldo fastlane/#{get_flavor} v#{Fastlane::Waldo::VERSION}"
85
- end
86
-
87
- def self.handle_error(message)
88
- UI.error(message)
89
-
90
- UI.error('No token for error report upload to Waldo!') unless @upload_token
91
-
92
- upload_error(message) if @upload_token
93
- end
94
-
95
- def self.make_build_request(uri)
96
- if @apk_path
97
- body_path = @apk_path
98
- elsif @ipa_path
99
- body_path = @ipa_path
100
- else
101
- app_basename = File.basename(@app_path)
102
- app_dirname = File.dirname(@app_path)
103
-
104
- body_path = File.join(Dir.tmpdir, "#{app_basename}.zip")
105
-
106
- unless zip(src_path: app_basename,
107
- zip_path: body_path,
108
- cd_path: app_dirname)
109
- return nil
110
- end
111
- end
112
-
113
- request = Net::HTTP::Post.new(uri.request_uri)
114
-
115
- request['Authorization'] = get_authorization
116
- request['Transfer-Encoding'] = 'chunked'
117
- request['User-Agent'] = get_user_agent
118
-
119
- request.body_stream = WaldoReadIO.new(body_path)
120
-
121
- if @app_path
122
- request.content_type = 'application/zip'
123
- else
124
- request.content_type = 'application/octet-stream'
125
- end
126
-
127
- request
128
- end
129
-
130
- def self.make_build_uri
131
- uri_string = 'https://api.waldo.io/versions'
132
-
133
- uri_string += "?variantName=#{@variant_name}" if @variant_name
134
-
135
- URI(uri_string)
136
- end
137
-
138
- def self.make_error_request(uri, message)
139
- request = Net::HTTP::Post.new(uri.request_uri)
140
-
141
- request['Authorization'] = get_authorization
142
- request['User-Agent'] = get_user_agent
143
-
144
- request.body = { "message": message }.to_json
145
- request.content_type = 'application/json'
146
-
147
- request
148
- end
149
-
150
- def self.make_error_uri
151
- uri_string = 'https://api.waldo.io/uploadError'
152
-
153
- URI(uri_string)
154
- end
155
-
156
- def self.parse_build_response(response)
157
- dump_response(response) if FastlaneCore::Globals.verbose?
158
-
159
- case response.code.to_i
160
- when 200..299
161
- UI.success('Build successfully uploaded to Waldo!')
162
- when 401
163
- handle_error('Token is invalid or missing for build upload to Waldo!')
164
- else
165
- handle_error("Build failed to upload to Waldo: #{response.code} #{response.message}")
166
- end
167
- end
168
-
169
- def self.parse_error_response(response)
170
- dump_response(response) if FastlaneCore::Globals.verbose?
171
-
172
- case response.code.to_i
173
- when 200..299
174
- UI.success('Error report successfully uploaded to Waldo!')
175
- when 401
176
- UI.error('Token is invalid or missing for error report upload to Waldo!')
177
- else
178
- UI.error("Error report failed to upload to Waldo: #{response.code} #{response.message}")
179
- end
180
- end
181
-
182
- def self.upload_build
183
- begin
184
- @variant_name ||= Actions.lane_context[Actions::SharedValues::GRADLE_BUILD_TYPE]
185
-
186
- uri = make_build_uri
187
-
188
- request = make_build_request(uri)
189
-
190
- return unless request
191
-
192
- UI.success('Uploading the build to Waldo. This could take a while…')
73
+ def self.get_script_path
74
+ root = Pathname.new(File.expand_path('../../..', __FILE__))
193
75
 
194
- dump_request(request) if FastlaneCore::Globals.verbose?
195
-
196
- Net::HTTP.start(uri.host, uri.port, :use_ssl => true) do |http|
197
- http.read_timeout = 120 # 2 minutes
198
-
199
- parse_build_response(http.request(request))
200
- end
201
- rescue Net::ReadTimeout => exc
202
- handle_error('Build upload to Waldo timed out!')
203
- rescue => exc
204
- handle_error("Something went wrong uploading build to Waldo: #{exc.inspect.to_s}")
205
- ensure
206
- request.body_stream.close if request && request.body_stream
207
- end
76
+ File.join(root, 'waldo', 'assets', 'WaldoCLI.sh')
208
77
  end
209
78
 
210
- def self.upload_error(message)
211
- begin
212
- uri = make_error_uri
213
-
214
- request = make_error_request(uri, message)
215
-
216
- UI.error('Uploading error report to Waldo…')
217
-
218
- dump_request(request) if FastlaneCore::Globals.verbose?
219
-
220
- Net::HTTP.start(uri.host, uri.port, :use_ssl => true) do |http|
221
- http.read_timeout = 30 # seconds
222
-
223
- parse_error_response(http.request(request))
224
- end
225
- rescue Net::ReadTimeout => exc
226
- UI.error('Error report upload to Waldo timed out!')
227
- rescue => exc
228
- UI.error("Something went wrong uploading error report to Waldo: #{exc.inspect.to_s}")
229
- end
79
+ def self.get_user_agent
80
+ "Waldo fastlane/#{get_flavor} v#{Fastlane::Waldo::VERSION}"
230
81
  end
231
82
 
232
- def self.validate_parameters(params)
233
- @apk_path = params[:apk_path]
234
- @app_path = params[:app_path]
235
- @ipa_path = params[:ipa_path]
236
- @upload_token = params[:upload_token]
237
- @variant_name = params[:variant_name]
238
-
239
- unless @upload_token
240
- handle_error('You must pass a nonempty upload token to the Waldo action')
241
-
242
- return false
243
- end
83
+ def self.upload_build_with_symbols(params)
84
+ apk_path = params[:apk_path]
85
+ app_path = params[:app_path]
86
+ ipa_path = params[:ipa_path]
244
87
 
245
- case get_platform
246
- when :android
247
- unless @apk_path
248
- handle_error('You must pass an APK path to the Waldo action')
249
-
250
- return false
251
- end
252
-
253
- unless File.exist?(@apk_path)
254
- handle_error("Unable to find APK at path '#{@apk_path.to_s}'")
255
-
256
- return false
257
- end
258
-
259
- unless File.file?(@apk_path) && File.readable?(@apk_path)
260
- handle_error("Unable to read APK at path '#{@apk_path.to_s}'")
261
-
262
- return false
263
- end
264
- when :ios
265
- unless @app_path || @ipa_path
266
- handle_error('You must pass an IPA or app path to the Waldo action')
267
-
268
- return false
269
- end
270
-
271
- if @app_path
272
- unless File.exist?(@app_path)
273
- handle_error("Unable to find app at path '#{@app_path.to_s}'")
274
-
275
- return false
276
- end
277
-
278
- unless File.directory?(@app_path) && File.readable?(@app_path)
279
- handle_error("Unable to read app at path '#{@app_path.to_s}'")
280
-
281
- return false
282
- end
283
- elsif @ipa_path
284
- unless File.exist?(@ipa_path)
285
- handle_error("Unable to find IPA at path '#{@ipa_path.to_s}'")
286
-
287
- return false
288
- end
289
-
290
- unless File.file?(@ipa_path) && File.readable?(@ipa_path)
291
- handle_error("Unable to read IPA at path '#{@ipa_path.to_s}'")
292
-
293
- return false
294
- end
295
- end
88
+ if apk_path
89
+ build_path = apk_path
90
+ elsif app_path
91
+ build_path = app_path
92
+ elsif ipa_path
93
+ build_path = ipa_path
296
94
  else
297
- handle_error("Unsupported platform: '#{get_platform.to_s}'")
298
-
299
- return false
95
+ build_path = ""
300
96
  end
301
97
 
302
- if @variant_name && @variant_name.empty?
303
- handle_error('Empty variant name for Waldo given')
98
+ command = []
304
99
 
305
- return false
306
- end
307
-
308
- return true
309
- end
100
+ command << "WALDO_UPLOAD_TOKEN='#{params[:upload_token]}'"
101
+ command << "WALDO_USER_AGENT_OVERRIDE='#{get_user_agent}'"
102
+ command << "WALDO_VARIANT_NAME='#{params[:variant_name]}'" if params[:variant_name]
310
103
 
311
- def self.zip(src_path:, zip_path:, cd_path:)
312
- unless FastlaneCore::CommandExecutor.which('zip')
313
- handle_error("Command not found: 'zip'")
104
+ command << get_script_path.shellescape
314
105
 
315
- return false
316
- end
106
+ command << '--include_symbols' if params[:include_symbols]
107
+ command << '--verbose' if FastlaneCore::Globals.verbose?
317
108
 
318
- FileUtils.cd(cd_path) do
319
- unless Actions.sh(%(zip -qry "#{zip_path}" "#{src_path}")).empty?
320
- handle_error("Unable to zip app at path '#{src_path.to_s}' into '#{zip_path.to_s}'")
109
+ command << build_path.shellescape
110
+ command << params[:dsym_path].shellescape if params[:dsym_path]
321
111
 
322
- return false
323
- end
112
+ Actions.sh_control_output(command.join(' '),
113
+ print_command: FastlaneCore::Globals.verbose?,
114
+ print_command_output: true) do |error|
115
+ # do nothing special, for now
324
116
  end
325
-
326
- return true
327
- end
328
- end
329
-
330
- class WaldoReadIO
331
- def initialize(path)
332
- @fp = File.open(path)
333
- end
334
-
335
- def close
336
- @fp.close
337
- end
338
-
339
- def read(length = nil, outbuf = nil)
340
- if result = @fp.read(length, outbuf)
341
- result.force_encoding('BINARY') if result.respond_to?(:force_encoding)
342
- end
343
-
344
- result
345
117
  end
346
118
  end
347
119
  end
@@ -1,5 +1,5 @@
1
1
  module Fastlane
2
2
  module Waldo
3
- VERSION = "1.2.2"
3
+ VERSION = "2.0.0"
4
4
  end
5
5
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: fastlane-plugin-waldo
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.2.2
4
+ version: 2.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - J. G. Pusey
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2019-07-26 00:00:00.000000000 Z
11
+ date: 2021-08-30 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -30,14 +30,14 @@ dependencies:
30
30
  requirements:
31
31
  - - ">="
32
32
  - !ruby/object:Gem::Version
33
- version: '0'
33
+ version: 2.192.0
34
34
  type: :development
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
38
  - - ">="
39
39
  - !ruby/object:Gem::Version
40
- version: '0'
40
+ version: 2.192.0
41
41
  - !ruby/object:Gem::Dependency
42
42
  name: pry
43
43
  requirement: !ruby/object:Gem::Requirement
@@ -76,6 +76,7 @@ files:
76
76
  - README.md
77
77
  - lib/fastlane/plugin/waldo.rb
78
78
  - lib/fastlane/plugin/waldo/actions/waldo_action.rb
79
+ - lib/fastlane/plugin/waldo/assets/WaldoCLI.sh
79
80
  - lib/fastlane/plugin/waldo/helper/waldo_helper.rb
80
81
  - lib/fastlane/plugin/waldo/version.rb
81
82
  homepage: https://github.com/waldoapp/fastlane-plugin-waldo
@@ -97,8 +98,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
97
98
  - !ruby/object:Gem::Version
98
99
  version: '0'
99
100
  requirements: []
100
- rubyforge_project:
101
- rubygems_version: 2.5.2.3
101
+ rubygems_version: 3.0.3
102
102
  signing_key:
103
103
  specification_version: 4
104
104
  summary: Upload build to Waldo