The Social App: CI Server Setup

Rafael Toledo
The Social App
Published in
5 min readApr 9, 2018

--

If you don’t know about this project’s motivation, read the first post here.

In the previous post, we’ve created the repository with an empty project, and configured the repository with the persistent branches that will be part of our Git Flow.

Today, we’ll create an initial setup for our CI server. I call it initial because this configuration is not final. During the development of our app, we’ll perform some adjusts, to better fit our needs at that time. To help us with this task, I will choose CircleCI. Why? Firstly because of its support for Docker, which makes the environment much easier to configure, in case we need to customize the tooling. In addition, it has a generous free quota not only for opensource projects (which is being the case here), but also for private projects on Github or Bitbucket.

The first step is to log in to CircleCI with our Github account and tap Setup Repository.

In the next screen, we select a Linux machine and Gradle as a build tool. In this same screen, a default configuration file will be offered, to be placed in the .circleci folder of the repository, named config.yml. The initial content of this file is:

# Java Gradle CircleCI 2.0 configuration file
#
# Check https://circleci.com/docs/2.0/language-java/ for more details
#
version: 2
jobs:
build:
docker:
# specify the version you desire here
- image: circleci/openjdk:8-jdk
# Specify service dependencies here if necessary
# CircleCI maintains a library of pre-built images
# documented at https://circleci.com/docs/2.0/circleci-images/
# - image: circleci/postgres:9.4
working_directory: ~/repo environment:
# Customize the JVM maximum heap limit
JVM_OPTS: -Xmx3200m
TERM: dumb
steps:
- checkout
# Download and cache dependencies
- restore_cache:
keys:
- v1-dependencies-{{ checksum "build.gradle" }}
# fallback to using the latest cache if no exact match is found
- v1-dependencies-
- run: gradle dependencies - save_cache:
paths:
- ~/.gradle
key: v1-dependencies-{{ checksum "build.gradle" }}
# run tests!
- run: gradle test

Starting from this model, let’s make some changes. The first one is to change the docker image to one that already contains the tools needed to build Android apps — we have a list of the images maintained by CircleCI here. Let’s also configure the version of the JDK to be used and configure the dependency cache (so Gradle don’t need to download all dependencies again if nothing changed from one build to another). There’s a task (Accept licenses) added to prevent the build process from failing because of licenses not accepted.

In the build task, we’ll configure Lint (through the task check), the compilation and execution of local tests (through the task build) and, for now, the compilation of the instrumented tests (through the task assembleAndroidTest) — later we will delegating those tests execution to the Firebase Test Lab.

The final file looks like this:

version: 2
jobs:
build:
docker:
- image: circleci/android:api-27-alpha

working_directory: ~/social-app

environment:
JVM_OPTS: -Xmx3200m
CIRCLE_JDK_VERSION: oraclejdk8

steps:
- checkout

- restore_cache:
key: jars-{{ checksum "build.gradle" }}-{{ checksum "app/build.gradle" }}

- run:
name: Accept licenses
command: yes | sdkmanager --licenses || true

- run:
name: Build
command: ./gradlew clean check build assembleAndroidTest

- save_cache:
paths:
- ~/.gradle
key: jars-{{ checksum "build.gradle" }}-{{ checksum "app/build.gradle" }}

After that, I also added a badge in the README.md of the repository, indicating the current status of our build. All of this was added to a committed to the repository in a branch called rt/setup-ci and then I’ve created a new Pull Request.

As an administrator, I could simply ignore the flow and merge my Pull Request myself. However, I would break the flow that I am proposing! 😄

To review my PR, I added Elessandra as a reviewer. In this case, the person reviewing the PR may make notes and, if all is correct, approve and merge.

But sometimes things don’t go well. I accidentally committed the file with some typos on the first attempt. Since we still did not have the CI server to validate errors in the configuration file, this happened. So, I was forced to make another PR by reversing the modification. Through Github’s own interface it is possible to undo the PR.

With all errors fixed (and, after a few tries), finally I was able to configure the CI server correctly.

As there were several commits of trial and error, the PR ended several commits. In this case, the ideal is to do Squash (join all commits into a single one), thus avoiding that the history of Git becomes confusing. During this process, another option is to use the option --amend when committing. There’s a great guide about rewriting the story on Git documentation.

Finally, after the merge it is important to delete the source branch, since it is not a persistent branch. Thus, this helps to keep the repository clean and organized! 🙂

That’s it for today. The repository already with the modifications is available here.

--

--