When developing software, the value of testing is immeasurable. Not only makes it easier to find bugs after changing small pieces of code or entire components, but with a code coverage, it gives extra confidence to the developing team, with all the benefits that this comes with.
Lately at my job, I’ve been assigned some tasks that can be considered specifically for DevOps positions, and although I’m specialized in mobile development, it’s always good to know a bit of every field.
I’ve been fighting with Jenkins in order to develop a few CI/CD pipelines to run unit and instrumented tests in Firebase Test Lab and to generate the different variants of the app, AABs and APKs, ready to be published to the stores or automate the uploading through the Firebase App Distribution functionality.
Although Jenkins is great, it mainly uses bash scripting, which is well-known and resources are available all over the internet. This gives a lot of customization, but I wanted to try GitHub Actions for my personal projects, as I don’t really need anything huge and most of the time I prefer simplicity.
Let’s start with some important info
GitHub Actions is a system that allows developers to implement CI/CI pipelines easier, specially for beginners, compared, for example, with Jenkins, as stated before.
It offers machines that are already configured to use with Linux, Windows and Mac, but there are a limited amount of free minutes depending on the machine. For smaller projects, it’s quite a good starting point in my opinion, specially if you only need Linux, which is the cheapest one.
It basically works using a YAML file that instructs the machine about what operations are going to be performed. This file is stored in the project repository in the .github/workflows
folder in the root of the repository.
GitHub also offers storage for secret keys that can be accessed by GitHub Actions. For example, in an Android project this is important if it’s needed to sign an APK or AAB file and the keys need to be obfuscated and unavailable in the repository files, so that no one can steal them.
The code
As mentioned before, we are going to need a YAML file that has mainly three parts.
- Workflow name
- Trigger condition
- Work to do
The workflow name is going to be shown in the summary of the workflow in the Actions tab of the GitHub repository, as you can see in the following picture, below the commit message that triggered the workflow.

The trigger can be configured to act in different scenarios. In this example, I’m showing how it’s done if we want to act on a push on the master branch, but it’s super configurable. You can check all the options here.

The jobs section is where we specify the machine that we are going to use and the work that we are going to do. You can either run two jobs concurrently or run them sequentially, so that a job depends on another.
In the following sample, you can see how I configured a job that builds the Android app and then runs unit tests. If these succeed, a release AAB is going to be compiled and updated to the repository as a downloadable artifact.
For the jobs, you can run Gradle commands directly on the machine or use GitHub Actions developed by other users. In this example, I’m using both of these options to show you that it’s possible and that sometimes is easier to do this instead of running the entire commands by ourselves.
The GitHub Action developed by other user takes the keys to sign the app from the secrets that we can set in our GitHub profile and outputs the file ready to publish to the store. It’s super easy to set up if you know GitHub Secrets, but if you don’t, you can check this repository to learn how to implement this.

I’ll leave here a GitHub Gist with the full code if you want to do a quick copy & paste.
name: Build, Test and Compile
on:
push:
branches: [ master ]
jobs:
Unit-Test:
runs-on: ubuntu-latest
# needs: Build
steps:
- uses: actions/checkout@v2
- name: Set up JDK
uses: actions/setup-java@v2
with:
java-version: '11'
distribution: 'adopt'
cache: gradle
- uses: actions/cache@v2
with:
path: |
~/.gradle/caches
~/.gradle/wrapper
key: ${{ runner.os }}-${{ hashFiles('**/*.gradle*') }}-${{ hashFiles('**/gradle/wrapper/gradle-wrapper.properties') }}-${{ hashFiles('**/buildSrc/**/*.kt') }}
- name: Grant execute permission for gradlew
run: chmod +x gradlew
- name: Unit Test
run: ./gradlew testDebugUnitTest
Compile:
runs-on: ubuntu-latest
needs: Unit-Test
steps:
- uses: actions/checkout@v2
name: Checkout project
- uses: actions/setup-java@v2
name: Set up JDK
with:
java-version: '11'
distribution: 'adopt'
cache: gradle
- uses: actions/cache@v2
name: Caching Gradle
with:
path: |
~/.gradle/caches
~/.gradle/wrapper
key: ${{ runner.os }}-${{ hashFiles('**/*.gradle*') }}-${{ hashFiles('**/gradle/wrapper/gradle-wrapper.properties') }}-${{ hashFiles('**/buildSrc/**/*.kt') }}
- name: Grant execute permission for gradlew
run: chmod +x gradlew
- name: Build Release Bundle
run: ./gradlew bundle
- uses: r0adkll/sign-android-release@v1
name: Sign Bundle
id: sign_app
with:
releaseDirectory: app/build/outputs/bundle/release
signingKeyBase64: ${{ secrets.SIGNING_KEY }}
alias: ${{ secrets.ALIAS }}
keyStorePassword: ${{ secrets.KEY_STORE_PASSWORD }}
- name: Upload Bundle
uses: actions/upload-artifact@v2
with:
name: release.aab
path: ${{steps.sign_app.outputs.signedReleaseFile}}
YAMLConclusion
In my experience, I think that I prefer Jenkins because I don’t need to have the repository specifically in GitHub, I also like bash scripting to define the steps of the CI/CD pipeline and, I’m not restricted to the pricing that GitHub is offering for the machines and I can evaluate other options.
But if the project is smaller, I’m not thinking about scaling it much, and I don’t want to think about Docker and Jenkins configurations, which can be a headache, GitHub Actions is the best option in my opinion.
Featured image by Roman Synkevych 🇺🇦 on Unsplash
If you want to read more content like this without ads and support me, don’t forget to check my profile, or give Medium a chance by becoming a member to access unlimited stories from me and other writers. It’s only $5 a month and if you use this link I get a small commission.