Setup for CI/CD with Homebrew

This guide will explain how to install the build tools needed to set up a CI Build Node.

The minimum set of required tools is the following:

Depending on your project you may also need Node.js.

Java 8 is also a requirement if you are looking to set up a Jenkins agent.

Finally, it is a good practice to have a bot user whose only responsibility is to build your OSX/iOS projects. This means such a user with the correct permissions should be created, so the user can build OSX/iOS projects.

To do all of this, you can either do this via VNC or via the Web Console, or if you enable Remote Login in the macOS settings, you can SSH in. This guide explains the latter approach as it’s easier to do repeatably and to automate as you scale up.

Install Homebrew

Homebrew is a package manager for macOS and used for managing installation of the various tools needed for iOS and macOS CI efforts. This step will take about 15 minutes, and you will be required to enter your password at least once.

Install Ruby

Lots of tooling requires a modern Ruby installed (fastlane for instance), so we also update our system Ruby:

/usr/bin/ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"
brew install rbenv ruby-build 

# Add rbenv to bash so that it loads every time you open a terminal 
echo 'if which rbenv > /dev/null; then eval "$(rbenv init -)"; fi' >> ~/.bash_profile 
source ~/.bash_profile 

# Install Ruby 
rbenv install 2.4.2 
rbenv global 2.4.2 
ruby -v

Install fastlane

fastlane provides an easy way to automate beta deployments and releases for iOS and Android apps.

You can install it by running:

sudo gem install fastlane -NV

Install CocoaPods

CocoaPods is a dependency manager for Swift and Objective-C Cocoa projects. It is installed via ruby gem as well:

sudo gem install cocoapods

Install Node.js

If you want to install the latest version of Node.js you can run:

brew install node

If you want to install the latest LTS you can run:

brew install node@10
brew link node@10 --force

This will install Node.js 10 LTS and will link it to /usr/local/bin so it is available in PATH.

Note: You may also consider using nvm. It allows you to manage different Node.js versions. To install nvm run:

curl -o- https://raw.githubusercontent.com/creationix/nvm/v0.34.0/install.sh | bash

Install Java 8

If your goal is to setup a Jenkins agent, you will need Java 8 installed on the machine.
To do that, run:

brew tap homebrew/cask-versions
brew cask install java8

Install Xcode

The most direct way to do this is via a VNC/screen-sharing session. If working from a Mac, simply open the Finder and press "cntrl k". This will open your machine's built-in VNC GUI. Collect your public IP and screen-sharing port, and pass them in the GUI.

Enter your user credentials.

Open a web browser via the screen-sharing connection.

Navigate to https://developer.apple.com, log in, and then navigate to https://developer.apple.com/downloads/more

Download and install your preferred version of Xcode by clicking the download link and double-clicking on the resulting download.

Creating Dedicated Build User

It is recommended to have a dedicated user that is responsible for building OSX/iOS applications.

First you need to create a group for this user. The group needs to have an unique id. You can list the current group ids in а numerical oder by running:

dscl . -list /Groups PrimaryGroupID | awk '{print $2}' | sort -n

Choose a number that is not in the list. Then run by replacing {GroupName} and {GroupID} with the desired values:

sudo dscl . -create /Groups/{GroupName}
sudo dscl . -create /Groups/{GroupName} PrimaryGroupID {GroupID}

Now you need to pick a unique id for the user. It is done in a similar fashion to the way we chose the group id:

dscl . -list /Users UniqueID | awk '{print $2}' | sort -n

Finally, run by replacing the placeholders:

sudo dscl . -create /Users/{UserName}
sudo dscl . -create /Users/{UserName} UserShell /bin/bash
sudo dscl . -create /Users/{UserName} UniqueID {UserID}
sudo dscl . -create /Users/{UserName} PrimaryGroupID {GroupID}
sudo dscl . -create /Users/{UserName} NFSHomeDirectory /Users/{UserName}

Ensure a home folder is created for the user:

sudo mkdir /Users/{UserName}
sudo chown {User}:{GroupName} /Users/{UserName}

Creating Default Keychain for the Build User

Since the build user will not log into the OSX machine, a default keychain will never be created.
This could cause build and/or code sign issues (especially if you are using fastlane).

To create a default keychain for the build user, we need to switch to the build user in the terminal:

sudo su {Username}

Now you can execute commands as the build user:

security create-keychain -p {KeychainPassword} login.keychain
security default-keychain -s login.keychain

This will create new keychain called login.keychain and will make it default for the build user.
The security command line tool has a bug and does not add the new keychain to the list of available keychains. To fix this, we need to call:

security list-keychains -d user -s {Keychain}

Now we can proceed with the rest of the setup. To switch back to the previous user type:

exit

Logging Remotely with the Build User

You will need to be able to log remotely with the newly created build user. Especially if you are looking to setup a Jenkins agent.
To do that, you first need to ensure the user can log remotely:

sudo systemsetup -setremotelogin on
sudo dseditgroup -o edit -a {UserName} -t user com.apple.access_ssh

Now we need to create an ssh key pair that we are going to use for remote logging.
If you do not have a ssh key pair you can create one by executing:

ssh-keygen -m PEM -t rsa -C "build machine key" -f "buildMachine_rsa"

Note: For an increased security, it is recommended to associate a passphrase to the private key.

The command will create two files:

  • buildMachine_rsa - This is your private key. Keep it safe and do not share it with anyone.
  • buildMachine_rsa.pub - This is your public key.

To copy the private key to a secure machine that you own, you can use scp. This command executed copy over ssh.
You can run:

scp /path-to-buildMachine_rsa/ username@host:/path-to-location-on-secure-machine

We need to create a authorized_keys file. It lists all keys that can be used to log remotely with a given user:

sudo su {UserName}
mkdir ~/.ssh
cat buildMachine_rsa.pub >> ~/.ssh/authorized_keys
chmod 644 ~/.ssh/authorized_keys
exit

Now you can use the private key to log to the machine remotely using the newly created user:

ssh {UserName}@{host} -i {path-to-private-key}