Developing on Staxmanade

Setting Jenkins up to run XCTool and Xcode Simulator Tests


We recently migrated an older Jenkins C.I. server over to a newer one, and struggled to get XCTool or xcodebuild to run unit tests where the simulator was needed.

There are quite a number of blog posts out there that describe how to setup a C.I. Jenkins server on a Mac, but many of them don't include the last bit (that worked for me), so I hope this helps you...

Why Can't I run the Xcode Simulator on a Jenkins server?

Some Error Messages I Encountered Along the Way:

Tried to install the test host app 'com.myapp.test' but failed.

Preparing test environment failed.


There was a problem starting the test bundle: Simulator 'iPhone 6' was not prepared: Failed for unknown reason.

Test did not run: Simulator 'iPhone 6' was not prepared: Failed for unknown reason.

2015-01-21 12:02:19.296 xcodebuild[35135:875297]  iPhoneSimulator: Timed out waiting 120 seconds for simulator to boot, current state is 1.

Testing failed:
Test target MyProjectTests encountered an error (Timed out waiting 120 seconds for simulator to boot, current state is 1. If you believe this error represents a bug, please attach the log file at /var/folders/yf/49df70js2xn524f9c3835zx0000087/T/

Need to run a GUI user.

The Simulator needs to run in the context of an actual user where it can get a window handle and render it's U.I...

Below is a great resource to get you most of the way there.

iOS CI with Jenkins

Once you've followed the instructions in the above post and you still can't get the Jenkins CI server to run your simulator tests, then check this last item which got it working for me.

Open up your Jenkins plist file in the LaunchAgents folder. (If you don't have one in LaunchAgents, then go back to the linked blog post and follow that first).

The key for me to get it working was to remove the CreateSession key from the plist.

-       <key>SessionCreate</key>
-       <true />

Once I removed this key, restarted the server, everything started building/working correctly.

In summary:

  1. Auto-login with a jenkins user
  2. Get your plist moved over to the LaunchAgents folder (see post linked above)
  3. Remove the SessionCreate key

How to Migrate a Jenkins Job to New Jenkins Server


We recently setup a new Jenkins build server for some iOS applications and I wanted to find a quick way to copy a couple Jobs from the old server to the new one.

Below are a few small options I found while working on the task.

Option 1: Copy jobs directory

One option (and seems to be the recommended one) is to just copy the jobs directory from the old server to the new one.

From the documentation Moving/copying/renaming jobs:

You can:

  1. Move a job from one installation of Jenkins to another by simply copying the corresponding job directory.
  2. Make a copy of an existing job by making a clone of a job directory by a different name.
  3. Rename an existing job by renaming a directory. Note that the if you change a job name you will need to change any other job that tries to call the renamed job.

Those operations can be done even when Jenkins is running. For changes like these to take effect, you have to click "reload config" to force Jenkins to reload configuration from the disk.

For me, I skipped this option because I was having a hard time finding where the jobs directory was on the old server. (Or just too lazy to find it, and I only had a couple jobs to copy over)

Option 2: Try one of the plugins out there

There are some Jenkins plugins out there that provide some job export options. Here are a couple...

Option 3: Use Jenkins CLI

This is what I used, which worked nicely for only the few jobs we had. If you have a large number of Jenkins jobs, you may consider the first aproach above.

  1. First download the Jenkins CLI jar.

    • You can do this from your jenkin's CLI page within your installed Jenkins instance.

    jenkins CLI menu

  2. Next we can use the following command (pointing to the old server) to list the jobs.

    java -jar jenkins-cli.jar -s http://<YourBuildServer>:<YourBuildServerPort>/ list-jobs

  3. Using one job from the list above, let's copy the xml of a job to the clipboard. (I'm using a Mac which is were pbcopy & pbpaste come from below)

    java -jar jenkins-cli.jar -s http://<YourBuildServer>:<YourBuildServerPort>/ get-job "NAME_OF_JOB" | pbcopy

    This uses the cli get-job "NAME_OF_JOB" command to print the job's xml to stdout, which we pipe to pbcopy on the Mac to load the configuration into the clipboard. You could of course pipe the output to a file like ... > job.xml

  4. If the above command placed a job's XML into the clipboard, you can use the below command to add it to the new server.

    pbpaste | java -jar jenkins-cli.jar -s http://<YourBuildServer>:<YourBuildServerPort> create-job "NAME_OF_JOB"

    This uses pbpaste to take what is in the clipboard, send it to stdin and pipe it to the Jenkins cli's create-job "NAME_OF_JOB" command.

Hope this helps...

Resgrid is a BizSpark Featured Startup


Today Microsoft published an article on their BizSpark Featured Startups blog about Resgrid!

What is Resgrid?

Resgrid is a software as a service product hosted on Microsoft Azure that provides logistics, management and communication tools to first responder organizations such as volunteer fire, career fire, EMS, search and rescue, public safety, disaster relief organizations, etc.

My partner Shawn Jackson and I created Resgrid a few years ago and the buzz is exciting to see.

If you have any interest in following some technical aspects of this little startup. Shawn often posts interesting articles both technical and startup/business related on his site.

How to install clang-format and formatting Objective-C files


Formatting your code so it follows whatever conventions your team/company/self define is important. As developers who have to read code on a regular basis, you have to train ourselves to mentally parse code and spot where bugs may be lurking.

However, if your code is not formatted in a consistent fashion, the cognitive load placed on your brain increases dramatically. Not only do you have to read, parse, and conceptualize the code you're reviewing, your brain is now having to decide if anomalies in the formatting of your project's source code are because of a problem in the code, or merely a difference in the code formatting or styling.

Easy and automatic code formatting tools were something I really missed when I started using Xcode because Visual Studio's built-in formatting of a file is as simple as CTRL+k+d.

This has definitely improved in recent years with the introduction of Alcatraz and ClangFormat-Xcode and I'd highly recommend you check them out.

But, what if you just acquired a legacy project, that was hacked on by quite a number of different developers, with different styles, that's a total mess (from a style consistency perspective)? Or what if you wanted to have an easy rake task that automatically formatted the necessary code files?

This is where a great little tool from the LLVM project clang-format comes in handy.

Unfortunately it's not as easy to install as brew install clang-format (It's now as easy to install as brew install clang-format), but I'll show you not only how to get it installed manually, but a command to easily format your code.

How to install clang-format manually

Thanks to this post for describing how to get (an older version of the tool), I put together the following steps that I hope you find useful.

  1. Go to the LLVM Download page
  2. In chrome dev tools (On my mac, ⌘+⌥+J aka CMD+Option+J, make sure theElementstab is selected, andCMD+Fwithin the html source formacosx-apple-darwin`.
  3. Copy that URL and place it into the following set of commands.

From a command prompt, navigate to a folder where you'd like to save or store the clang tools.

  1. Remove the older version if there was one, and create a folder to work in rm -rf ./clang-format/ && mkdir -p ./clang-format
  2. Take the previously discovered link from above and use the following to download it into our working folder. curl '' -o './clang-format/clang-format.tar.xz'
  3. Extract the tar file tar xvfJ clang-format/clang-format.tar.xz -C ./clang-format
  4. Remove any previously sym-linked linked version you have rm -f ~/bin/clang-format
  5. Link the downloaded clang-format command into our ~/bin folder ln -s $(pwd)/$(find clang-format | grep bin/clang-format$) ~/bin/clang-format
  6. Test the command works clang-format --help

Here are all of the steps above as a script:

rm -rf ./clang-format/ && mkdir -p ./clang-format
curl '' -o './clang-format/clang-format.tar.xz'
tar xvfJ clang-format/clang-format.tar.xz -C ./clang-format
rm -f ~/bin/clang-format
ln -s $(pwd)/$(find clang-format | grep bin/clang-format$) ~/bin/clang-format
clang-format --help

How to setup your project style guide

Now that you have the command line clang-format tool installed, you can walk through how to use it to format our Objective-C code files. Let's walk through some steps I used to apply a standard code format to the project.

But, before you use the command line tool to rip through our project, let's first set the standards you'd like clang-format to adhere to when formatting our code.

At the root of your project (probably where your .git folder is), create a file called .clang-format

The .clang-format file contains the formatting rules for a project. Its structure is YAML and is what the clang-format CLI can read to format your project's Objective-C files.

For details about the .clang-format file, you can check out the docs to get a list of all of the options possible in this file.

Here is one I have used before.

BasedOnStyle: Chromium

AlignTrailingComments: true
AllowShortIfStatementsOnASingleLine: false
BreakBeforeBraces: Attach
ColumnLimit: 0
IndentWidth: 4
KeepEmptyLinesAtTheStartOfBlocks: true
Language: Cpp
MaxEmptyLinesToKeep: 4
ObjCSpaceAfterProperty: true
ObjCSpaceBeforeProtocolList: false
PointerBindsToType: false
SpacesBeforeTrailingComments: 1
TabWidth: 4
UseTab: Never

If you want to ignore a folder from being touched, you can place a .clang-format in that folder with the following option set:

BasedOnStyle: None

Format all our files at once

Now that you have a .clang-format file which helps to define our project's styling conventions, you can begin our initial formatting sweep.

First let's create a command that gives us all the files you want to process.

Here's my initial example (executed in a zsh shell):

ls MyProject/*.[hm]

Tweak this however you need so that you get a list of files to format from your project. You may want to be careful to exclude a CocoaPods folder, or other third party libraries and once you are happy with it, you can then pipe its output to clang-format.

ls MyProject/*.[hm] | xargs clang-format -i -style=file

You can use the xargs command to execute the clang-format command for each file in the output ls.

clang-format options

In the above example you use the following clang-format options:

  • -i tells it to do an in-place edit of the file
  • style=file this tells clang-format to use our .clang-format style rules when formatting.

Did you have your project under source control before doing this?

I sure hope you have the project in source control. You should now be able to git diff or whatever you do to view your source changes and see the files that have been modified by the clang-format command.

I hope this post was helpful in showing you how to install clang-format and use it to format your existing Objective-C project.

Custom Static Blog Generator - No Longer Using Octopress



In summary I left my Octopress blog behind quite a while ago, and this site has been statically generated with a custom tooling build up around gulpjs and node.

Some of the details...

After I migrated from Blogspot to Octopress I started running into workflow issues and other issues that turned me off from Octopress/Jekyll (at least for my own site).

It was also right around the time that GulpJS came out and I needed a project to play around with...

So I did what every developer does. I wrote my own.

Using Approvals.NodeJS to capture previous renderings of the Octopress generated version of, I was surprised at how quickly I ported my Octopress generated site to a new custom static site generator.

I'm not writing this to convince you to leave Octopress for anything (especially my home-grown tool), but felt compelled to get a blog post out describing some of the cool little features I've implemented.

Personal struggles with Octopress:

  • Octopress site generation was too SLOW for me. There's even a helper rake task that moves your posts to a temporary folder to exclude from generation when you want to quickly see the post you're working on generate fast, but this just bothered me from a fundamental level.
  • I'm not a Ruby developer and don't have the ability or desire to fork/maintain Jekyll or Octopress. I wanted to have something that I pretty much owned. (yea - that comes with a larger maintenance burden, but meh - I'm a developer and its part of the process)
  • Disliked that every time I rake gen_deploy I didn't know the exact code-diff that was changed since the previous version. I'd like to know exactly what files have changed and how they have changed before they get deployed. (again, there's probably a solution here, but didn't really care to dig deeper)
  • There's an issue on Windows where you end up mucking around with the codepage, which made working on things a bit of a headache.

So what did I end up with?

I now have a statically generated site all powered by gulp and a small library/command line tool I've thrown up here: Togglejs.

How is this better ~err~ different?

  • Regenerating my site only takes about 6 seconds (as opposed to the Octopress 30+)
  • I learned gulp, and node.js streams along the way.
  • Built by myself — which was a good for the learning experience.
  • Don't have to set the codepage to 65001 for Windows machines.
  • Series support.
    • I've implemented two different features for supporting a series. One allows me to control through YAML front matter posts and how they tie into a series topic. Another feature allows me to write out a series in a single markdown file, where I can specify a delimiter to split the articles up by. I may blog more about these in the future as they're a feature I've quite liked and was relatively easy to implement using my custom site generator.
  • Easy post tagging for a custom feed that gets cross-posted to
  • The tog is easy to extend with custom commands and has a number of pre-built commands already ready to go.

Since I've not put a huge amount of time into it - and I haven't exactly developed it to be a competitor to Octopress or other static site generators, it pretty much has just what I need it to have at the moment and not really anything more.

How is this worse?

  • I have to maintain it (this is both a blessing and a curse) - don't get the benefits of bug fixes by hundreds of contributors to Octopress.
  • I haven't yet ditched the Octopress theme, so that change will be coming at some point.
  • I don't have any automated process to deploying changes. So I can't just create a post on my phone, save to my repo and expect it to automatically show up online - but have ideas on how to do that.
  • My gulp watch is not working correctly and it's not yet wired up to livereload which would be a nice next step...


This is my site so it's all up to me to make it right...

It's been a pleasure to build this up and just a fun little project to hack on (as if all the other OSS projects I hack on aren't enough).

Use different Git Diff Tools Per File Extension


How to setup git to allow different merge/diff tools based on file extension.

I'm going to put this here so I can find it later...

Create a merge-wrapper script

To allow us the flexibility we want to determine which diff tool should be used for different file extensions, we need to break out the logic in to an external script. Below I have 2 samples of a merge script. I started with the .sh file (bottom), but changed over to the .js version (above that) since it is easier for me to maintain.

I haven't yet tried to run this on windows, but suspect we can wrap the merge-wrapper.js in a .cmd file calling it with Node.JS.

Customize the merge-wrapper.js

  1. Extend with other diff tool support:

    If you want to extend the script to add support for your own diff tool, just create a new function that returns an object following the pattern of the existing createP4MergeCommand or createOpenDiffCommand.

  2. Modify which diff tool is used per extension:

    If you want to change which tool is used per file extensions you can modify the diffLookup hash to map various extensions to whatever tool you setup.

  3. Leave me a comment (either here - or in the gist) of what diff tool you added.

    I'd be happy to take contributions of other diff tools in this gist if you leave a comment with yours...

Below was an attempt at using a bash script to manage what I do above, it'll work for some, but I didn't want to maintain this - prefer the JS version instead.

Setup ~/.gitconfig

Now that we've created our merge wrapper script we need to tell git how to use it.

Say we placed our merge script in the following directory: $HOME/dotfiles/tools/merge-wrapper.js. You can add the below to your ~/.gitconfig file and when you use git difftool our new merge-wrapper will be used to pick diff tools based on file extension.

    tool = merge_wrapper
[mergetool "merge_wrapper"]
    cmd = $HOME/dotfiles/tools/merge-wrapper.js \"$BASE\" \"$LOCAL\" \"$REMOTE\" \"$MERGED\"

Introducing SkypeIt - Command Line Skype Phone Calls



In short npm install -g skypeit and enjoy quickly jumping on conference calls.

What is it?

A simple little command line utility that can be used to efficiently jump on a conference call and automatically dials the extension or conference ID.

What pain does this solve?

I've recently been working on a number of projects where often times more than twice a day I have to jump on a conference bridge.

This typically involves:

  1. Opening the Outlook appointment
  2. Copying just the conference phone number (without extension)
  3. Pasting it in Skype to dial
  4. While Skype is dialing, I go back to Outlook and copy the extension/conference id.
  5. Pasting in Skype's number pad area
  6. Type or use the mouse to press the final # key.

How does SkypeIt improve this?

SkypeIt takes the 6 steps and cuts them in half or more.

  1. Open the Outlook appointment
  2. Copy the conference phone number & extension (if there is one) in one shot.
  3. At the (already open command line - because we developers usually have a command line open) paste in skypeit "<paste here>" <press enter>

The problem this solves may seem like a first world problem, but a big annoyance factor when running through the original steps to get on a conference call is, people who setup these meetings, rarely include the final # sign needed at the end of a conference ID/extension #. So when I paste the extension into Skype, I still have to manually get the # in there.

SkypeIt even better with teams!

If you work remotely as I do, then you're probably communicating through things like HipChat, Skype, Slack, AOL (I-kid, I-kid), etc. Instead of your team to remind them to jump on a call where they would have to repeat the long steps above, you can just paste the skypeIt ###-###-### ###### command necessary to immediately jump on a call. This serves to remind them a call is coming up or already started and saves time from having to find the number/extension as they can copy/paste it directly at the command line.

Or even better, if you're on a Mac and using ZSH at the command line, SkypeIt has tab completion support and a YAML config strategy, so you can easily configure a project with your standard phone numbers (say daily standup conference number) and check in a .skypeitrc file to the project. When you're in the context of the project you can just type skypeit stand<tab> and jump on your daily standup conference call.

Does anyone who works remotely actually stand-up on a daily standup call? hmmm...

Still early...

SkypeIt was written to solve a personal pain-point and is not yet a complete solution for all conference call situations. If you'd like to see your scenario supported, head on over to the SkypeIt Issues on GitHub and drop me a line.

I'm not currently using a windows machine - but with the windows protocol activation capabilities, we can probably easily add support for windows to SkypeIt.

Thoughts on Working Remotely from Home


This post may seem a bit longer than my usual posts. It's one I've slowly been extending over the last couple years while working remotely. Many of the points may be obvious ones, but if you're considering a work-from-home (remotely) type of position that you consider some of these topics.


My previous job afforded me the opportunity to work from home a couple days out of the week. While putting my wife through school, those days were great. I would start work extra early so I could leave early and watch our little girl while my wife headed off to class. The early start was great because these quiet mornings were often the most productive part of my day. The lack of distractions such as email, meetings, and instant message chats along with the quiet focus time all contributed to this increased productivity.

While I quite enjoyed this time, was often productive, and it helped my family I still preferred to go into the office over working from home.

So why did I still prefer going to the office over working from home?

I did not feel as connected to the group, which left me feeling as thought I was always playing catchup. All of those water-cooler discussions and inpromptu office meetings where I (or anyone else remote) wasn't pulled into more often not left me feeling like I was not able to keep on top of what was going on.

This experience and the feeling it left me with is what concerned me about the new job I was about to take.

Worried to take a remote / work from home job.

Given my limited work from home experience, I was concerned about working remotely 100% of the time. However, the new opportunity to work for a consulting firm I admired, and the thought of being able to constantly try new technologies, and business domains was really appealing.

I have now worked remotely for Vertigo for over 3 years and I'd like to share a list of Pros/Cons that I've gathered through my experience working from home full time.

Con's to working from home

Now, while Con's do not outweigh the Pro's for me, there is quite a bit of grey area here, so let's review some con's.

  • Less human/social interaction on a daily basis. As an introvert, and a software developer, this is generally not too bad. This was a bigger concern for me originally and is much less of an issue now that I've tried it out. I make sure to take some time to have great Skype video calls with fellow remote coworkers and I also try to offset this by participating in local user groups or and other social occasions. However, the best medicine for this is a simple trip to the park with my little girls. I will say that I've had a day or two where I jumped at the opportunity to take a trip to Costco or other errand just so I could get out of the house...
  • Shipping Hardware.
    • This one is a bit of a pain. Working for a consulting firm means there are many of different projects that require varying hardware configurations. From Xboxes, test phones, tablets, computers, and even TVs. I semi-regularly run to FedEx and send something to H.Q. or the Apple Store or Best Buy to pick up some hardware based on the needs of a project.
  • It can be a little too easy to sit at the personal computer in the evening and reach over to my work computer to reply to a late work-related email, or hammer on some code. So you need to be careful about the work/family balance when it's so easy to work from home. This takes a bit of discipline.
  • Sitting in the office chair when the amazingly yummy aromas of some fresh home cooking - distracting me from being productive as the smell is driving my stomach to scream at me to go downstairs for some food!
  • Communication
    • Being remote, you have to become an over-communicator. An email here and there is fine, but combine that with chat/I.M., phone calls, video chat calls (preferred), and more emails. However, you have to work a little harder to be noticed, especially if you have to compete with people who are all working in the same office.
  • It often takes a little more discipline to take breaks.
  • Time Zones
    • Time Zones are a hassle from many different angles, even when you work at an office; however, working remotely often means your employer has hired you because you are not near them. This increases the chance that you are several or more timezones away from your company's headquarters. Which can mean the usual things like meal planning, start/stop times, etc require a bit more planning and accommodation.

Pro's to working from home

  • Home office temperature!
    • Like most indoor jobs, AC and Heat are good amenities to have, but in big buildings people cannot often control the temperature. It's either too cold or too hot as big buildings have a mind of their own (their airflow and ventilation kinks). However, working from home, you're the master of your indoor weather. If you get hot, take off some clothes or turn on the AC. If you're too cold, put on some clothes or crank up the heat.
  • Commute
    • I often joke with my fellow Californian commute ridden co-workers when they complain about traffic that day that I narrowly avoided a 3 (lego) car pile-up on my way to the office.
    • I live where it's cold in the winter and not having to scrape the ice off of the windshield of my car in the morning due to the icy dew is a HUGE benefit.
    • Plus there's the, well not commuting part. While I enjoyed using the commute to zone out to my favorite podcasts, I still find time to keep up with my podcast when doing things like laundry, dishes, etc.
  • More family time overall. Since my coffee, water, bathroom breaks all lead to opportunities where I can say hello to the family.
  • SWEATPANTS! My wife recently introduced me to sweatpants. OMG they are comfortable, try wearing those at the stuffy-formal-office...
  • Quiet place to focus. It's easy to isolate yourself from the outside world if you need some quiet time to focus and be productive. Shut off the I.M., put phone on do not disturb, close email and get some serious work done.
  • We have all the usual necessities at home,
    • Tools (for that time you need a screwdriver)
    • Easy access to hygiene related products/tools. Ever need to take a shower in the middle of the day? Change of clothes (spilled coffee....)? Or brush your teeth?
  • Invest in your office.
    • When you invest in your home office, you're investing in yourself. Get a good chair, desk, keyboard, mouse, etc.
  • Lunch at home. My wife is a great cook. I'm spoiled to nearly always have a great set of leftovers in the fridge. Keeping me from eating out all the time. Not having to worry about someone eating my leftover chicken-wings (ya, that really happened - not even funny - You know who you are!)
  • My wife just brought me the most amazing homemade burrito. I didn't even care I was on a video call with my team. nom...nom...nom...
  • One of my favorite perks, is not even a perk that any company could offer (or even replace). I take the opportunity to for 10-minute break in the afternoon, where I walk up the street to meet my daughter at the bus stop. This is so much more important in my life than practically any company can offer (like free lunches, ping-pong table, etc...).
  • Scheduling an at-home call is easy. It's rarely a problem to have a fix-it man come by, or cable-guy, or if a package needs to be signed for, working from home makes this easy.
  • David's Additions: I shared a draft of this post to a good friend and coworker and he gave me some other tips, I hadn't thought of, which I totally agree.
    • You struggle on problems and your kid walks in the room and puts your life in perspective.
    • I can listen to my music turned way up!

What about distractions?

I get this a lot, when I tell others I work from home. "I don't know how you don't get distracted with other things to do at home." This may be a very individual thing. While, there can be distractions at home, I've always been a focused individual and I would say it's often easier to be distracted at the office with office chit-chat, meetings, going out to lunch, etc.

Not-so socially appropriate

  • When you're at the office, possibly in a long meeting, what do you do if you have some gas? Working remotely, there's no stress, or stomach pain... Mute your conference call, relax and nobody is the wiser. (Except this one time, I did such a thing not realizing my wife was within an earshot. Yea, a bit embarrassing but we had a laugh over it.)

One of the Simplest Things You can do to Improve Email Communication



Respond to emails with got it. Or some context-related reply, for example: thanks or will respond with further detail later...

More Context

We all know that communication is important, and often where things go awry.

I sometimes wonder if I'm alone in this thinking, but don't think I am. When I send an important email, I like to know that the person on the other end received it. It may be an email that will take the other person time to respond with the detail necessary, but it's awfully unproductive to send an email, and wait a day or two before finding out that the communication was never received.

Simply replying with got it or got it, will respond with more detail later... is a great way to notify me that you've received the email (and may take some time to respond).

I don't necessarily care that my email takes priority, but at least knowing that the other end has seen it is 1/2 the battle.

Updating git branches.


How to update a git branch OTHER than the one you're currently on.

git branch -f {branch-to-change} {commit-to-change-to}

I recently setup a C.I. server to automatically generate builds of an iOS application and upload to TestFlight. I don't want each and every push to master to trigger a new TestFlight build, so I configured my C.I. server to watch the release branch.

I was starting to dislike the switch branch dance to trigger a new build.

What I used to do:

# When I was on the master branch
git checkout release
git merge master
git push

When things start to hurt, look for a better alternative. And with Git, there is almost always a more efficient way.

After digging a bit, I found the answer.

git branch -f {branch-to-change} {commit-to-change-to}

So to trigger a new build from master I can just:

git branch -f release master
git push origin release

Or wrap that in a Gulp task gulp tf. And with CommandAllThings I can now type rake tf, or grunt tf or gulp tf and they all trigger a new build to come out of TestFlight.

Or if you wanted to skip moving your local branch, you could just update the remote branch directly.

git push origin local_branch:remote_branch

So my workflow would look more like

git push origin master:release

Happy Automation!