iOS Continuous Integration
A collection of scripts to automate the build and deploy steps of iOS applications for continuous integration via the excellent Jenkins.
A script to automatically update the Jenkins web application if a new version is
available. The intention is for this script to be executed periodically as a Jenkins Job.
The following files make up the CI portion of this repository:
cupertino is used to fetch the latest distribution provisioning profile from the Apple iOS Developer portal.
Let's say you have a workspace set up called Foo.xcworkspace. At the same level of your
workspace, there's typically a directory called "Foo" which contains your sources. These
scrips are designed to reside in a directory named
jenkins inside of that directory. So
your directory structure should look like this:
Foo.xcworkspace Foo jenkins build.sh download_profile.sh last_success_rev.sh testflight.sh
Assuming you've created a Jenkins freeform job for your build, create an "Execute Shell" build step, and pass in the needed configuration values, like this:
#!/bin/bash -e DEBUG=0 \ TF_UPLOAD=1 \ APP_NAME="Foo" \ PROJECT_NAME="Bar" \ DEV_USER="levi" \ DEV_PASSWORD="devsecret" \ KEYCHAIN_PASSWORD="supersecret" \ JENKINS_USER="levi" \ JENKINS_API_TOKEN="somereallylonggoop" \ TF_API_TOKEN="otherreallylonggoop" \ TF_TEAM_TOKEN="evenlongergoop" \ /bin/bash Archer/Archer/jenkins/build.sh
DEBUG (if set to
1) will enable verbose output of the script.
TF_UPLOAD (if set to
1) will upload the generated
DSYM files to TestFlight.
APP_NAME is the name of the application being built; i.e.
PROJECT_NAME is the name of the Xcode project (workspace) being built; i.e.
DEV_PASSWORD are the credentials for the Apple Developer account which
contains the desired distribution mobileprovision. If not supplied, the script will assume
cupertino has the needed credentials in the keychain
KEYCHAIN_PASSWORD is the password for the default keychain on the build machine which
contains the certificates and keys needed for the build.
To figure out your
JENKINS_API_TOKEN visit the Jenkins Wiki
NOTE: You may want to specify the shell which Jenkins uses so sensitive information in
your configuration is not output to the Jenkins log. To do this, simply add
as the first line of the "Execute Shell" script. This will replace the default of
#!/bin/sh -ex (note the 'x') which prints out all evaluations.
Additional configuration may be desired within the
build.sh script to specify the
different Xcode schemes to build. See the
Build Configurations section in
In the example below, there will be three builds. A "Tests" build, AdHoc and Enterprise.
The following configurations are index-representative for each config type. For instance,
the "Tests" scheme (defined in
SCHEMES) is enabled (
SCHEME_ENABLEDS) has the label
SCHEME_LABELS), is of type
BUILD_TYPES), uses the "AdHoc" Xcode
CONFIGS), uses the mobileprovision profile called
PROFILE_NAMES) which is of type "distribution" (
PROFILE_TYPES) and uses the
PROFILE_ACQUISITION_SCRIPTS) to provide the actual mobileprovision
SCHEMES=("Tests" "$PROJECT_NAME" "$PROJECT_NAME Enterprise") SCHEME_ENABLEDS=("$YES" "$YES" "$YES") SCHEME_LABELS=("Tests" "AdHoc" "Enterprise") BUILD_TYPES=("$TEST_TYPE" "$IPA_TYPE" "$IPA_TYPE") CONFIGS=("AdHoc" "AdHoc" "Enterprise") PROFILE_NAMES=("$PROJECT_NAME AdHoc" "$PROJECT_NAME AdHoc" "$PROJECT_NAME Enterprise") # The type of profile (used to download the profile from the Apple Developer portal) PROFILE_TYPES=("distribution" "distribution" "distribution") # Script relative to $RESOURCE_DIR/$CI_DIR which will download mobileprovision profile files PROFILE_ACQUISITION_SCRIPTS=("local_profile.sh" "local_profile.sh" "local_profile.sh")
Each scheme listed in
SCHEMES should have a corresponding TestFlight list defined.
In the example below, the "Tests" build does not get distributed to TestFlight, yet the second build will be distributed to the "Development" list while the third build wil go to the "Enterprise" list.
TF_DIST_LISTS=("" "Development" "Enterprise")
Additional configuration is needed within the
local_profile.sh script to specify the
different hardcoded profiles to fetch from the filesystem. See the
#The hardcoded profile names we are expecting PROFILE_NAMES=("CHANGE_ME AdHoc" "CHANGE_ME Enterprise") #The matching profile files PROFILE_FILES=("CHANGE_ME_AdHoc.mobileprovision" "CHANGE_ME_Enterprise.mobileprovision")
This work is licensed under the Creative Commons Attribution 3.0 Unported License. Please see the included LICENSE.txt for complete details.
A professional iOS engineer by day, my name is Levi Brown. Authoring a technical blog grokin.gs, I am reachable via:
Your constructive comments and feedback are always welcome.