Building an iOS Distribution Pipeline — Creating a Freestyle Jenkins Project (Part 2)
By: Efekan Egeli
Tags: Jenkins, Automation, Continuous Delivery, iOS, Continuous Integration

Photo by Samuel Sianipar on Unsplash

In the first part of this guide, we’ve built & uploaded our iOS project locally via command line with the tools that Apple provided. But we don’t want to run these on our local machine and we don’t want to type in commands to terminal each time we want to upload an iOS app to the store. We need to automate every step and uploading an app should be as easy as clicking a button.

Wel’ll try to achieve that with a jenkins freestyle project. Let’s begin with creating a new freestyle project on jenkins.

Unless we specify another location, the jenkins project we created will put everything — the repo it pulled, the file it created etc. — under “freestyle-project-demo” folder.

In the first part, we built the project with specified parameters like our scheme name. We have multiple schemes and want to select one of them when we want to run the jenkins job. So we need to parameterize the job first.

We also needed a “branch” parameter as well because we should be able to build & upload from any branch at any given time with the scheme we want. To be able to do that, we added another parameter called “BRANCH” and we needed the jenkins job to connect to our bitbucket server and get the available branch names. So we added a groovy script to the active choices “BRANCH” parameter to achieve that and used a bit of regex to get the branch names with the format we use.



def branchList = getTags.text.readLines().collect {

it.split()[1].replaceAll('refs/heads/', '').replaceAll('refs/tags/', '').replaceAll("\\^\\{\\}", '')

}

return branchList def getTags = ("git ls-remote -h -t https://your-user-name:your-password@your-git-path.git ").execute()def branchList = getTags.text.readLines().collect {it.split()[1].replaceAll('refs/heads/', '').replaceAll('refs/tags/', '').replaceAll("\\^\\{\\}", '')return branchList

After you added these two parameters, your jenkins job should look like this when you are at “Build with Parameters” section.

Now we’ll add a Source Code Management step and this will clone the branch we wanted each time we press the “Build” button in the “Build with Parameters” section.

As the last step of creating a freestyle jenkins project, we will take all the shell code from part 1 and move it to “execute shell” action of the jenkins “build step”.

To upload an app from a jenkins server, there are very important 2 steps you have to add.

Store your app-specific password and username to a file in your jenkins server and add it to your shell script as a source. You can create app specific passwords at https://appleid.apple.com.

#get appstoreconnect username and password from config file

. /Users/jenkins/Documents/workspace/ios-distribution-config/credentials.config

This config file stores 2 variables which are “username” and “password”. We’ll use these in the upload step.

2. Unlock keychain on the machine to give the Jenkins access to your keychain.

#jenkins needs to access keychain over SSH

security unlock-keychain -p your-machine-password ~/Library/Keychains/login.keychain

We don’t want to reach the altool with full path, so let’s add its path globally.

#access altool globally

export PATH=$PATH:/Applications/Xcode.app/Contents/Applications/Application\ Loader.app/Contents/Frameworks/ITunesSoftwareService.framework/Support/

Finally, add the xcodebuild and altool commands to the end of your shell script.

#archive project

xcodebuild -workspace Trendyol.xcworkspace -scheme ${BUILD_SCHEME} -sdk iphoneos -configuration ${BUILD_CONFIGURATION} archive -archivePath /Users/jenkins/Documents/workspace/ios-distribution-config/${BUILD_SCHEME}.xcarchive | /usr/local/bin/xcpretty #export IPA

xcodebuild -exportArchive -archivePath /Users/jenkins/Documents/workspace/ios-distribution-config/${BUILD_SCHEME}.xcarchive -exportOptionsPlist exportOptions.plist -exportPath /Users/jenkins/Documents/workspace/ios-distribution-config -allowProvisioningUpdates | /usr/local/bin/xcpretty #upload IPA

altool --upload-app -f /Users/jenkins/Documents/workspace/ios-distribution-config/${BUILD_SCHEME}.ipa -u $username -p $password

That’s all. Now we can upload an app to the app store with the branch and scheme we wanted to upload with just a click of a button.