Continuous Integration in Android with Jenkins and SVN

In this article I discuss how to implement continuous integration for an android project using a Continuous Integration (CI) server, Jenkins, and SVN.

Setting up project and test project

First, create an application project in eclipse. Let’s assume it’s called ‘project’ and is at /home/user/Documents/project

Next, create a test project for the aforementioned project. Let’s call it ‘test project’. So, in eclipse, go to File > New > Android Application Project. Uncheck ‘Create Project in Workspace’ and set the Location field to /home/user/Documents/project/tests. This way, both project and test are under one folder and can be managed easily with version control software. Also, uncheck the Create Activity checkbox.

After creating test project, we need to add the main project to its build path so that it can access the main project resources. To do this, right click the test project in Package Explorer view and click Properties. Then click ‘Java Build Path’ in the left sidebar. Click on Projects tab, click Add and choose project. Click OK to save.

Update the AndroidManifest file of the test project so it reads something like:

<?xml version="1.0" encoding="utf-8"?>

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.project.tests"
android:versionCode="1"
android:versionName="1.0" >
<uses-sdk android:minSdkVersion="8" />
<instrumentation
android:name="android.test.InstrumentationTestRunner"
android:targetPackage="com.example.project" />
<application
>
<uses-library android:name="android.test.runner" />
</application>
</manifest>

Setting up Ant

Jenkins, our CI server, requires Ant in order to manage Android projects. So we must supply Ant information to the project (build script and properties file). Thus we need to install Ant

Get Ant from http://ant.apache.org/bindownload.cgi. Unpack it somewhere on local machine. Create an environment variables ANT_HOME and JAVA_HOME and add the path to the directory containing ant binary to your PATh by adding the lines below to your ~/.profile file. Be sure to adjust the paths accordingly.

export JAVA_HOME=/usr/lib/jvm/java-7-openjdk-amd64

export ANT_HOME=/home/user/development/apache-ant-1.9.2

PATH="${ANT_HOME}/bin:$PATH"

Test that ant is installed properly by running the command ‘ant’ on a terminal. You should see something like

Buildfile: build.xml does not exist!

Build failed

Generating ANT build scripts

cd to your project directory and run the following command:

android update project -p .

This will update and rebuild your project, then generate a build.xml file in your project’s root folder which will be used by ANT to build your project.

cd to your test project directory and run the following :

android update test-project -m .. -p .

Note that the general form of the command is: android update test-project -m _PATH_TO_ANDROID_PROJECT -p _TEST_PROJECT_PATH_

This will update and build your test project, generating a build.xml file in its root folder. So we now have two build.xml files.

Add the test project’s build.xml and ant.properties file to version control. Also add the project’s build.xml to version control. Do NOT add the test project’s local.properties file to version control as that is machine-specific.

Building with ANT

cd to your project’s root directory and run the following :

ant clean debug

This should build the project.

Next, cd to your test project directory and run the following code:

ant clean emma debug install test

This will build the test project, run code coverage with the EMMA code coverage tool, install the application on your emulator or device and run your JUnit tests on the application.

Install Jenkins

Now we will install Jenkins on the CI server. Website: http://jenkins-ci.org/. For ubuntu servers, this involves running the following code:

wget -q -O - http://pkg.jenkins-ci.org/debian/jenkins-ci.org.key \
	| sudo apt-key add -

sudo sh -c 'echo deb http://pkg.jenkins-ci.org/debian binary/ > \ 
	/etc/apt/sources.list.d/jenkins.list'

sudo apt-get update

sudo apt-get install jenkins

By default, Jenkins listens on port 8080. To avoid having to type this port number in the browser everytime, you could proxy the web server to point port 80 to 8080. For that, assuming you use apache, create a file /etc/apache2/sites-available/jenkins and add the following code to it:

<VirtualHost *:80>


	ServerAdmin webmaster@localhost

	ServerName ci.company.com

	ServerAlias ci

	ProxyRequests Off

	<Proxy *>

Order deny,allow Allow from all </Proxy> ProxyPreserveHost on ProxyPass / http://localhost:8080/ </VirtualHost>

Enable mod proxy, enable the site and restart apache using the following code:

sudo a2enmod proxy
sudo a2enmod proxy_http
sudo a2ensite jenkins
sudo service apache2 restart

Now Jenkins is installed. You should be able to access it by going to http://ci.company.com/

Install Android SDK on the server and all relevant versions.

Install Android Emulator Plugin. This involves, going to the main page, then clicking on Manage Jenkins > Manage Plugins. Then click on Available tab, find the plugin, check the checkbox next to it, and click ‘Install without restart’ button.

Check if Subversion plugin is installed. If it isn’t, check if it available for download. If it isn’t, download and install it manually. To do this, visit the plugin page at https://updates.jenkins-ci.org/download/plugins/subversion/, download the latest plugin, and move the downloaded file into Jenkin’s plugin folder at /var/lib/jenkins/plugins/

System Configuration

Configure required paths (e.g. to ANT, SDK, etc) by going to Manage Jenkins > Configure System

Create Project on Jenkins

Create a new job by going clicking New Job. Enter name of job and check the Build a free-style software project radio.

Next, configure the new job.

Go to the homepage and click on the job. On the job page, click Configure link on the left sidebar. Enter the project name and description. Under Source Code Management, check Subversion Modules. Enter the url for the repository.

If your repository requires authentication, then an error message will show saying Jenkins couldn’t access the repository. To fix this, first create a new svn user for Jenkins on your repository. On the error message section, there will be a link for Credentials. Click that link and enter the username and password of a user you have just created. The error message should disappear. Click the Save button.

Now test that the job can access the repository. On the job’s page, click Build Now. Jenkins should checkout the project and create a workspace. On the workspace you should see files for the project.

Building project with ANT

Next, we will configure Jenkins to build the job with ANT.

Go to the job page and click Configure.

Under Build section, click Add Build Step button. Select Invoke Ant build step on the dropdown that appears.

In the build step’s command textfield, enter the following:

clean debug

This will build a debug version of the app. Test that it runs fine by saving and clicking Build Now link.

If there’s an error about sdk.dir not found, you can add this to the step by visiting Configure page, clicking Advanced button for the build step, and entering the following line, where the path is changed to reflect where you installed the sdk. I assume you should see this error if you entered the data under System Configuration:

sdk.dir=/home/user/android-sdks

Run android emulator to run tests

On the configure we need to run the emulator in order to run tests, so check the Run an Android emulator during build checkbox. A form will appear asking for avd details. Fill it in as shown below

Add another build step.. Choose Invoke Ant. Set the command to

clean emma install debug test

Next, tell Jenkins where the build file is for this step. To do this, click Advanced button, and enter the following for Build file:

tests/build.xml

Test it by saving and clicking Build Now link. If there’s an error about sdk directory, then go back to the Configure page, click Advanced for this step, and enter the following for Properties:

sdk.dir=/home/user/android-sdks

where the path is updated accordingly.

Save and build the project.

Tip: while build is in progress, you can move the mouse next to the build time on the main page, click the down arrow button that appears and click Console output in the dropdown that appears. This will show you the commands being run in real-time.

Publish JUnit and EMMA coverage report

Next, we will make Jenkins generate JUnit test result and EMMA coverage report when tests are run.

To do this, go the Configure page of the job. Under Post-build Actions, add an action called Publish JUnit test result report. Set Test report XMLs to tests/junitreports/*.xml

Add another Post-build action and this time choose Record Emma coverage report. Set the Folders or files containing Emma XML reports to tests/bin/coverage.xml

Save.

Note that JUnit reports get stored on the emulators and Jenkins doesn’t have access to this. To get around this problem we can use the android junit report by Jason Sanky.

Here are the steps:

Visit the Jsanky github at https://github.com/jsankey/android-junit-report. Go to the downloads page and download the latest android-junit-report jar.

Place the jar file in your test project’s libs folder.

Update the test project’s AndroidManfest file. Specifically, change the android:name attribute of the instrumentation tag from

android.test.InstrumentationTestRunner to com.zutubi.android.junitreport.JUnitReportTestRunner

cd to the test project’s root folder and edit ant.properties. Add a line as follows:

test.runner=com.zutubi.android.junitreport.JUnitReportTestRunner

We also need to update the run configuration of the test project to use the library. To do this, click on the arrow next to the Run button and click Run configurations. Under Android JUnit Tests, click on the test project. In the Test tab, update the Instrumentation runner to com.zutubi.android.junitreport.JUnitReportTestRunner

Click Close .

Next, we need to add a target called fetch-test-report to the test project’s build.xml file. Edit that file and add the following code:

<target name="fetch-test-report">
<xpath input="${tested.project.dir}/AndroidManifest.xml"
expression="/manifest/@package" output="tested.package"/>
<echo>Downloading XML test report...</echo>
<mkdir dir="junitreports"/>
<exec executable="${adb}" failonerror="true">
<arg line="${adb.device.arg}"/>
<arg value="pull" />
<arg value="/data/data/${tested.package}/files/junit-report.xml"/>
<arg value="junitreports/junit-report.xml"/>
</exec>
</target>


Save and close the file.

Finally, update the second Ant build task in the Configure page of the job in Jenkins. Change the command from

clean emma debug install test

to

clean emma debug install test fetch-test-report

Press Save button.

Click Build Now. The project should build and you should get both coverage and junit report.

Automatic Build

If you want to notify Jenkins immediately commits take pace and trigger a build automatically, you can do this using a post-commit hook. Here’s how.

In the project’s repository, create a file called post-commit in the hooks folder.

Add the following code to the file:

#!/bin/sh
REPOS="$1"
REV="$2"
UUID=`svnlook uuid $REPOS`
/usr/bin/wget \
  --header "Content-Type:text/plain;charset=UTF-8" \
  --post-data "`svnlook changed --revision $REV $REPOS`" \
  --output-document "-" \
  --timeout=2 \
  http://ci.company.com/subversion/${UUID}/notifyCommit?rev=$REV
# let's build the project too
/usr/bin/wget \
  --output-document "-" \
  --timeout=2 \
 http://ci.company.com/job/job/build

Note that on the last line, the general format of the link is

http://ci.company.com/job/YOUR_JOB_NAME_IN_JENKINS/build

Save and close the file. Make it executable and make sure the svn user (e.g. apache) is able to execute it.

That’s it. When you commit henceforth, Jenkins will create a build.