Setup Android Continuous Integration (CI) for Bitbucket in 1 minute.

Intro

Continuous Integration (CI) is the process of automating the build and testing of code every time a team member commits changes to version control.

CI brings benefits for every team, from one-(hu)man-teams to big teams, by detecting integration errors as quickly as possible. Individual developers can ensure that the “minor change” they submit without hitting “Run” in Android Studio doesn’t break anything and big teams contributors can ensure that the feature they worked in isolation for the last week doesn’t introduce a regression.

Atlassian’s Bitbucket is a great version control hosting provider for indie developers, offering not only unlimited private Git repositories but also free (limited amount) CI/CD using their Pipelines feature! I have been using Bitbucket for microtasks project but never bothered with setting up CI because I considered it too hard. As it turns out, it’s a 1-minute setup!

1-minute setup

All the credit goes to Ming C from this StackOverflow post. And it’s just 2 easy steps (actually the “1 minute” estimation might be an overestimation if everything goes right :)

Select Pipelines in Bitbucket

From the side navigation bar in your Bitbucket project, select Pipelines and then Java (not really necessary, it’s just pre-filling the editor).

Commit the Pipeline configuration

In the online editor, fill the content of bitbucker-pipelines.yml:

image: mingc/android-build-box:latest
pipelines:
default:
- step:
script:
- chmod +x gradlew
- ./gradlew assembleDebug

Commit and that’s all! Now everytime you commit to the main branch, assembleDebug Gradle task will be executed to verify that the app builds just fine. To run your unit tests instead of just building, replace assembleDebug with test.

(Optionally) Going deeper

Brief Pipelines explanation

Pipelines are basically running a Docker image and then execute the commands in the scripts section. The android-build-box image I think contains everything (SDK 16–26, Support Library, Play Services, etc) that a typical modern Android app might need (and more). For more specific needs, you will need to build your own Docker image.

Gradle task(s)

You can select to run more than one Gradle task from your Android project by appending more lines to the scripts section (to see all Gradle tasks from Android Studio, View -> Tool Windows -> Gradle). A real CI system will run tests to ensure that a new commit does not introduce a regression (i.e. re-introduce an old bug). Be cautious of the time limit the free Bitbucket plan provides, 50 minutes per month. Running too many tasks/tests might consume this limit pretty quickly.

Periodic integration

You can also configure the Pipeline to run periodically, like every hour/day/week. If you have a bigger project with multiple contributors, this is probably needed. Just select Schedules button from the Pipelines view in Bitbucket.

Local Pipelines debug

At some point, something in the Docker image, Pipelines, or your project will stop working and you might need to emulate what Pipelines are doing locally to debug the issue. To do this follow the instructions in Bitbucket website, or for this specific image:

  1. Get Docker and download the android-build-box image (Warning: It’s a ~5GB image):
docker pull mingc/android-build-box:latest

2. Get an interactive shell into the Docker image, with the same restrictions (i.e. RAM, swap memory, etc):

docker run -it --volume=/PATH/TO/YOUR/SRC:/localDebugRepo --workdir="/localDebugRepo" --memory=4g --memory-swap=4g --memory-swappiness=0 --entrypoint=/bin/bash mingc/android-build-box:latest

3. Run the commands in the scripts section and debug the issue(s).

Conclusion

I think that CI is extremely useful for detecting issues early on and since it’s that easy (and free) to set it up, everyone using Bitbucket for version control should have it enabled!

P.S. If you are like me and enjoy being productive throughout the day, check out microtasks, a task-as-undismissable-notification manager that helps you remember the small things that matter :)