fastlane-plugin-waldo 1.3.0 → 2.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -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