Skip to content

Instantly share code, notes, and snippets.

@jamesstout
Last active February 19, 2024 01:09
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save jamesstout/76f49b0d63493dfd2d2561129ca810ac to your computer and use it in GitHub Desktop.
Save jamesstout/76f49b0d63493dfd2d2561129ca810ac to your computer and use it in GitHub Desktop.
Xcode script to upload symbols to AppCenter during build phase
#!/usr/bin/env bash
# shellcheck shell=bash
# SEE: https://docs.microsoft.com/en-us/appcenter/diagnostics/iOS-symbolication#app-center-api
# AND: https://github.com/microsoft/appcenter-cli#commands
# Common functions
jcs_log () { echo "[JCS] $1"; }
# TODO: change to fail
jcs_fail () { jcs_log "$1"; exit 1; }
jcs_usage ()
{
jcs_log "You must invoke the script as follows:"
echo " sh \"/path/to/.../upload_symbols.sh\" \"your/appname\" \"YOUR_USER_TOKEN\"]"
}
check_return_code () {
case "$1" in
0)
jcs_log "Symbols uploaded succesully."
;;
1)
jcs_fail "Error: Unknown Error"
;;
2)
jcs_fail "Error: Invalid Options"
;;
3)
jcs_fail "Error: App File Not Found"
;;
[4-9])
jcs_fail "Error: Misc errors"
;;
10)
jcs_fail "Error: dSym Not Found Or Not Directory"
;;
11)
jcs_fail "Error: dSym Directory Wrong Extension"
;;
12)
jcs_fail "Error: dSym Contains More than One Dwarf"
;;
13)
jcs_fail "Error: Test Chunking Failed"
;;
14)
jcs_fail "Error: Upload Negotiation Failed"
;;
15)
jcs_fail "Error: Upload Failed"
;;
20)
jcs_fail "Error: Incompatible Versions"
;;
25)
jcs_fail "Error: Cancelled"
;;
*)
jcs_fail "Error: Unknown Error"
;;
esac
}
APP="${1}";
TOKEN="${2}";
# Pre-checks
if [[ -z "$APP" ]]; then
jcs_usage
jcs_fail "App name not specified!"
fi
if [[ -z "$TOKEN" ]]; then
jcs_usage
jcs_fail "User token not specified!"
fi
if [ ! "${DWARF_DSYM_FOLDER_PATH}" ] || [ ! "${DWARF_DSYM_FILE_NAME}" ]; then
jcs_fail "Xcode Environment Variables are missing!: DWARF_DSYM_FOLDER_PATH and/or DWARF_DSYM_FILE_NAME"
fi
DSYM_PATH="${DWARF_DSYM_FOLDER_PATH}/${DWARF_DSYM_FILE_NAME}";
if [[ ! -d $DSYM_PATH ]]; then
jcs_fail "dSYM path ${DSYM_PATH} does not exist!"
fi
jcs_log "APP = ${APP}"
jcs_log "DSYM_PATH = ${DSYM_PATH}"
# export the path to your NPM packages
export PATH="/Users/james/.npm-packages/bin:$PATH"
method=""
if hash appcenter 2> /dev/null; then
method="cli"
else
method="curl"
fi
jcs_log "method = ${method}"
if [ "$method" == "cli" ]
then
appcenter crashes upload-symbols --app "${APP}" --symbol "${DSYM_PATH}" --token "${TOKEN}"
# should error check here: https://docs.microsoft.com/en-us/appcenter/test-cloud/troubleshooting/cli-exit-codes
rc="$?"
check_return_code "${rc}"
else
if ! hash jq &>/dev/null; then
jcs_log "You need to install jq for this to work - jq is like sed for JSON data"
jcs_log "Run: brew install jq"
jcs_fail "Or build from source: https://github.com/stedolan/jq"
fi
# per: https://docs.microsoft.com/en-us/appcenter/diagnostics/iOS-symbolication#app-center-api
#construct filename
file_name="$(echo ${APP#*\/})"
file_name="${file_name}-"$(date -u +"%Y-%m-%dT%H-%M-%SZ")
jcs_log "file_name = ${file_name}"
#construct url
# This call allocates space on our backend for your file and returns a symbol_upload_id and an upload_url property.
URL="https://api.appcenter.ms/v0.1/apps/${APP}/symbol_uploads"
response="$(curl -s -X POST "${URL}" -H "accept: application/json" \
-H "X-API-Token: ${TOKEN}" \
-H "Content-Type: application/json" \
-d "{ \"symbol_type\": \"Apple\", \"file_name\": \"${file_name}\"}")"
jcs_log "response = ${response}"
# check for errors
error_msg=$(echo "$response" | jq -r '.message')
if [[ "$error_msg" != "null" ]]; then
jcs_fail "Request failed. error_msg = ${error_msg}"
fi
symbol_upload_id=$(echo "$response" | jq -r '.symbol_upload_id')
upload_url=$(echo "$response" | jq -r '.upload_url')
if [[ "$symbol_upload_id" == "null" ]]; then
jcs_fail "Request failed. symbol_upload_id = ${symbol_upload_id}"
fi
if [[ "$upload_url" == "null" ]]; then
jcs_fail "Request failed. upload_url = ${upload_url}"
fi
jcs_log "symbol_upload_id = ${symbol_upload_id}"
jcs_log "upload_url = ${upload_url}"
# Using the upload_url property returned from the first step, make a PUT request with the header: "x-ms-blob-type: BlockBlob" and supply the location of your file on disk.
# This call uploads the file to our backend storage accounts
# -----------
# HOWEVER
# -----------
# this doesn't work. Reported to MS
# Transfer-Encoding: chunked is set by the call to curl
#
# https://docs.microsoft.com/en-us/rest/api/storageservices/put-blob#request-headers-all-blob-types says:
# "For a page blob or an append blob, the value of this header must be set to zero"
#
# but this is the response:
#<?xml version="1.0" encoding="utf-8"?><Error><Code>InvalidHeaderValue</Code><Message>The value for one of the HTTP headers is not in the correct format.
# RequestId:1485bd45-701e-0025-284b-9eb210000000
# Time:2020-10-09T14:47:04.2689302Z</Message><HeaderName>Content-Length</HeaderName><HeaderValue>-1</HeaderValue></Error>
curl -X PUT "${upload_url}" -H "Content-Length: 0" -H "x-ms-blob-type: BlockBlob" --upload-file "${DSYM_PATH}"
# this works, but nothing is committed
# Make a PATCH request to the symbol_uploads API using the symbol_upload_id property returned from the first step.
# In the body of the request, specify whether you want to set the status of the upload to committed (successfully completed) the upload process,
# or aborted (unsuccessfully completed).
#construct url
URL="https://api.appcenter.ms/v0.1/apps/${APP}/symbol_uploads/${symbol_upload_id}"
curl -X PATCH "${URL}" \
-H 'accept: application/json' \
-H "X-API-Token: ${TOKEN}" \
-H 'Content-Type: application/json' \
-d '{ "status": "committed" }'
fi
exit 0;
@jamesstout
Copy link
Author

Add a build phase in the project settings like this:

Screenshot 2020-10-10 at 4 13 22 PM

Use your desired path and replace the pixelated args with "your/appname" "YOUR_USER_TOKEN"

In my case, I only want to upload when I do a Release build.

@jamesstout
Copy link
Author

NOTE: at the moment the curl method doesn't work. I've given feedback to MS, awaiting response.

@az-oolloow
Copy link

For some reason with Xcode 15 I am getting path doesn't exist for this ${DWARF_DSYM_FOLDER_PATH}/${DWARF_DSYM_FILE_NAME} :(

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment