Hosted CI Blog

Hosted Continuous Integration for iOS and Mac

New Feature: Support for Xcode 6, iOS 8 and Swift

With Xcode 6 GM coming out this week we couldn’t wait anymore and so pushed support for Xcode 6 into production. Now you should be able to compile and test your projects with iOS 8 SDK, including code written on Swift.

For now however Xcode 6 is still marked as beta, so you have to enable it explicitly by selecting iOS 8 SDK when configuring your project targets:

That’s all, after you save project settings new builds would use iOS 8 SDK. Please contact us at ask@hosted-ci.com if you have any problems / questions.

New Feature: Builds Using Xctool Instead of Jenkins Xcode Plugin

As some of you may have noticed – all of the newly created / updated projects on Hosted CI use xctool with custom shell scripts in build process, instead of relying on Xcode plugin for Jenkins as before.

There are several important reasons for this change:

  • Jenkins plugin is inflexible and hard to make changes to. One has to edit Java code, recompile .jpi file, deploy it to Jenkins and then restart Jenkins to make any change to the build commands used. With our own shell scripts and xctool it is just a matter of editing shell script file.
  • Jenkins plugin relies on using xcodebuild which produces hard to decipher output that is full of garbage. xctool has much cleaner output.
  • xctool makes running tests easier and even allows potential to parallelize logic tests.
  • xctool has configurable reporters which allow to parse and analyze results easier at later stages of build process

xctool screenshot

I hope that everyone benefits from this change. If you have any questions / comments don’t hesitate to contact us at ask@hosted-ci.com.

How We Fixed Heartbleed Bug at Hosted CI

I guess you’ve already heard about terrible Heartbleed bug in OpenSSL library.

So I’m here to tell you some good news – we didn’t even have to fix it at all. :)

Our server uses OpenSSL version 0.9.8, which isn’t vulnerable to this bug. So you don’t have to change your passwords at Hosted CI, unless you have reused them on other sites. Sometimes it pays off to use conservative Linux distro like Debian.

If you have any questions or need help with Hosted CI, please write to me at ask@hosted-ci.com.

Let’s Meet During WWDC

I’m going to WWDC this year and will stay in San Francisco from Sunday 9th of June to Friday 14th. So if you either attend WWDC or just happen to live near – I’d like to meet to discuss Hosted CI, contiuous integration and programming in general.

If you are interested, please leave your e-mail here – I’ll keep you updated on time and location of meet-up.

I haven’t decided yet when and where exactly to meet, so I’m open to your suggestions – drop me a line to ask@hosted-ci.com.

New Feature: Test Your Apps With Real People via Amazon Mechanical Turk

I’ve constantly met with problems while running application tests from command line during development of Hosted CI. Apple doesn’t seem to care much about usability of it’s command line tools.

So given that iOS developers generally don’t unit test, we’ve decided that a radically different approach is needed.

Machine would never test your app better than a human person can. So starting from today we provide an option (on Premium and Max plans) to enable human testing of each otherwise successful Hosted CI build. It is made possible thanks to availability of human intelligence API from Amazon Mechanical Turk service, which we use through modified version of Jenkins Xcode Plugin.

As distributing your iOS apps to random people is quite a hassle (having to manage all those UDIDs) – we take care of that for you. We sign your app with our own distribution certificate and use own provisioning profile, so that you don’t have to deal with it.

Note that it means that apps using In-App Purchase and Push Notifications won’t work without modifications, please contact our support if you need to use aforementioned functionality.

P.S. I plan to push appropriate updates to my fork of Jenkins Xcode Plugin to allow you to use same approach on your own Jenkins server. Stay tuned.

Updates to Plans & Pricing

By popular demand we’ve decided to make few changes to our Plans & Pricing. The changes are already in effect for some time, but I haven’t announced it before.

  • Max plan (with unlimited projects) is now just $199 (compared to $499 previously)
  • We’ve added Indie plan (costing just $19) available for inidividual developers and unfunded startups

Max plan includes 750 hours of build time and 80 GB storage. It is targeted for big iOS / Mac development agencies.

Indie plan includes 10 hours of build time, 10 GB storage and maximum of 2 active projects. It’s ideal for starting out, but cannot be used by agencies.

Check out updated plans and register to try out our service. To speed up invite process you may drop e-mail to ask@hosted-ci.com.

New Feature: Clean-Up iOS Simulator and Jenkins Workspace

Meet two small and closely related new features:

  1. iOS Simulator data is now fully cleaned-up before each build so that tests are consistent.
  2. There is ability to force clean-up of Jenkins workspace if it somehow gets messed.

New Feature: CocoaPods Support

On popular request I’ve finally added CocoaPods support to Hosted CI builds. It’s been in development for quite a while (as I am using CocoaPods myself), but it took time to sort out issues with it.

For projects using CocoaPods there is now the Use Podfile checkbox when selecting build targets:

It is checked by default and results in following:

  • pod setup, pod install and pod update are called before build
  • our script generates appropriate .xcscheme files for your targets
  • xcodebuild is called with .xcworkspace file corresponding to your project, not .xcodeproj itself

So now you can enjoy package management awesomeness!

Configure Jenkins to Include Commit Logs With TestFlight Builds

Motivation

Inspired by the FullContact’s post I’ve decided to implement a feature to include commit messages in TestFlight release notes.

However FullContact’s solution is quite hacky and is Git-only (while we have to support Git, Mercurial and Subversion). So I had to put together my own solution which is described in this post.

Idea

Implementing separate code for each of the version control systems seemed like overkill (especially given the same info is already parsed by Jenkins). I’ve decided to fetch the commit logs using Jenkins REST API, however after further investigation I used a simpler hack.

Jenkins stores information about builds in a relatively straightforward order, which looks something like following (included only stuff relevant for our task):

JENKINS_HOME
 +- jobs
     +- [JOB_NAME]
         +- lastSuccessful (symlink to the last successful build folder)
         +- builds
             +- [BUILD_NUMBER] (for each build, symlink to corresponding build folder)
             +- [BUILD_ID] (for each build, contains all data, named based on build date)
                 +- changelog.xml (this file contains change logs that we need)

Individual changelog.xml files contain data in folowing format:

Changes in branch origin/master, between b34f501dbddae6ccc962797945d44b7f37ce38f6 and d24808f7bd6c3c84ba256913350472e370cbc42e
commit d24808f7bd6c3c84ba256913350472e370cbc42e
tree f4f538a6f8867b4f3ee1ae1d18676c170ebcdc54
parent 8fa86545108ac070c4e840b9e027b056b379b100
author Vladimir Grichina <vgrichina@componentix.com> 1358642236 +0200
committer Vladimir Grichina <vgrichina@componentix.com> 1358642236 +0200

    Added CalendarDemo as dependency for tests

:100644 100644 72f0d09be20b86ec26f19af064dddd96fc186169 be53875b416ba4c968c31b5edfe8287aded833ff M  Calendar.xcodeproj/project.pbxproj

commit 8fa86545108ac070c4e840b9e027b056b379b100
tree 0007a2a3259f6b965a34b43c4f6448f7afba45d9
parent 121a19c952b338af3506e05fac70500075270207
author Vladimir Grichina <vgrichina@componentix.com> 1358642075 +0200
committer Vladimir Grichina <vgrichina@componentix.com> 1358642075 +0200

    Uncommented commented out tests

:100644 100644 1e0c797595d2b09491aa0939d4a86dd2bf5766ca 4cd227fd5b19d2a1ec80e8adb67fecdbe727fdd1 M  CalendarTests/CalendarViewSpec.m

So basically our script has to do following:

  1. Get build folder linked to by lastSuccessful symlink
  2. Find changelog.xml files in all build folders that go after it (in lexicographical order)
  3. Select relevant info from changelog.xml files
  4. Output resulting message for TestFlight upload script

Implementation

Most of Hosted CI code is using Node.js, so I used it for this script too (slightly adapted here to be standalone):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
function filterChangeLog(changeLog) {
    return changeLog.split("\n").filter(function(it) {
        return it.startsWith("    ");
    }).map(function(it) {
        return it.substring(4);
    }).join("\n");
}

function printLogSinceLastSuccess(jobName) {
    var projectDir = path.join(process.env.HOME, ".jenkins/jobs", jobName);
    var lastSuccesfulPath = path.join(projectDir, "lastSuccessful");
    var lastSuccessfulBuildPath;
    if (fs.existsSync(lastSuccesfulPath)) {
        lastSuccessfulBuildPath = path.join(projectDir, fs.readlinkSync(lastSuccesfulPath));
    }
    var buildPaths = fs.readdirSync(path.join(projectDir, "builds")).sort();
    buildPaths.forEach(function(buildPath) {
        if (buildPath.length < 6) {
            return;
        }

        var fullPath = path.join(projectDir, "builds", buildPath);
        if (!lastSuccessfulBuildPath || fullPath > lastSuccessfulBuildPath) {
            var changelogPath = path.join(fullPath, "changelog.xml");
            if (fs.existsSync(changelogPath)) {
                console.log(filterChangeLog(fs.readFileSync(changelogPath, "utf-8")));
            }
        }
    });
}

var args = process.argv.slice(2);

printLogSinceLastSuccess(args[0]);

Now it is just needed to use it in Jenkins – I use script similar to the following:

1
2
3
4
5
6
COMMIT_LOG="Changes since last build:\n"`/path/to/script.js "$JOB_NAME"`
curl http://testflightapp.com/api/builds.json \
    -F file=@"$WORKSPACE/PROJECT_DIR/build/CONFIGURATION-iphoneos/TARGET_NAME-CONFIGURATION-$BUILD_NUMBER.ipa" \
    -F api_token="API_TOKEN" -F team_token="TEAM_TOKEN" \
    -F notes="This is an autodeploy build $BUILD_ID from http://hosted-ci.com\n\n$COMMIT_LOG" \
    -F notify=True -F distribution_lists="DISTRIBUTION_LIST"

Shameless plug

To avoid all aforementioned pain-in-the-ass you may wish to subscribe to Hosted CI, which provides complete CI solution for iOS / Mac apps without need to waste time tinkering with Jenkins configuration.

Configure Code-Signing for CI Build

This post duplicates our knowledge base entry here.

Code-signing of iOS apps is often quite tricky and so questions on it arise.

It is common to have situations where build on different machines needs different code-signing settings Developer may use his own iPhone Developer identity to test app on his device, however appropriate iPhone Distribution identity has to be used for “Ad-Hoc” builds sent to testers.

When using continuous integration builds it may rise the problem: if identity set in Xcode project is iPhone Developer and it is committed into source code repository – it cannot be used by build server as is.

The solution is simple. Xcode has concept of build configurations and by default two of them are available: Debug and Release.

So there are two ways to solve the problem:

  1. Configure iPhone Developer for Debug builds and iPhone Distribution for Release builds. Then use Release configuration in CI builds.

  2. Add configuration specific to CI build and make it use appropriate iPhone Distribution identity. Then use it in CI builds.

In both cases you’ll be able to commit Xcode project into repository and then not have to override identity for each specific build. However in first case developer still occasionally may need to alter code signing identity to debug Release builds.