Last active
August 29, 2015 14:08
-
-
Save jcayzac/f3c12499dff8431af209 to your computer and use it in GitHub Desktop.
CI build script for Xcode6.1/iOS8
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env bash -e -u -o pipefail | |
export LANG="en_US.UTF-8" | |
usage() { | |
cat <<EOT | |
NAME | |
${0##*/} -- Build iOS stuff. | |
SYNOPSIS | |
cd /some/git/repository | |
${0##*/} [options] | |
DESCRIPTION | |
${0##*/} builds iOS stuff defined in a '.ci' file at the root of the git repository working copy the current directory is part of. The format of this file is as follow: | |
--8<------8<------8<------8<------8<------8<------8<-- | |
# This is a comment. Blank lines are also ok, as shown below: | |
# Each line represents a buildable. | |
# Fields below are tab-separated. Using space as a separator is not supported, as spaces can appear inside a field. | |
# Workspace Scheme Options | |
Subfolder/Foo.xcworkspace MyAppScheme1 profile=deadbabe-f000-1337-1001-dead13370473 arg2=.. arg3=.. | |
Subfolder/Foo.xcworkspace MyAppScheme2 profile=deadbabe-f000-1337-1001-dead13370473 arg2=.. arg3=.. | |
Subfolder/Foo.xcworkspace MyLibScheme | |
# vim:noet:ts=4:sw=4:ff=unix: | |
--8<------8<------8<------8<------8<------8<------8<-- | |
The following options are available: | |
profile=<...> The identifier of the provisioning profile to use when signing apps. REQUIRED if the scheme is that of an app. | |
identity=<...> The identity to use when signing apps. Optional (Xcode will try to guess). | |
notest Skip unit tests for that buildable. | |
IMPORTANT | |
${0##*/} is not meant to be run concurrently. Running multiple insteances at the same time will spread havoc. | |
BUILD PHASES | |
When building stuff, the following happens: | |
1: SIMULATOR ENVIRONMENT GATHERING | |
Information about the available simulator runtimes and device types is gathered. | |
2: PRISTINE GIT ENFORCEMENT | |
If both GIT_URL and GIT_BRANCH (or GERRIT_REFSPEC) are defined, this phases turn the current working copy pristine and, if git submodules are being used, re-modularize it. | |
3: RELEASE NOTES GENERATION | |
This phase builds a unique version number using the current datetime, the build number (if the BUILD_NUMBER environment variable is defined) and the current commit's shortened SHA-1 identifier. It then gathers the changelog from the git history and creates release notes for the build. | |
4: PROCESSING OF THE DOTCI FILE | |
The project's '.ci' file gets processed, and each declared artifact is in turn built, analyzed, tested, uploaded to SauceLabs and/or TestFlight (optional) and archived. | |
4.1: BUILDABLE SETTINGS GATHERING | |
Information about the current buildable is gathered. | |
4.2: VERSION INJECTION | |
The version info generated in the RELEASE NOTES GENERATION phase above is injected into the buildable's Info.plist file. | |
4.3: BUILD FOR DEVICE | |
Binary for iOS devices is created. If the buildable is an app, it is also signed and archived. Note this phase is skipped if the buildable is a unit test bundle. | |
4.4: BUILD FOR SIMULATOR | |
Binary for the iOS simulator is created. If the buildable is an app, it gets archived. | |
4.5: UNIT TESTS | |
Tests are run for every available simulator runtime and device type combination, using temporary simulators that are destroyed after each has run the tests, unless the 'notest' option was specified. | |
4.6: UPLOAD TO SAUCELABS | |
[Optional] If the buildable is an app, and if SAUCELABS_CREDENTIALS is defined, the application is uploaded to SauceLabs. | |
4.7: UPLOAD TO TESTFLIGHT | |
[Optional] If the buildable is an app, and if TESTFLIGHT_API_TOKEN, TESTFLIGHT_DISTRIBUTION and TESTFLIGHT_TEAM_TOKEN are defined, the application is uploaded to TestFlight. | |
OPTIONS | |
Supported options: | |
--help, -h Print this message and exit. | |
--verbose, -v Be more verbose. | |
ENVIRONMENT | |
Supported environment variables. | |
BUILD_NUMBER If specified, will be included in the product's version number. Normally set by the CI environment. | |
GERRIT_REFSPEC If specified, will be used instead of the GIT_BRANCH. Normally set by JIRA's Gerrit Trigger plugin. | |
GIT_BRANCH If specified, the working copy will be made pristine before the build is started. | |
GIT_URL If specified, used when making the working copy pristine. Otherwise the remote currently tracking the specified branch is used. | |
PROXY_CREDENTIALS If specified, will be passed to 'curl' as the value of --proxy-user when trying to upload apps to SauceLabs or TestFlight. | |
SAUCELABS_BUCKET The bucket name to use for uploading to SauceLabs. The URL used for uploading will become https://saucelabs.com/rest/v1/storage/<SAUCELABS_BUCKET>/. If not specified the bucket will default to the username part of SAUCELABS_CREDENTIALS. | |
SAUCELABS_CREDENTIALS SauceLabs' credentials. Should be 'username:key'. If defined, apps will get uploaded to SauceLabs automatically. | |
TESTFLIGHT_API_TOKEN TestFlight API token. If specified along with TESTFLIGHT_TEAM_TOKEN and TESTFLIGHT_DISTRIBUTION, signed apps will be uploaded to TestFlight automatically. | |
TESTFLIGHT_DISTRIBUTION TestFlight distribution lists (comma-separated). If specified along with TESTFLIGHT_API_TOKEN and TESTFLIGHT_TEAM_TOKEN, signed apps will be uploaded to TestFlight automatically. | |
TESTFLIGHT_TEAM_TOKEN TestFlight team token. If specified along with TESTFLIGHT_API_TOKEN and TESTFLIGHT_DISTRIBUTION, signed apps will be uploaded to TestFlight automatically. | |
EOT | |
} | |
usage_and_exit() { | |
for sig in INT TERM EXIT; do trap $sig; done | |
usage | |
exit ${1:-} | |
} | |
while (($#)) | |
do | |
case "$1" in | |
--verbose|-v) | |
VERBOSE=1 | |
;; | |
--help|-h) | |
usage_and_exit | |
;; | |
esac | |
done | |
# Signal handler that reports failures and do bits of cleanup | |
sig_handler() { | |
declare RC=$? SIG=$1 CMD="$BASH_COMMAND" | |
# Don't fail anymore | |
set +e +u +o pipefail | |
if [ "$SIG" == "EXIT" ] | |
then | |
if (($RC)) | |
then | |
# Command failed! | |
declare START=1 END=${#BASH_SOURCE[@]} I=0 FN= | |
printf "*** ERROR: [%s] exited with return code [%i]!\nStack:\n" "$CMD" $RC | |
for ((I=$START; I < $END; I++)) | |
do | |
printf "%s[%i] %s()\n" "${BASH_SOURCE[$I]}" ${BASH_LINENO[$((I-1))]} "${FUNCNAME[$I]}" | |
done | |
# If the script has a "onfailure" function, call it | |
[ "$(type onfailure 2>&-)" != "onfailure is a function" ] || onfailure "$CMD" "$RC" | |
else | |
printf '\n%s\n' "𝕭𝖚𝖎𝖑𝖉 𝖘𝖚𝖈𝖈𝖊𝖊𝖉𝖊𝖙𝖍. 𝕿𝖍𝖔𝖚 𝖉𝖎𝖉𝖘𝖙 𝖜𝖊𝖑𝖑." | |
fi | |
fi | |
# Treat INT (i.e. Ctrl-C) as KILL and send to the whole process group | |
kill -s ${SIG/INT/KILL} 0 | |
} | |
for sig in INT TERM EXIT | |
do | |
trap "sig_handler $sig" $sig | |
done | |
if ! git rev-parse --show-toplevel >&- 2>&- | |
then | |
printf '*** ERROR: Not a GIT working copy: "%s"\n\n' "$PWD" | |
usage_and_exit 1 | |
fi | |
cd "$(git rev-parse --show-toplevel)" | |
ROOT_DIR="$PWD" | |
BUILD_DIR="$ROOT_DIR/build" | |
export TMPDIR="$BUILD_DIR/tmp" | |
fuckingkillthesimulatornow() { | |
killall iOS\ Simulator launchd_sim 2>&- || true | |
(launchctl list | grep CoreSimulatorService | cut -f 3 | xargs -n 1 launchctl remove) || true | |
sleep 5 | |
} | |
# Collect available runtimes and devices | |
fuckingkillthesimulatornow | |
set +u | |
declare -a RUNTIMES=() | |
declare -a RUNTIME_VERSIONS=() | |
while IFS= read -r LINE | |
do | |
[[ ! "$LINE" =~ unavailable && "$LINE" =~ ^iOS\ [0-9\.]*\ \(([0-9\.]*).*\((com\.apple\.CoreSimulator\.[^\)]*) ]] || continue | |
RUNTIME_VERSIONS=("${RUNTIME_VERSIONS[@]}" "${BASH_REMATCH[1]}") | |
RUNTIMES=("${RUNTIMES[@]}" "${BASH_REMATCH[2]}") | |
done < <(xcrun simctl list runtimes) | |
printf "Found active runtime: [iOS %s]\n" "${RUNTIME_VERSIONS[@]}" | |
RUNTIME_COUNT=${#RUNTIMES[@]} | |
declare -a DEVICES=() | |
declare -a DEVICE_TYPES=() | |
while IFS= read -r LINE | |
do | |
[[ ! "$LINE" =~ unavailable && "$LINE" =~ ^(.*)\ \((com\.apple\.CoreSimulator\.[^\)]*) ]] || continue | |
DEVICES=("${DEVICES[@]}" "${BASH_REMATCH[1]}") | |
DEVICE_TYPES=("${DEVICE_TYPES[@]}" "${BASH_REMATCH[2]}") | |
done < <(xcrun simctl list devicetypes) | |
printf "Found active device type: [%s]\n" "${DEVICES[@]}" | |
DEVICE_COUNT=${#DEVICES[@]} | |
set -u | |
clean() { | |
rm -rf "$BUILD_DIR" | |
} | |
PRETTY=/bin/cat | |
if which xcpretty >&- 2>&- | |
then | |
PRETTY='xcpretty --no-utf -r junit' | |
fi | |
NCPU=$(sysctl -n hw.ncpu) | |
xcbare() { | |
declare WORKSPACE="$1"; shift | |
declare SCHEME="$1"; shift | |
[[ "$*" =~ .*-jobs\ *([0-9]+) ]] || declare JOBS="-jobs $NCPU" | |
rm -rf "$TMPDIR" | |
nice -n 19 xcrun xcodebuild \ | |
-workspace "$WORKSPACE" \ | |
-scheme "$SCHEME" \ | |
-derivedDataPath "$BUILD_DIR/derived" \ | |
${JOBS:-} \ | |
CACHE_ROOT="$TMPDIR/cache" \ | |
${1+"$@"} | |
} | |
xcnice() { | |
xcbare ${1+"$@"} | $PRETTY | |
return ${PIPESTATUS[0]} | |
} | |
#set -x | |
if [[ -n "${GERRIT_REFSPEC:-}" ]] | |
then | |
GIT_BRANCH="$GERRIT_REFSPEC" | |
fi | |
if [[ -n "${GIT_BRANCH:-}" ]] | |
then | |
# Makes the workspace pristine | |
git fetch --all | |
git reset --hard | |
git clean -fdx | |
git submodule foreach --recursive git reset --hard | |
git submodule foreach --recursive git clean -fdx | |
if [[ -n "${GIT_URL:-}" ]] | |
then | |
printf 'Fetching branch [%s] from remote [%s]:\n' "$GIT_BRANCH" "$GIT_URL" | |
git fetch "$GIT_URL" "$GIT_BRANCH" | |
git checkout FETCH_HEAD | |
else | |
printf 'Checking out branch [%s]:\n' "$GIT_BRANCH" | |
git checkout "$GIT_BRANCH" | |
fi | |
git submodule update --init --recursive --force | |
fi | |
if [ ! -f "$ROOT_DIR/.ci" ] | |
then | |
printf '*** ERROR: File not found: "%s"\n\n' "$ROOT_DIR/.ci" | |
usage_and_exit 1 | |
fi | |
VERSION="$(/bin/date -u +'%Y%m%d.%H%M%S')-build${BUILD_NUMBER:--is-local}-commit$(git rev-parse --short HEAD)" | |
CHANGELOG="$(git log -n 50 --date=short --pretty=tformat:"%ad %w(0,0,4)%B" --no-merges | /usr/bin/sed -E 's/[[:space:]\n\r]*Change-Id: [[:alnum:]]*[[:space:]\r\n]*//g' | /usr/bin/grep -vE '^[[:space:]]*$')" | |
RELEASE_NOTES="$(printf 'Build version: %s\n%s \n\nChangelog (truncated):\n\n%s\n' "$VERSION" "CI: ${JOB_URL+${JOB_URL}${BUILD_NUMBER:-}}" "$CHANGELOG")" | |
printf '\n\n+-----------------+\n| RELEASE NOTES |\n+-----------------+\n\n%s\n' "$RELEASE_NOTES" | |
log() { | |
echo "$(date +'%b %d %H:%M:%S') $HOSTNAME cibuild[$!] <Debug>: [Line ${BASH_LINENO[1]}] $1" >>~/Library/Logs/CoreSimulator/CoreSimulator.log | |
} | |
process_buildable() { | |
declare BUILDABLE_WORKSPACE="$1"; shift | |
declare BUILDABLE_SCHEME="$1"; shift | |
declare BUILDABLE_PROFILE= | |
declare BUILDABLE_IDENTITY= | |
declare BUILDABLE_SHOULD_TEST=1 | |
printf '\n\n\nPROCESSING %s…\n==============================================\n\n' "$BUILDABLE_WORKSPACE:$BUILDABLE_SCHEME" | |
while (($#)) | |
do | |
declare BUILDABLE_OPT_VALUE="${1#*=}" | |
declare BUILDABLE_OPT="${1%%=*}" | |
case "$BUILDABLE_OPT" in | |
profile) | |
BUILDABLE_PROFILE="$BUILDABLE_OPT_VALUE" | |
;; | |
identity) | |
BUILDABLE_IDENTITY="$BUILDABLE_OPT_VALUE" | |
;; | |
notest) | |
BUILDABLE_SHOULD_TEST=0 | |
;; | |
*) | |
printf '*** ERROR: Unknown option: %s\n' "$BUILDABLE_OPT" | |
usage_and_exit 1 | |
;; | |
esac | |
shift | |
done | |
if [ ! -d "$ROOT_DIR/$BUILDABLE_WORKSPACE" ] | |
then | |
printf 'ERROR: could not find workspace at "%s".\n' "$ROOT_DIR/$BUILDABLE_WORKSPACE" | |
exit 1 | |
fi | |
# Gather project settings from Xcode | |
clean | |
BUILDABLE_SETTINGS="$(xcbare "$BUILDABLE_WORKSPACE" "$BUILDABLE_SCHEME" -sdk iphoneos -configuration Release -showBuildSettings \ | |
ONLY_ACTIVE_ARCH=YES \ | |
ARCHS=arm64 \ | |
"${BUILDABLE_IDENTITY+CODE_SIGN_IDENTITY=$BUILDABLE_IDENTITY}" \ | |
"${BUILDABLE_PROFILE+PROVISIONING_PROFILE=$BUILDABLE_PROFILE}" \ | |
| /usr/bin/sed "1,/Build settings for action build and target ${BUILDABLE_SCHEME}/d; /^\$/,\$d" | |
)" | |
[ -z "${VERBOSE:-}" ] || printf '\n\nPROJECT SETTINGS FOR %s:\n\n%s\n\n' "$BUILDABLE_WORKSPACE/$BUILDABLE_SCHEME" "$BUILDABLE_SETTINGS" | |
read BUILDABLE_INFO_PLIST < <(/usr/bin/awk "/ PRODUCT_SETTINGS_PATH"' =/ {print $3}' <<<"$BUILDABLE_SETTINGS") | |
read BUILDABLE_NAME < <(/usr/bin/awk "/ PRODUCT_NAME"' =/ {print $3}' <<<"$BUILDABLE_SETTINGS") | |
read BUILDABLE_FULLNAME < <(/usr/bin/awk "/ FULL_PRODUCT_NAME"' =/ {print $3}' <<<"$BUILDABLE_SETTINGS") | |
read BUILDABLE_PRODUCTS < <(/usr/bin/awk "/ BUILT_PRODUCTS_DIR"' =/ {print $3}' <<<"$BUILDABLE_SETTINGS") | |
read BUILDABLE_SYM < <(/usr/bin/awk "/ DWARF_DSYM_FILE_NAME"' =/ {print $3}' <<<"$BUILDABLE_SETTINGS") | |
read BUILDABLE_TYPE < <(/usr/bin/awk "/ PRODUCT_TYPE"' =/ {print $3}' <<<"$BUILDABLE_SETTINGS") | |
BUILDABLE_TYPE=${BUILDABLE_TYPE##com\.apple\.product-type\.} | |
unset IS_APP | |
if [[ "$BUILDABLE_TYPE" == "application" ]] | |
then | |
IS_APP=1 | |
fi | |
printf '\nName: %s' "$BUILDABLE_FULLNAME" | |
printf '\nType: %s %s' "$BUILDABLE_TYPE" "${IS_APP+[will be archived]}" | |
printf '\n' | |
# Inject version number into artifact's Info.plist | |
if [[ -n "$BUILDABLE_INFO_PLIST" && -f "$BUILDABLE_INFO_PLIST" ]] | |
then | |
defaults write "$BUILDABLE_INFO_PLIST" CFBundleVersion "$VERSION" | |
fi | |
declare BUILDABLE_ARTIFACTS_ROOT="$ROOT_DIR/artifacts/$BUILDABLE_NAME" | |
mkdir -p "$BUILDABLE_ARTIFACTS_ROOT"/{device,simulator} | |
if [[ "$BUILDABLE_TYPE" != "bundle.unit-test" ]] | |
then | |
# Build for device (release) | |
printf '\n# Building %s for device:\n' "$BUILDABLE_NAME" | |
clean | |
xcnice "$BUILDABLE_WORKSPACE" "$BUILDABLE_SCHEME" -sdk iphoneos -configuration Release \ | |
ONLY_ACTIVE_ARCH=NO ARCHS='${ARCHS_STANDARD}' \ | |
${IS_APP+${BUILDABLE_IDENTITY+CODE_SIGN_IDENTITY="$BUILDABLE_IDENTITY"}} \ | |
${IS_APP+${BUILDABLE_PROFILE+PROVISIONING_PROFILE="$BUILDABLE_PROFILE"}} \ | |
clean build analyze ${IS_APP+archive -archivePath "$BUILDABLE_ARTIFACTS_ROOT/device/archive.xcarchive"} | |
if [[ "$BUILDABLE_TYPE" == "application" ]] | |
then | |
declare BUILDABLE_PROFILE_PATH="$(/usr/libexec/PlistBuddy -c "print Name" /dev/stdin <<< $(security cms -D -i "$HOME/Library/MobileDevice/Provisioning Profiles/${BUILDABLE_PROFILE}.mobileprovision"))" | |
nice -n 19 /usr/bin/ditto -c -k --zlibCompressionLevel 9 --sequesterRsrc --keepParent "$BUILDABLE_ARTIFACTS_ROOT/device/archive.xcarchive/dSYMs/${BUILDABLE_SYM}" "$BUILDABLE_ARTIFACTS_ROOT/device/${BUILDABLE_SYM}.zip" | |
nice -n 19 xcrun xcodebuild -exportArchive -exportFormat ipa -archivePath "$BUILDABLE_ARTIFACTS_ROOT/device/archive.xcarchive" -exportPath "$BUILDABLE_ARTIFACTS_ROOT/device/${BUILDABLE_NAME}.ipa" -exportProvisioningProfile "$BUILDABLE_PROFILE_PATH" | |
nice -n 19 /usr/bin/ditto -c -k --zlibCompressionLevel 9 --sequesterRsrc --keepParent "$BUILDABLE_ARTIFACTS_ROOT/device/archive.xcarchive" "$BUILDABLE_ARTIFACTS_ROOT/device/archive.xcarchive.zip" | |
rm -rf "$BUILDABLE_ARTIFACTS_ROOT/device/archive.xcarchive" | |
fi | |
fi | |
# Build for simulator (debug) | |
if [[ "$BUILDABLE_TYPE" == "application" ]] || ((BUILDABLE_SHOULD_TEST)) | |
then | |
printf '\n# Building %s for simulator:\n' "$BUILDABLE_NAME" | |
clean | |
xcnice "$BUILDABLE_WORKSPACE" "$BUILDABLE_SCHEME" -sdk iphonesimulator -configuration Debug \ | |
ONLY_ACTIVE_ARCH=NO ARCHS='${ARCHS_STANDARD}' \ | |
clean build | |
if [[ "$BUILDABLE_TYPE" == "application" ]] | |
then | |
BUILDABLE_PRODUCTS="${BUILDABLE_PRODUCTS//Release/Debug}" | |
BUILDABLE_PRODUCTS="${BUILDABLE_PRODUCTS//iphoneos/iphonesimulator}" | |
[ ! -d "$BUILDABLE_PRODUCTS/$BUILDABLE_FULLNAME" ] || \ | |
nice -n 19 /usr/bin/ditto -c -k --zlibCompressionLevel 9 --sequesterRsrc --keepParent "$BUILDABLE_PRODUCTS/$BUILDABLE_FULLNAME" "$BUILDABLE_ARTIFACTS_ROOT/simulator/${BUILDABLE_FULLNAME}.zip" | |
[ ! -d "$BUILDABLE_PRODUCTS/$BUILDABLE_SYM" ] || \ | |
nice -n 19 /usr/bin/ditto -c -k --zlibCompressionLevel 9 --sequesterRsrc --keepParent "$BUILDABLE_PRODUCTS/$BUILDABLE_SYM" "$BUILDABLE_ARTIFACTS_ROOT/simulator/${BUILDABLE_SYM}.zip" | |
fi | |
fi | |
# Test on simulators | |
if ((BUILDABLE_SHOULD_TEST)) | |
then | |
TEST_REPORTS_ROOT="$BUILDABLE_ARTIFACTS_ROOT/simulator/unit-tests" | |
mkdir -p "$TEST_REPORTS_ROOT" | |
for ((DEVICE_IDX=0; DEVICE_IDX<$DEVICE_COUNT; ++DEVICE_IDX)) | |
do | |
DEVICE="${DEVICES[DEVICE_IDX]}" | |
DEVICE_TYPE="${DEVICE_TYPES[DEVICE_IDX]}" | |
for ((RUNTIME_IDX=0; RUNTIME_IDX<RUNTIME_COUNT; ++RUNTIME_IDX)) | |
do | |
RUNTIME="${RUNTIMES[RUNTIME_IDX]}" | |
RUNTIME_VERSION="${RUNTIME_VERSIONS[RUNTIME_IDX]}" | |
printf '\n\n\nUnit tests will now run for [name=%s,OS=%s]\n' "${DEVICE}" "${RUNTIME_VERSION}" | |
printf 'Killing whatever iOS simulator might be running…' | |
fuckingkillthesimulatornow | |
printf ' Done.\n' | |
printf 'Creating temporary simulator for [name=%s,OS=%s]…' "${DEVICE}" "${RUNTIME_VERSION}" | |
unset SIMULATOR_ID | |
read SIMULATOR_ID < <(xcrun simctl create "$DEVICE" "$DEVICE_TYPE" "$RUNTIME" 2>&- && sleep 3 || printf 'error=%s' $?) || true | |
if [[ "$SIMULATOR_ID" == 'error=144' ]] | |
then | |
printf ' Unsupported (skipping).\n' | |
continue | |
elif [[ "$SIMULATOR_ID" =~ ^error=([0-9]*)$ ]] | |
then | |
printf ' ERROR (%s).\n' "${BASH_REMATCH[1]}" | |
exit 1 | |
else | |
printf ' Done. UDID is %s.\n' "$SIMULATOR_ID" | |
printf 'Launching frontend simulator application for [name=%s, OS=%s, id=%s]…' "${DEVICE}" "${RUNTIME_VERSION}" "${SIMULATOR_ID}" | |
[ ! -d "/tmp/tmp$!.trace" ] || rm -rf "/tmp/tmp$!.trace" | |
xcrun instruments -l 5 -t Blank -D "/tmp/tmp$!" -w "$SIMULATOR_ID" >&- 2>&- | |
rm -rf "/tmp/tmp$!.trace" | |
printf ' Done.\n' | |
declare TEST_RUN_EXIT_STATUS=0 | |
set +e +o pipefail | |
xcnice "$BUILDABLE_WORKSPACE" "$BUILDABLE_SCHEME" -jobs 1 -sdk iphonesimulator -configuration Debug \ | |
ONLY_ACTIVE_ARCH=NO ARCHS='${ARCHS_STANDARD}' \ | |
test -destination "platform=iOS Simulator,id=$SIMULATOR_ID" -destination-timeout 10 | |
TEST_RUN_EXIT_STATUS=$? | |
set -e -o pipefail | |
printf 'Killing simulator [name=%s, OS=%s, id=%s]…' "${DEVICE}" "${RUNTIME_VERSION}" "${SIMULATOR_ID}" | |
fuckingkillthesimulatornow | |
printf ' Done.\n' | |
printf 'Deleting simulator [name=%s, OS=%s, id=%s]…' "${DEVICE}" "${RUNTIME_VERSION}" "${SIMULATOR_ID}" | |
xcrun simctl delete "$SIMULATOR_ID" | |
printf ' Done.\n' | |
# sysexits(3): 66 is EX_NOINPUT | |
if ((TEST_RUN_EXIT_STATUS == 66)) | |
then | |
printf 'No test specified for scheme %s! Aborting test runs now.\n' "$BUILDABLE_SCHEME" | |
break 2 | |
fi | |
printf 'Testing ended with exit code=%i.\n' $TEST_RUN_EXIT_STATUS | |
[ ! -f build/reports/junit.xml ] || mv build/reports/junit.xml "$TEST_REPORTS_ROOT/${SIMULATOR_ID}.xml" | |
((TEST_RUN_EXIT_STATUS)) && exit $TEST_RUN_EXIT_STATUS | |
fi | |
done | |
done | |
fi | |
# Optional: upload to saucelabs | |
if [[ -n "${SAUCELABS_CREDENTIALS:-}" && "$BUILDABLE_TYPE" == 'application' ]] | |
then | |
printf 'Uploading "%s" to SauceLabs bucket "%s"…\n' "${BUILDABLE_NAME}-${VERSION}" "${SAUCELABS_BUCKET:-${SAUCELABS_CREDENTIALS%%:*}}" | |
/usr/bin/curl -s -S 2>&1 \ | |
${PROXY_CREDENTIALS+--proxy-user "$PROXY_CREDENTIALS"} \ | |
-u "$SAUCELABS_CREDENTIALS" \ | |
-X POST \ | |
-H "application/octet-stream" \ | |
"https://saucelabs.com/rest/v1/storage/${SAUCELABS_BUCKET:-${SAUCELABS_CREDENTIALS%%:*}}/${BUILDABLE_NAME}-${VERSION}.zip" \ | |
--data-binary "@$BUILDABLE_ARTIFACTS_ROOT/simulator/${BUILDABLE_FULLNAME}.zip" | |
fi | |
# Optional: upload to testflight | |
if [[ -n "${TESTFLIGHT_DISTRIBUTION:-}" && -n "${TESTFLIGHT_API_TOKEN:-}" && -n "${TESTFLIGHT_TEAM_TOKEN:-}" && "$BUILDABLE_TYPE" == 'application' ]] | |
then | |
printf 'Uploading "%s" to TestFlight…\n' "${BUILDABLE_NAME}-${VERSION}" | |
/usr/bin/curl -s -S 2>&1 \ | |
${PROXY_CREDENTIALS+--proxy-user "$PROXY_CREDENTIALS"} \ | |
"http://testflightapp.com/api/builds.json" \ | |
-F "file=@$BUILDABLE_ARTIFACTS_ROOT/device/${BUILDABLE_NAME}.ipa" \ | |
-F "dsym=@$BUILDABLE_ARTIFACTS_ROOT/device/${BUILDABLE_SYM}.zip" \ | |
-F "api_token=$TESTFLIGHT_API_TOKEN" \ | |
-F "team_token=$TESTFLIGHT_TEAM_TOKEN" \ | |
-F "notes=$RELEASE_NOTES" \ | |
-F "notify=True" \ | |
-F "replace=True" \ | |
-F "distribution_lists=$TESTFLIGHT_DISTRIBUTION" | |
fi | |
printf '\n\n\n\n\n' | |
} | |
[ ! -d "$ROOT_DIR/artifacts" ] || rm -rf "$ROOT_DIR/artifacts" | |
while IFS=$'\t' read -ra BUILDABLE | |
do | |
process_buildable "${BUILDABLE[@]}" | |
done < <(grep -vE '^\s*(#.*)?$' "$ROOT_DIR/.ci") | |
# vim:nosi:noet:ts=4:sw=4:ff=unix: |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env bash -l -e -o pipefail | |
# Example usage | |
export LANG="en_US.UTF-8" | |
cd "$WORKSPACE" | |
# Get the Ruby environment right | |
[[ "$(type rvm 2>&-)" =~ "rvm is a function" ]] | |
RES=$? | |
(($RES)) || rvm use "ruby-2.0.0-p481" | |
gem update -N --minimal-deps --conservative "cocoapods" "xcpretty" | |
# Unlock the keychain | |
security unlock-keychain -p "$CI_USER_PASSWORD" "$HOME/Library/Keychains/login.keychain" | |
security set-keychain-settings -t 3600 -l "$HOME/Library/Keychains/login.keychain" | |
export \ | |
TESTFLIGHT_API_TOKEN="$CI_TF_API_TOKEN" \ | |
TESTFLIGHT_TEAM_TOKEN="$CI_TF_TEAM_TOKEN" \ | |
TESTFLIGHT_DISTRIBUTION="Developers" \ | |
PROXY_CREDENTIALS=$USER:$CI_USER_PASSWORD \ | |
http_proxy=http://proxy | |
# Build! | |
"$HOME/cibuild.sh" |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment