Get insightful engineering articles delivered directly to your inbox.
By

— 7 minute read

The Trials of Mobile Automation at InVision

Anyone who works in mobile development can relate to the pain and frustration of long build times, device provisioning and installation management. The InVision mobile team struggled with these things for some time before we threw up our hands and shouted to the heavens for help! After much toiling and iterating we have completely automated our mobile build process and nearly eradicated all frustration around this part of our job.

I invite you to read on where I share some tools and processes which we have developed, that could remove all pain and frustration for your engineering team around these frustrations as well.

Feel the Pain!!! - Back Story

InVision is a 100% remote company and without going into how awesome that is for a variety of reasons, it does present some unique challenges when it comes to managing physical devices for testing. In a traditional office setting, I could just walk over and grab your phone to install our app, or hand out pre-installed devices for testing. Being remote, our team had to figure out a fast and painless way to get builds on devices remotely with as little friction as possible to our testers. Our current process involved a lot of back and forth which was time consuming and frustrating for both developers and testers.

We also repeatedly spent a not-insignificant amount of time merely creating builds for people to test. Xcode builds would take five to ten minutes to compile (longer when we needed to update our Cocoapods). With context-switching time costs this could eat up an hour or more of daily developer time.

We felt the pain and we decided to stop the madness. We had the-twinkle-of-a-vision of a promised land where we could create builds that didn’t require a developer to get involved, that anyone could run on-demand without developer assistance.

Step 1 - We say goodbye to Testflight

Early on we used Testflight to manage our builds for testing, but its limitations forced us to look elsewhere. One issue we had was that Testflight only allows one build available at any given time. We frequently had the need for testers to test an older version; Strike 1. We also wanted to test a special build with a small group of people; Strike 2. Finally, we ran into issues where Testflight builds would hang, and our only recourse was to get Apple involved; Strike 3. It became obvious that we had to go with someone else, (but don’t worry it’s not you, it’s me.)

Step 2 - Say hello to Fabric (Crashlytics)

Our problems with Testflight were all solved by switching to Fabric. Fabric (formerly known as Crashlytics) is the build management and reporting tool that is offered by Twitter. With Fabric we were able to begin making groups of testers, a history of builds, and start on the path to self service deployments.

As we continued our journey to self serve deployments we discovered that Fabric has an external API which could be leveraged to generate builds, which would prove invaluable to us once we discovered Bitrise.

Step 3 - Things start getting better

Bitrise is an amazing product that got us nearly to the finish line. Bitrise is a SaaS service which offers several features that we leveraged including customizable workflows that allow you to set up automation like cloning specific branches on git repositories, installing mobile provisioning profiles, building in XCode, and deploying those builds to Fabric.

We have a few different workflows that we use, but here are the steps to our most common build process:

  1. Preparing the Build Environment: that’s a required Bitrise step, and it’s obvious what it’s doing.
  2. Git Clone Repository: this pulls from our Github repo and it takes an argument that says what branch it should load (more on this later).
  3. Certificate and profile installer: this step gets the latest certificate and mobile profiles. It’s a HUGE time saver because when new devices were added everyone would have to manually refresh locally in XCode. This step automates it.
  4. Set the XCode/Git Build Number: This step sets the build number based off the date and latest git commits. It’s a step that Peter Gulyas wrote in house (https://github.com/InVisionApp/steps-set-xcode-git-build-number) and you should really check it out if you want to automate build numbers.
  5. XCode Create Archive: Here’s where the magic happens! Bitrise will generate a new build from the code that it downloaded in step #2.
  6. Fabric deployer: Once our build is finished in step 5, Bitrise will automatically upload it to Fabric for us.
  7. Custom Jira Step: Another tool developed by Peter, this step takes the Build Number and adds it to JIRA. We used to do this manually (and of course we’d frequently forget about it).
  8. Send a Slack message: finally we send a message to our team’s Slack channel saying the build has started.

This move to Bitrise yielded a dramatic time savings for our team because now builds and deploys could happen without developer intervention. If someone wanted a build, they could just go to Bitrise and hit a button. Bitrise would pull from our develop branch and things would hum along magically.

It was after a few weeks using Bitrise that we got an idea, did someone really need to log into Bitrise to trigger a build? Couldn’t we make it easier?

Nearing the Promised Land - Rosie closes the circle

Invision uses Slack in our day to day communications and some of our incredible engineers have configured an instance of Hubot (we call it Rosie) to manage many of our chatops functions, including web deployments. The workflow is amazing - teams can issue commands to Rosie in Slack and she merges branches, handles reverts, deploys code, and reports back the status.

If you remember from Step 8 in our Bitrise workflow, we have messages already integrated into Slack that give us alerts to the progress of builds. The next logical step was duplicating what Rosie did for web deploys, and as it turns out Bitrise was already able to handle what we wanted.

Any of the Bitrise workflows can be executed via a curl command, here’s a sample of what one looks like:

$ curl https://www.bitrise.io/app/somethingunique/build/start.json --data '{"hook_info":{"type":"bitrise","api_token":"yourtoken"},"build_params":{"branch":"yourbranch"}}'

The fantastic detail here is that the command can take a branch which Bitrise will use in Step 2 mentioned above. They also accept multiple build_params, which we used for passing in the build notes from the latest commits. We can also set the specific workflow that we want to use.

With that piece of the puzzle already in place, it was straight forward to extend Rosie (Hubot) to handle commands in our Slack channel that would execute the necessary curl commands to Bitrise.

In our Bitrise utility class in Hubot we added code to manage the optional params and workflow:

Bitrise.prototype.startWorkflow = function(branch, workflow, notes) {
	var _self = this;
	branch = branch ? branch : this.defaultBranch;
	workflow = workflow ? workflow : this.defaultWorkflow;

	var bitriseData = {
		hook_info: {
			type: "bitrise",
			api_token: process.env.BITRISE_API_TOKEN
		},
		build_params: {
			branch: branch,
			workflow_id: workflow
		}
	};

	if (notes) {
		bitriseData["build_params"].environments = [
			{
				mapped_to: "BUILD_NOTES",
				value: notes
			}
		];
	}

	return _self.sendCommand(bitriseData);

};

In this BUILD_NOTES maps to a custom environment variable that we have set up in Bitrise. What it does is replace any occurrence of the variable with that value.

Self Service Build Generation - Putting it all together

With all of this in place, with just a short slack command anyone in our channel can start a mobile build that auto deploys to Fabric off a specific branch automagically.

Behind the scenes here’s all that’s happening:

  1. Rosie is listening for that command, and she makes a REST request to Bitrise with the values we’ve set.
  2. Bitrise does the heavy lifting, making the build and shipping it off to Fabric.
  3. Once the build is complete and uploaded, Bitrise messages back into our Slack channel to let everyone know the build is completed.

I hope this little history in our journey towards automation was useful to you. If you have any comments or questions, please feel free to drop us a comment!

By
Josh is a Full Stack Engineer at InVision.

Like what you've been reading? Join us and help create the next generation of prototyping and collaboration tools for product design teams around the world. Check out our open positions.