Setting up Jenkins on OS X

First post in a long time. I didn't really do much iOS development over the summer and am only starting to get back into it in the past few weeks. I have some draft posts on my dealings with both Core Data and UITableViews and once those features are complete I'll post them.

Along with coding, I've been looking at adding some build infrastructure for my projects. Having seen Jenkins used at work, I wanted to get a CI system set up for my builds here at home. I want to use it to kick off a build, run the tests and package up the iPhone app. By using something like Jenkins I can automate my build and testing process and also have a record of previous builds.

Jenkins Install

The first step was to install Jenkins. They provide a Mac installer - the only annoyance is that it triggers the new OS X Gatekeeper dialog blocking unsigned apps from installing. Then I loaded locahost:8080 in my browser to find that Jenkins wasn't loading and there was no error message telling me what went wrong. D'oh. The issue is that Jenkins requires Java to run but it isn't installed by default on OS X. To install simply type java into a terminal and a message box will appear prompting you to install Java.

Then I followed the user setup from Moritz Haarmann's blog. I'm not sure if the jenkins account part is still necessary, as when I got to the stage about changing the user name in the plist file, it had already been set to Jenkins. The changing permissions on the Jenkins home folder was needed though. After that I was able to run ssh-keygen and generate some keys.

Updating Git Workflow

I installed the Git and XCode plugins from the Manage Jenkins screen with no issues. I then created a simple project to test it out. I just added a git clone step. This failed for me with the following errors

Failed to connect to repository : Command "git ls-remote -h ..../MyApp.git HEAD" returned status code 128:
stdout: 
stderr: fatal: '..../MyApp.git' does not appear to be a git repository
fatal: The remote end hung up unexpectedly

The problem here is that the repository is on my Dropbox account (as described here). This folder is not visible to the jenkins user. I didn't want to mess around with changing permissions on the Dropbox folder so I looked for an alternative solution. A colleague at work told me about Bitbucket from Atlassian. This is similar to Github but allows for private repositories. As luck would have it, I had already been using another Atlassian product SourceTree to manage my git repositories. This tool works seamlessly with Bitbucket. Once I uploaded my ssh key to Bitbucket I could simply add another remote repository to my local repository and push to it, all from within SourceTree.

Now that I had a repository on Bitbucket, it was time to integrate that with Jenkins. This turned out to be fairly easy. I uploaded the ssh key for the jenkins account to Bitbucket. The admin page for the repository showed its ssh address so I added a Git build step to the project using that ssh address. When the project is built now, Jenkins will download the latest code from the repository first and then continue on.

Jenkins Issues

While Jenkins is mostly working fine now, there were a few issues I've run into. The git checkout isn't working at all using the Git Plugin. Originally it did but then I started getting the following errors FATAL: Could not checkout null with start point 02dbc3e456d6aa6079543eeaa8361bdebe8fac9d hudson.plugins.git.GitException: Could not checkout null with start point 02dbc3e456d6aa6079543eeaa8361bdebe8fac9d at hudson.plugins.git.GitAPI.checkoutBranch(GitAPI.java:956) ...

Caused by: hudson.plugins.git.GitException: Command "git checkout -f 02dbc3e456d6aa6079543eeaa8361bdebe8fac9d" returned status code 128:
stdout: 
stderr: fatal: reference is not a tree: 02dbc3e456d6aa6079543eeaa8361bdebe8fac9d

I wasn't able to find a solution to this so I had to stop using the Git plugin and just add an execute shell build step to clone the Bitbucket git repository. As I add more projects to Jenkins, I'll check if I get the same issues there also.

Build XCode Project

The XCode plugin for Jenkins made it really easy to build once setup. You add an XCode build step and configure it as necessary. I chose to do a clean build each time. The project I tested this on was a static library so I didn't need an IPA built or any of the version number updates but they should be useful when building a proper app.

When I first tried to build I got an error saying You have not agreed to the Xcode license agreements. I needed to run sudo xcodebuild -license in the terminal to fix this.

In order to run the unit tests, the XCode plugin recommends using two build steps, one to build the app and the other to execute the tests. The reason for this is that the test step requires extra parameters i.e. path to the simulator SDK. If you're using the OCTest framework which comes with XCode then the plugin will listen to the test output and generate JUnit compatible xml files. Jenkins can read these and add the to the build results page.

Set up Coverage Setting up code coverage for iOS projects is not an easy task. My gcov setup for XCode 4.3 still worked for me but the problem was to integrate this with Jenkins. Coverstory would not be of use here but I found this gcovr script from the Octo Talks blog. Gcovr will convert the gcov output into a cobertura xml file which can be read by Jenkins.

One problem I had was that for some reason, gcov wouldn't work on the files in the Jenkins workspace. I was getting gcno:cannot open graph fileerrors. Coverstory also didn't work on the files in this location. What worked for me was to copy the gcda and gcno files out to a temp folder under /Users/Shared/Jenkins/Home. Passing the original build location as the root parameter to gcovr allowed the cobertura plugin to find the source code in the html report, while also removing system headers from the coverage report. Here is the script.

cp -r ${WORKSPACE}/build/${JOB_NAME}.build/Coverage-iphonesimulator/${JOB_NAME}.build/Objects-normal/i386/*.gc* /Users/shared/Jenkins/tmp/${JOB_NAME}
cd /Users/shared/Jenkins/tmp/${JOB_NAME}
gcovr -r $WORKSPACE/$JOB_NAME -x > ${WORKSPACE}/coverage.xml

The Octo Talks blog also suggested a number of other metrics which could be captured in Jenkins. I added the SLOC Count and the Clang Build Scan. Both of these required installing tools and then Jenkins plugins which used those tools. This instructions on the blog covered this. Ones that I've put on the someday/maybe list are the PMD plugin and OCLint.

At the end of all this, Jenkins is working quite well for my simple test project. Next step is to try it out on my app.

posted on September 16, 2012development


Localizing iOS Apps

I was looking at a tutorial for creating a settings bundle for my app and it had separate files for different languages. I realised that I hadn't a clue how to localize iOS applications. I decided I'd better look into it now, rather than at the end of development, in case it required me to change existing code. Much better to implement with localization in mind, than retrofit at the end of development.

I'm interested to see how many translations I'll be able to include in the app. I'm not sure how easy it will be to do the translation or even how much text there will be to translate. I'm planning a Chinese translation and for sentimental reasons I'll do an Irish translation. I'll probably try to get some European languages done also. I think that once I put in the infrastructure to do one language then adding additional ones shouldn't be too much bother.

The basics of implementing localization is that you externalize all strings in your application to .strings files and then provide versions of these files for each language you support. The process for creating the basic localization.strings file is outlined here. In your code you can get the localized values for these strings using NSLocalizedString(@"Externalized String Name", @"").

Localization Tools

Using this method, we will have to deal with lots of .strings files. Xcode doesn't provide much help here so I looked around for third party apps. I bought Linguan on the Mac App Store and it looks very good. You point it at an Xcode project file and it locates all the .strings files and presents them in a nice table. It can generate text files which you can send on to your translators for them to translate and re-import their translations. I'm very pleased with it so far.

Apart from having .strings files for strings in the code, I also need to localize the app's storyboards. Albert Mata has a fantastic tutorial on how to do this here. A big problem with localizing storyboards is that changes in one language's storyboards are not propagated to the others. Manually keeping these in sync would be a nightmare. Thankfully there is a handy script here by Ederson Machado, which will update the .strings files for the storyboard and also keep the storyboards in sync. There is a nice video outlining the features of the script here. By adding this script as a build run script, we can ensure that our storyboards are always in sync.

Localization Workflow

My localization workflow is as follows:

  • First I created multiple storyboards for each language using the Localization area on the sidebar. This will create a language.proj folder for each language.
  • I ran the localize.py script on the project. This generated the mainstoryboard.strings files in each of the language folders.
  • I manually add these files to Xcode. First I added the English version. Then I clicked the plus button in the Localization sidebar and added the other languages. Xcode is able to find those .strings files and link them to the overall file.
  • I create a localization.strings file to deal with the strings in the code and added all languages.
  • I ran genstrings but I don't think this is needed if you're using Linguan.
  • When I opened the project in Linguan it was able to find all the strings files, including those from the storyboard.

I'm satisfied now that I have the localization mostly under control. One thing I still need to look at is how does this affect testing. Hopefully any test framework that I used will be able to run the tests in all languages.

posted on May 19, 2012development


Starting out with Core Data

For my project, I need a way to store the model data that I will be generating. I certainly don't want to write a persistence layer for my model objects so I will definitely use a standard library for this. There are a number of options

  • Core Data. This provides an editor to create the objects and XCode will generate the required model classes for me.
  • Use a database like Sqlite directly. Core Data uses a sqlite database behind the scenes but instead I could create one directly and access it using a library like FMVH.
  • A service like Parse.com. This provides an online backend for apps.

I don't want to use the database directly as I prefer working with objects, so that would rule out sqlite for me. Parse.com is really interesting. Among other things, it provides an online site where you can see the data in a spreadsheet interface. This tutorial shows how you can use Parse.com to implement a todo list website. It's a real pity that iCloud doesn't provide a similar API to allow non-Apple devices access the data.

In the end I've decided to go with Core Data. The reasons for this are

  • It's an Apple standard library and one of the purposes of writing an app was to learn about iOS and Apple technologies. Where possible I've tried to stick to the Apple way of doing things as I can be sure that this approach will be supported in future - or if there is a new system, then a transition path will be provided.
  • Core Data works on the object level rather than the database level. I've programmed in objects for most of my career so this is familiar to me. I have a working knowledge of databases but I feel more comfortable using OOP.
  • I'm assuming that Core Data should integrate with iCloud better than other approaches. Thinking ahead I'd like to look at iCloud at some stage and learning Core Data first should make that a bit easier.

Magical Record and Mogenerator

There are some good Core Data tutorials out there. The best introduction that I found was the Stanford iOS course (lectures 13 & 14). To be honest, the code required to implement Core Data is fairly complex and verbose. To deal with that, I started looking for libraries which would improve the Core Data experience. The best I found is Magical Record. This library simplifies Core Data a great deal and provides loads of helper categories & functions. There is an excellent tutorial on MagicalRecord here. I also found this tutorial really good and it also includes a sample project which uses MagicalRecord.

Magical Record works well with another tool called Mogenerator. You download a .dmg from the site and install from that. There is a nice tutorial here. Mogenerator generates classes from the Core Data xcdatamodel file. The normal Core Data build can also do this but the advantage of Mogenerator is that it generates a second set of classes for each Core Data entity. This second set will never be overwritten so you can write custom code in these. The first set of classes will be regenerated each time the model gets updated.

Magical Record is available on Github. Like most iOS projects I've found there, it seems the standard way to integrate this with your project is to copy the source files into your code and work away. I'm not too comfortable with this approach and would prefer to keep third party libraries separate from my code. This would allow me to update these independently and share them between projects. I'll have to look into what options are available for this.

posted on May 15, 2012development


Joined the iOS Developer program

I've been fairly busy with the Start Your Own Business course so I haven't had much time to do iOS programming. It's time to get back into it now though, and so I've just paid my subscription to the iOS developer program. I'm looking forward to being able to run code on an actual device. It's been a bit limiting working on just the simulator and there's nothing like seeing your code running on the final hardware.

posted on April 29, 2012development


Where have all the SRPGs gone

I had a draft post pre-written earlier this year lamenting the decline of the SRPG game genre. In brief, I used to import these types of games all the time from America for my PS2. I assumed that this would continue for the PS3 and really enjoyed Valkyria Chronicles, but after that the genre has pretty much disappeared for the mainstream consoles. Even on PSN and Xbox live, there has been very little released (Vandal Hearts excepted). Modern games seemed to be limited more and more to mass market genres such as the 3D first person shooter.

However in the past month a surprising new development in game development has kind of invalidated my draft post. Veteran game designers have started to use Kickstarter to seek funding for niche game genres with some amazing results. The first big success on Kickstarter was Tim Schafer, Ron Gilbert and Double Fine raising over three million to make a new adventure game. I love the Monkey Island games so I backed this - it was actually the first thing I'd ever supported on Kickstarter. I have no idea if the game will be any good but given the caliber of the people involved, I think it's in safe hands. To be honest, the videos they've made for the project have been worth the cash already.

Following on from that Brian Fargo launched a Wasteland 2 project. This is an attempt to revive the party based CRPGs. This was another genre that I really enjoyed and which stagnated recently. Today's publishers aren't willing to put up the cash for these games. I've started to contribute to more of these gaming projects on Kickstarter (including a space based game - FTL and a Norse SRPG - The Banner Saga). Hopefully this will show that there is a sizable market for these games and they will be more likely to be funded in future. It's really interesting how much more invested in the games you feel once you back them on Kickstarter. For example, I'm really enjoying reading the updates from the game developers. If I was an indie developer I would definitely go down this route. The community that the Kickstarter project creates for your game might be as important as the funding itself.

Another other thing this has made me realize is how much reputation and track record matters. I had never heard of Wasteland 2 before backing it. However once Brian Fargo reeled off the list of games that he'd worked on, i.e. Fallout, Baldur's Gate and Icewind Dale (all of which still sit proudly on my shelf), I had no hesitation in subscribing. I would much rather see people like him develop games instead of leaving it in the hands of companies like Zynga. Trying to learn from this, I think that having a portfolio would be really valuable for a software engineer. Imagine the kind of CV/resume you'd have if you developed one app, website or side project per year and hosted these online. Given the frameworks and services that are out there e.g. Rails, Parse.com, Heroku for the web, iOS and Android for mobile, I think it's never been easier to create quality small scale projects. To be honest I wish I had started something like that years ago. If I was coming out of college now, one of the first things I'd do would be to register my name as a url and start hosting projects there. It's something small but would really pay off down the line.

posted on April 2, 2012gaming


Start your own Business Course

I've signed up for a Start Your Own Business course which is being run by the South Cork Enterprise Board. It's an eight week course taking three hours every Thursday. I've no intention of leaving my current job but if I'm going to be doing this on the side, then I'd like to know how to do it properly and what type of supports are out there.

I've gone to three nights already and I'm finding it very useful. I think that the process of creating a business plan focuses your mind on what you want to achieve. I've asked myself more questions about what I want to do with this app development in the past few weeks than in the previous two months. It's also interesting meeting people there who are setting up non software businesses and seeing what common problems and tasks we have. It's good to step outside the software/computing world for a bit and get a wider perspective on things. I hope to come out of this with a clear idea of where I want to take the app work and what I need to do to accomplish this.

posted on March 20, 2012business


Setting up a Blog on Octopress and Github

This post documents how I migrated the blog from Wordpress.com to Octopress. There are a number of bloggers who have written about switching their blogs to Octopress. I found these posts very helpful - Scott Muc, Matt Gemmell and Bigdinosaur Blog. The basic sequence of steps I followed was

  • Install Ruby.
  • Install Octopress.
  • Create account on Github.
  • Export previous blog from Wordpress and convert it to Markdown
  • Generate Octopress blog and publish it to Github.
  • In parallel I registered www.gerardcondon.com and set it up so that it pointed to the blog on Github.
  • Setup a drafts folder on Dropbox so that I can write posts from anywhere.

Ruby Setup

The first step is to install Ruby. If you want to, you can compile this from the source but the better option is to use a third party tool to install and manage Ruby. The one I used is RVM.

By default OS X Lion comes with 1.8.7 pre-installed but Octopress needs 1.9.2. (I tried 1.9.3 at first but Octopress reported an error). I read on Stack Overflow that it's not recommended to upgrade the default installation but instead to install the newer version alongside it. RVM is designed to manage multiple versions of Ruby on a system so it's a nice fit here.

The command to install Ruby is rvm install 1.9.2. However when I tried this I got errors complaining that the C compiler was LLVM based instead of gcc. To get around this I added the following flag rvm install 1.9.2 --with-gcc=clang. Now we can tell RVM to use version 1.9.2 with this command rvm use 1.9.2.

Install Octopress

Installing Octopress is very easy once Ruby is installed. The instructions can be found at Octopress Setup. The install command is rake install and then to build your website run rake generate. Octopress takes whatever pages and posts it finds under the source folder and builds these to a static website. These need to have particular file names and contents, so Octopress provides helper commands to generate a new post or page. These are rake new_page["page_title"] and rake new_post["post_title"] respectively.

Export from Wordpress

To export from Wordpress I simply used their export tool. This exported all the posts in their own html files. This would have been fine for Octopress but I wanted the whole site in Markdown, so I converted each post from html to markdown and added to the source/_posts folder.

Host on Github

Once you have the Octopress blog created you need to host it somewhere. I choose Github as it provides for free hosting of static blogs. Also if I do release some iOS code later it will be on Github, so there's no harm in getting it set up now.

This site has a very good explanation of what is going on with Github. Basically we build our website locally to a folder named public. We create a repository on Github for our webpage. Octopress then uploads the contents of the public folder to the master branch on this repository whenever we run the rake deploy command. It is recommended that you upload the site source to a source branch on the repository. That way you can always regenerate the website even if you delete the local files.

Register URL

I decided to register www.gerardcondon.com for this site as I didn't want to be tied to a Github url in the same way as I was tied to the Wordpress.com one. I didn't need hosting or anything special - just forwarding. I used Namecheap. The price is really cheap for a .com address - only 6 or 7 dollars a year.

There are instructions on Github Pages on how to set up the forwarding. You need to setup an A record to redirect to www.github.com for your url without the www part, i.e. gerardcondon.com will redirect to www.github.com. Then you need to create a CNAME file in github and then setup a CNAME redirect for the www part of the url, i.e. www.gerardcondon.com redirects to gerardcondon.github.com. However I ran into some problems doing this on the namecheap site. When I tried to setup the CNAME I got the following errors

Improper records were NOT saved!

There were issues with some records and they were either set to default or completely removed. Please review the issues below and update again appropriately.

INVALID_ADDR: 'gerardcondon.github.com/' should not be an IP/ URL for CNAME record. (host name: www)

However I just connected to the online chat support and the person assigned to me fixed it up in a few minutes - I have to say they were really helpful. This DNS stuff takes a while to settle down - I think it was a day or so before it had propagated out. Since then I've had no trouble with it.

Octopress tweaks

I've made a few tweaks to Octopress to suit my own tastes.

  • I changed the indented-lists setting to true in sass/custom/_layout.scss. Previously the numbers and bullets for lists were not in line with the rest of the post text but instead were placed in the left margin.
  • I reduced the size of the blockquotes in the sass/base/_typography.scss file, from 1.2 em down to 1 em to be the same size as normal text.
  • I changed the solarized theme from dark to light in sass/base/_solarized.scss.

It's really easy to make changes to Octopress, there is a folder called sass with most of the style stuff. There are a few configuration files also which can be updated. One nice thing about checking all this stuff into github is that you can go back and see what style updates you made in previous commits.

Add Draft folder and sync with Dropbox

At this stage Octopress was installed on my Macbook Air and working perfectly for me. One limitation of this setup was that I could only edit posts from that machine. I didn't mind only being able to regenerate the site from the Air as that's not a common task, but I wanted to be able to write posts from anywhere. I also wanted the ability to write draft posts and not have Octopress automatically publish those.

I found a technique for managing draft posts on Frozen Bytes. This allows you to create a drafts folder and provides commands for moving posts between the draft and published state.

Using this, I created a folder called drafts in Dropbox. I then symlinked to this from inside the sources directory on the Air. All my drafts are now available in Dropbox and I can edit these anywhere. This is especially useful when editing from iOS as there are a number of markdown editors which can edit files on Dropbox.

Summary

I think that's everything! It was fairly straightforward in retrospect to set up. The new setup works really well. I'm very happy with the look of Octopress and the editing workflow in markdown is much better than using the Wordpress editor. Looking forward to using it in future.

posted on March 4, 2012octopress


OS X Mountain Lion

Apple has just announced Mountain Lion, the latest update to OS X, and it looks to have some interesting features. The main one I'm looking forward to is the addition of AirPlay to the Mac. I love being able to stream video from the iPhone to the Apple TV. It's really handy for the iTunes U lectures. However for normal videos that I have on the Mac, it's annoying to have to convert them via Air Video Server on the Mac and then use Air Video on the iPhone to get them to display on the Apple TV. Having AirPlay on the Mac stream directly to the Apple TV will be very handy. According to the docs, it's just for streaming applications and presentations but perhaps they will open it up to interactive applications in future. I wonder what the latency would be like on this and if eventually it would be possible to play games via the Apple TV.

I'm finding that as I integrate more and more Apple devices into my setup, they all make each other work better. AirPlay is one example of this. Another is iTunes match which really starts to excel when you have multiple devices. Previously it was impossible to keep multiple iTunes in sync. It was a nightmare trying to add new music as it had to be added to each library separately. Now my music library is always in sync everywhere and when I add music to one library, it gets uploaded and is available on all others immediately. I haven't always been too impressed with Apple's cloud services (i.e. MobileMe was a bit of a disaster) but they've got it right with iTunes Match.

posted on February 22, 2012apple


Code Coverage Updates for Xcode 4.3

In a previous post, I described how I got code coverage up and running in Xcode 4.2. Apple have just released Xcode 4.3 and unfortunatly updating to this has broken my code coverage. The reason is that 4.3 removes the /Developer folder and moves this internally to the Xcode.app package. While this has good consequences - it should be possible to update Xcode from the App Store like a normal app - unfortunately it has also removed the libprofile_rt library from /Developer/usr/lib. I haven't been able to find a new version of this library in Xcode 4.3. When I tried using the version from 4.2, I got "mach-o but wrong architecture" errors.

This means that when building my unit tests with Coverage I get link errors saying that I am missing llvmgcda functions (llvmgcdastartfile, llvmgcdaincrementindirectcounter, llvmgcdaemitfunction, llvmgcdaemitarcs). I searched on Google to try and find a solution for 4.3 but it seemed all solutions were for 4.2 so I needed to try to solve this myself. The solution I came up with is fairly hacky. I'm hoping that as more people upgrade to 4.3, a better solution will be found and I can switch to that.

My solution is to take the actual file which contained the gcda functions in libprofile_rt, add it to my own source code and compile it myself. The file in question can be found on llvm.org - here. To get it to build locally I deleted the win32 and sys includes (lines 27 to 31 inclusive) and replaced the llvm include (line 23) with #include "stdint.h". This builds fine using the Coverage build configuration and outputs the same gcda and gcno files as before. To make sure that this code doesn't end up in the released project by accident, I've included it in the unit test bundle rather than the app bundle. This is fine for me as I only need coverage when running the tests anyway.

Update: Some feedback from Tom Black, who emailed me to point out that libprofile_rt can be found in /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/usr/ However this library did not work for either of us. Instead we got errors like The bundle “GCUtilsTests.octest” couldn’t be loaded because it is damaged or missing necessary resources. Library not loaded: @executable_path ... libprofile_rt.dylib Reason: image not found
Also this library didn't produce .gcda files but instead generated .dia files which didn't work in Coverflow.

What worked for Tom, but not for me, was not to include libprofile at all. This removed these errors and another incompatible binary error. Now however he got the following error. Detected an attempt to call a symbol in system libraries that is not present on the iPhone: fopen$UNIX2003 called from function llvm_gcda_start_file He found the solution to this issue here. I still got link errors when I followed this though so I need to stick with my original solution.

Update: Another commenter Rajiv emailed me to say that creating a new target for his project made the coverage work for him. It generated the .gcda and .gcno files when he exited using exit(0). I've tried creating a new simple iOS app and I don't get any errors for this when I enable coverage.

One thing which might explain why it still doesn't work for some of my projects is the type of project being built. My original project was a static library. I tried to create a new static library project and when I try to enable coverage I get the same link errors as above.

posted on February 21, 2012development


Apple's New Introduction to iOS Development

Apple has posted a new guide to iOS development which ties together all the various strands of creating an app. (via Loop Insight). Looks really nice.

posted on February 18, 2012development


Tags

By year

  1. 2020 (14)
  2. 2019 (17)
  3. 2018 (2)
  4. 2017 (11)
  5. 2016 (3)
  6. 2015 (6)
  7. 2014 (3)
  8. 2013 (11)
  9. 2012 (25)