After some headaches and frustration configuring Jenkins to work the way I would like to work, it is time to think in another alternatives. I won’t say this post saying Jenkins is evil because for many people work and it is useful, but above all, to respect its authors and contributors. My goal is to share a bit of experience after working with Jenkins and how with others tools we can have a better Continuous Integration expierence.
You may think there are also nice alternatives out there and very good ones. That’s true, coding in Ruby on the iosgen I’ve tried Travis-CI with Coverall, Code climate and Hound.
This combination works great, in every Pull Request submitted in Github you have all the information you need to ensure the code you are about to merge is good:
- Hound to checks the code style.
- Coverall to check the cobertura of our unit tests.
- Code Climate to check code smells, avoid deterioration.
- Travis-CI compile and run the tests.
Unfortunately not all these tools are available for iOS and at work we have some limitations or restrictions, for example, the build has to be done in our server and sharing that unique server with others platform teams mean the result of a Pull Request is delayed until the poor machine can do the work, that isn’t very agile and we can’t blame Jenkins or other system for that. However, we can do something better, we can use our machines to help the server and have the Pull Request resolution earlier.
After spending quite a lot of time with my workmate Alex fighting to get the most of Jenkins and have the setup we dream, we failed. So we though, if Jenkins didn’t satisfy our expectations and it is pointless to spend more time on it, what if we build our custom solution as alternative?
A Continuous Integration system among others requirement should save us time with repetitive tasks and our requirements were quite basic :
- Be able to build and distribute any environment branch (develop, qa, staging and production).
Pull new Pull Requests and make sure our all our unit tests per module pass.
We did a spike in Ruby using a few and very handy Ruby gems like octokit for Github integration, shenzhen for building and distributing the ipa through TestFlight and Thor to have CLI.
As a result, in less time of setting up Jenkins, we had our custom script making a new build for a particular environment and distributing meanwhile we could focus on work.
It doesn’t make sense to share this spike for everyone because it is very dependant on iOS and architecture used. So I decided to re-write it in order to have a script we can reuse for any other platforms:
Here you can find the source code of the script, done in Ruby:
Once you fetch the script, you will need to do a few easy modifications in order to adapt the script to your project:
Modify the building method, adding the commands you need to build your project:
def building puts "[+] Building".magenta # Your building commands # example: # system "ipa build -w ".xcworkspace/" -s scheme -c configuration --clean" ($?.exitstatus == 0) end
Modify the testing method to ensure your project is always green passing your unit tests.
def testing puts "[+] Testing".magenta # Your testing commands # example: # system "xcodebuild test -workspace .xcworkspace \ # -scheme scheme -sdk iphonesimulator ONLY_ACTIVE_ARCH=NO\ # -destination platform='iOS Simulator',OS=8.1,name='iPhone 5s'" ($?.exitstatus == 0) end
The last method to override is uploading.
def uploading puts "[+] Uploading".magenta # Your uploading code, example for TestFligth # system "ipa distribute:testflight \ # -a TF_API_TOKEN\ # -T TF_TEAM_TOKEN \ # -m Release \ # --notify \ # -l QA \ # -f file_name # " ($?.exitstatus == 0) end
There is one more thing you need to add to the script and is the github access token. It is needed to fetch the PR and change its status with the result of building and testing methods.
If you don’t know how to generate an access token, follow these steps and finally add the token here:
github = Octokit::Client.new(access_token: 'your_access_token')
Now everything is ready to start using it, if you want to create and distribute a new build, you will need to execute the script with these params:
ruby ci.rb distribute -u fjbelchi -n clean-iOS-architecture-generator -b master
The command is distribute which require:
-u : github username of repository
-n : Name of the repository
-b : Branch we want to build
In this case I’m building and distributing my repository : https://github.com/fjbelchi/clean-iOS-architecture-generator
The second option of the script is to integrate a Pull Request:
ruby ci.rb integrate -u fjbelchi -n clean-iOS-architecture-generator -b master -p 26
The only thing new is -p to pass the Pull Request number we want to integrate, the result of testing will modify the status of the commit like the image above.
This is the first version of the script, with a lot of space for new improvements, step by step I hope to make it more robust and include new options. Feel free to add any issue in Github or even better open a Pull Request with the issue fixed. I hope it can be as useful as it is for me.