Do you know that feeling, while messing around with an Android app, you feel the sudden urge to put in under continuous integration? Me neither. But I had that feeling nonetheless.

First of all: I’m writing this post while my new Docker account is doing a continuous integration build on a Dockerfile. Yes, you read that correctly, I’m doing CI on a Docker file, not on an Android project. Why? Read on.

While doing some Android development with my girlfriend, you can suddenly feel the urge to put things under continuous integration, especially if you don’t want to break the carefully written unit tests you produced ten minutes ago. So, I tried.

To sketch our situation: we’re committing our changes to the amazing SaSS service of GitLab.com. I’m dead serious. Drop GitHub, GitLab is a beauty and you wont have vendor lock-in or ethical freedom issues anymore.

I crafted some nice Unit tests for my SugarORM model classes, so I could ensure myself that these things worked. That’s not easy either; if you want to run those JUnit4 test cases without having to boot an entire Android VM, you’ll have to mock the SQLite backend that SugarORM uses.

@RunWith(RobolectricGradleTestRunner.class)
@Config(constants = BuildConfig.class, sdk=18)
public class ORMTest extends ApplicationTestCase<com.orm.SugarApp> {
    public ORMTest() {
        super(com.orm.SugarApp.class);
        //createApplication();
    }
}

So, you’ll have to use something like Robolectric, which will happily mock out most of the Android runtime.

So, after I made those Unittests run, I though “Hey, why don’t I try to have GitLab CI run them?”, so I did<

git checkout master
git checkout -b ci

and started toying around. My commit log so far for that branch:

9f110a7 Try to get gitlab-ci working
258555d Install java 8
69b3023 Install java from external repo
b77b6cf Add repository installer for java repo
f416a54 Try with a docker image instead
954f5ef Docker container name spelling
4d418b0 Use our own Android-sdk docker image to build stuff
fa5a878 Wrong name. Corrected

No worries, I’ll squash and rebase them into more sane messages. It’s just to get GitLab CI working. Some explanation:

diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
new file mode 100644
index 0000000..d1c1a16
--- /dev/null
+++ b/.gitlab-ci.yml
@@ -0,0 +1,3 @@
+build:
+    script:
+        - ./gradlew

The first commit just tries naively to execute the gradlew script included in Android Studio projects. I guessed that wouldn’t work, except if the publicly available Shared Runners in  GitLab had Java on board. Nope, they didn’t.

ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.

So, we’ll install Java 8, right? I didn’t want to install Oracle JDK, because ethical and license issues, but as the Shared Runners run on Ubuntu 14.04 (citation needed), they don’t have the package openjdk-8-jdk.

Next idea: add the ppa! add-apt-repository ppa:openjdk-r/ppa && apt-get update && apt-get install openjdk-8-jdk. Nope, Ubuntu Server doesn’t come with ppa support. apt-get install software-properties-common? Apparently, GitLab doesn’t like that either.

But wait. GitLab runs on Docker, perhaps I can provide a Docker image, like java:8-jdk? Apparently, that’s right!

diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index 0ec0b74..5be6fbc 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -1,8 +1,4 @@
-before_script:
-    - apt-get install software-properties-common
-    - add-apt-repository ppa:openjdk-r/ppa
-    - apt-get update
-    - apt-get install openjdk-8-jre
+image: java:8-jdk
 build:
     script:
         - ./gradlew

But now, of course, ./gradlew only downloads everything but the Android SDK. There are some Java 8 images that do Android, but they have Oracle Java and use older API targets (we target API 23 with compatibility to API 15) or they are on Java 7 (we use fancy new Java 8 features).

So, let’s learn Docker. I’ve seen it working before, and to be honest, I like it. Just specify “Hi Docker, I’d like to use java:8-jdk” and say whatever you want to install on top of that. Docker will take care.

Now, I already managed to have the Shared Runners of GitLab CI import my Docker image, which I made publicly available on GitHub (because Docker Hub doesn’t integrate with GitLab yet, otherwise I’d post it on my GitLab profile) and Docker Hub, so everyone can use it.

After some struggling with the well documented android sdk cli tool (/s), I got it to work. The trick is to search for the “packages” you want by using something along the lines of android list sdk --all --extended | grep Support -A5 -B2. That will print out every package with the term “Support” in it. Most importantly, two lines above that match, there will be the package name you’ll need.

So, I woke up this morning with a good build of that Docker image, I clicked the “Retry” button on the GitLab CI interface. All I had to do was append ./gradlew build and ./gradlew test to my .gitlab-ci.yml file et voila! Builds and tests are passing!

Did I mention I really like GitLab?