Automated Xcode 6 Bot TestFlight Uploads

Once upon a time, there was a script for uploading Xcode Bot builds to TestFlight automagically. You can find it here but sadly it doesnt work with Xcode 6, like everything else.

I’ve created a new script that will do the same job. It’s been tested with Xcode 6.1.1, Xcode Server 4.0 and Yosemite 10.10.1.

Usage

  1. Set up a new shared scheme and build config that properly signs your archive for TestFlight distribution. I recommend duplicating your Debug build config for this.
  2. In this scheme, add a ‚ÄĚPost-actions” script in the Archive action. Make sure you do this in the scheme “Post-actions”, not as a script in the “Build phases”. Find the script at the end of this post.
  3. Update your tokens and distribution list in the script
  4. Create an Xcode bot that runs this scheme.
  5. Profit

Notes

The script won’t codesign your ipa file any more as the previous one did. The reason is that ipa files may now contain app excensions which need to be codesigned separately. I think this is easier to set up in a scheme in Xcode than in a script.

Script

API_TOKEN="your api token"
TEAM_TOKEN="your team token"
DISTRIBUTION_LISTS="your distribution list"

# DO NOT EDIT BELOW HERE!
########################################
upload() {
    BASE_PATH="/Library/Developer/XcodeServer/IntegrationAssets/"
    IPA="${BASE_PATH}${XCS_BOT_ID}-${XCS_BOT_NAME}/${XCS_INTEGRATION_NUMBER}/${XCS_BOT_NAME}.ipa"
    ARCHIVE="${BASE_PATH}${XCS_BOT_ID}-${XCS_BOT_NAME}/${XCS_INTEGRATION_NUMBER}/Archive.xcarchive.zip"
    DSYM_ZIP="/tmp/dSYM.zip"
    
    # Remove old files 'n folders
    rm /tmp/tflog
    rm /tmp/tfupload
    rm /tmp/tfuploadout
    rm -rf /tmp/Archive.xcarchive
    rm "${DSYM_ZIP}"
    
    TIMEOUT=120
    until [ -e "${IPA}" ]; do
    echo "Waiting for ${IPA} to exist" >> /tmp/tflog
    
    if [ $TIMEOUT -eq 0 ]
    then
        echo "Giving up on ${IPA} existence" >> /tmp/tflog
        exit
    else
        TIMEOUT=`expr $TIMEOUT - 1`
    fi
    
    sleep 1
    done
    
    # Unzip Archive to get at the juicy dSYM files
    echo "Unpacking ${ARCHIVE} to /tmp/Archive.xcarchive" >> /tmp/tflog
    unzip "${ARCHIVE}" -d /tmp >> /tmp/tflog
    
    # Zip the aforementioned juicy dSYM files up for TestFlight
    echo "Packing dSYM(s) as ${DSYM_ZIP}" >> /tmp/tflog
    pushd /tmp/Archive.xcarchive/dSYMs
    # Multiple dSYM files are not supported by TestFlight at this time. Just uploading the main one for now.
    #zip -r "${DSYM_ZIP}" * >> /tmp/tflog
    zip -r "${DSYM_ZIP}" "${DWARF_DSYM_FILE_NAME}"
    popd
    
    # Get the SCM log
    SCM_LOG=$(grep "\s\s\s\s\s\s\s" ${BASE_PATH}${XCS_BOT_ID}-${XCS_BOT_NAME}/${XCS_INTEGRATION_NUMBER}/sourceControl.log | sed 's/          //g')
    
    # Upload to TestFlight
    echo "Uploading to TestFlight" >> /tmp/tflog
    /usr/bin/curl -vs "http://testflightapp.com/api/builds.json" \
    -F file=@"${IPA}" \
    -F dsym=@"${DSYM_ZIP}" \
    -F api_token="${API_TOKEN}" \
    -F team_token="${TEAM_TOKEN}" \
    -F distribution_lists="${DISTRIBUTION_LISTS}" \
    -F notes="${SCM_LOG}\n\nBuild uploaded automatically from Xcode Server Bot."  --stderr /tmp/tfupload -o /tmp/tfuploadout
    
    # Clean up after ourselves before we leave
    rm -rf /tmp/Archive.xcarchive
    rm "${DSYM_ZIP}"
}

echo "Starting TestFlight Upload, check /tmp/tflog for status";

upload &