What is CI-CD? How to build CI-CD pipeline in Android using GitHub actions.

Kaushal Vasava
10 min readDec 12, 2023

I’ll show you what is CI-CD and How to build CI-CD pipeline in Android using GitHub actions.

What is CI/CD?

In modern software development, continuous integration and continuous development (CI/CD) is pivotal. It automates tasks like software building, testing, and deploying, ensuring rapid and consistent releases. By dividing work into smaller parts and automating workflows, CI/CD reduces errors, accelerates development, and maintains software readiness. In today’s tech landscape, CI/CD is a fundamental requirement for staying agile, responsive, and competitive.

CI/CD is a method to frequently deliver apps to customers by introducing automation into the stages of app development. The main concepts attributed to CI/CD are continuous integration, continuous delivery, and continuous deployment. CI/CD is a solution to the problems integrating new code can cause for development and operations teams (AKA “integration hell”).

Specifically, CI/CD introduces ongoing automation and continuous monitoring throughout the lifecycle of apps, from integration and testing phases to delivery and deployment. Taken together, these connected practices are often referred to as a “CI/CD pipeline” and are supported by development and operations teams working together in an agile way with either a DevOps or site reliability engineering (SRE) approach.

What is CI: Continuous Integration?

The “CI” in CI/CD always refers to continuous integration, which is an automation process for developers. Successful CI means new code changes to an app are regularly built, tested, and securely merged to a shared repository. It’s a solution to the problem of having too many branches of an app in development at once that might conflict with each other.

In modern application development, the goal is to have multiple developers working simultaneously on different features of the same app. However, if an organization is set up to merge all branching source code together on one day (known as “merge day”), the resulting work can be tedious, manual, and time intensive. That’s because when a developer working in isolation makes a change to an application, there’s a chance it will conflict with different changes being simultaneously made by other developers. This problem can be further compounded if each developer has customized their own local integrated development environment (IDE), rather than the team agreeing on one cloud-based IDE.

Continuous integration (CI) helps developers merge their code changes back to a shared branch, or “trunk,” more frequently — sometimes even daily. Once a developer’s changes to an application are merged, those changes are validated by automatically building the application and running different levels of automated testing, typically unit and integration tests, to ensure the changes haven’t broken the app. This means testing everything from classes and function to the different modules that comprise the entire app. If automated testing discovers a conflict between new and existing code, CI makes it easier to fix those bugs quickly and often.

What is CD: Continuous Deployment?

The “CD” in CI/CD refers to continuous delivery and/or continuous deployment, which are related concepts that sometimes get used interchangeably. Both are about automating further stages of the pipeline, but they’re sometimes used separately to illustrate just how much automation is happening.

Continuous Delivery

Continuous delivery usually means a developer’s changes to an application are automatically bug tested and uploaded to a repository (like GitHub or a container registry), where they can then be deployed to a live production environment by the operations team. It’s an answer to the problem of poor visibility and communication between dev and business teams. To that end, the purpose of continuous delivery is to ensure that it takes minimal effort to deploy new code.

Following the automation of builds and unit and integration testing in CI, continuous delivery automates the release of that validated code to a repository. So, in order to have an effective continuous delivery process, it’s important that CI is already built into your development pipeline. The goal of continuous delivery is to have a codebase that is always ready for deployment to a production environment.

In continuous delivery, every stage — from the merger of code changes to the delivery of production-ready builds — involves test automation and code release automation. At the end of that process, the operations team is able to deploy an app to production quickly and easily.

Continuous Deployment

Continuous deployment (the other possible “CD”) can refer to automatically releasing a developer’s changes from the repository to production, where it is usable by customers. It addresses the problem of overloading operations teams with manual processes that slow down app delivery. It builds on the benefits of continuous delivery by automating the next stage in the pipeline.

The final stage of a mature CI/CD pipeline is continuous deployment. As an extension of continuous delivery, which automates the release of a production-ready build to a code repository, continuous deployment automates releasing an app to production. Because there is no manual gate at the stage of the pipeline before production, continuous deployment relies heavily on well-designed test automation.

In practice, continuous deployment means that a developer’s change to a cloud application could go live within minutes of writing it (assuming it passes automated testing). This makes it much easier to continuously receive and incorporate user feedback. Taken together, all of these connected CI/CD practices make deployment of an application less risky, whereby it’s easier to release changes to apps in small pieces, rather than all at once. There’s also a lot of upfront investment, though, since automated tests will need to be written to accommodate a variety of testing and release stages in the CI/CD pipeline.

Build CI-CD Pipeline in Android using GitHub actions

Steps:

  1. Open Android studio
  2. Switch your app file structure to Project mode.

3. Create new directory and name it as .github/workflows

4. Create new file inside workflows folder. Name it as AndroidBuild.yml

# This is a basic workflow to help you get started with Actions
name: Android Build

# Controls when the workflow will run
on:
# Triggers the workflow on push or pull request events but only for the "master" branch
pull_request:
branches: ["master"]
push:
branches: ["master"]

# A workflow run is made up of one or more jobs that can run sequentially or in parallel
jobs:
# This workflow contains a single job called "build"
build:
# The type of runner that the job will run on
runs-on: ubuntu-latest
# Steps represent a sequence of tasks that will be executed as part of the job
steps:
# Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it
- name: Checkout
uses: actions/checkout@v4.1.1

- name: Setup Java JDK
uses: actions/setup-java@v4.0.0
with:
java-version: '17'
distribution: 'adopt'

- name: Change wrapper permissions
run: chmod +x ./gradlew

# Runs a single command using the runners shell
- name: Build with Gradle
run: ./gradlew build

- name: Upload a Build Artifact
uses: actions/upload-artifact@v3.1.3
with:
name: AndroidCICD.apk
path: app/build/outputs/apk/debug/app-debug.apk

What are GitHub Actions?

For want of a better way of making the GitHub Actions term super comprehensible, I’m going to oversimplify this.

In the CI/CD Pipeline, GitHub Actions is the entity that automates the boring stuff. Think of it as some plugin that comes bundled with every GitHub repository you create.

The plugin exists on your repo to execute whatever task you tell it to. Usually, you’d specify what tasks the plugin should execute through a YAML configuration file. Whatever command you add to the configuration file, will translate to something like this in plain English:

“hey GitHub Actions, each time a PR is opened on X branch, automatically build and test the new change. And each time a new change is merged into or pushed to X branch, deploy that change to Y server.”

At the core of GitHub Actions lies five concepts: jobs, workflows, events, actions, and runners.

Job:

Jobs are the tasks you command GitHub Actions to execute through the YAML config file. A job could be something like telling GitHub actions to build your source code, run tests, or deploy the code that has been built to some remote server.

For example,

# A workflow run is made up of one or more jobs that can run sequentially or in parallel
jobs:
# This workflow contains a single job called "build"
build:
# The type of runner that the job will run on
runs-on: ubuntu-latest
# Steps represent a sequence of tasks that will be executed as part of the job
steps:
# Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it
- name: Checkout
uses: actions/checkout@v4.1.1

Workflow

Workflows are essentially automated processes that contain one or more logically related jobs. For example, you could put the build and run tests jobs into the same workflow, and the deployment job into a different workflow.

Remember, we mentioned that you tell GitHub Actions what job(s) to execute through a configuration file right? GitHub Actions considers each configuration file that you put in some folder in your repo a workflow.

So, to create a separate workflow for the deployment job and then a different workflow that combines the build and tests jobs, you’d have to add two config files to your repo. But if you are merging all the three jobs into a single workflow, then you’d need to add just one config file.

Event

Events are literally the events that trigger the execution of a job by GitHub Actions. Recall we mentioned passing jobs to be executed through a config file? In that config file you’d also have to specify when a job should be executed.

For example, is it on-PR to master? Is it on-push to master? is it on-merge to master? A job can only be executed by a GitHub Action when some event happens.

# Controls when the workflow will run
on:
# Triggers the workflow on push or pull request events but only for the "master" branch
pull_request:
branches: ["master"]
push:
branches: ["master"]

Okay, let me quickly correct myself. It’s not always the case that some event has to happen before a job could be executed. You could schedule jobs too.

For example, in your config file, instead of specifying that the event that should trigger the execution of, let’s say, the build-and-test job, you could schedule it to happen a 2am every day. In fact, you could both schedule a job and specify an event for that same job.

Actions

Actions are the reusable commands that you can reuse in your config file. You can write your custom actions or use existing ones.

For example,

- name: Checkout
uses: actions/checkout@v4.1.1

Runner

A runner is the remote computer that GitHub Actions uses to execute the jobs you tell it to.

# The type of runner that the job will run on
runs-on: ubuntu-latest

For example, when the build-and-test job is triggered based on some event, GitHub Actions will pull your code to that computer and execute the job.

The same thing happens in the case of the deployment job. The runner triggers the deployment of the built code to some remote server you specify.

Let’s make sense of each line in the file above.

  • name: Android Build This is the name of our workflow. When you navigate to the actions tab, each workflow you define will be identified by the name you give it here on that list.
  • on: This is where you specify the events that should trigger the execution of our workflow. In our config file we passed it two events. We specified the main branch as the target branch.
  • jobs: Remember, a workflow is just a collection of jobs.
  • runs-on GitHub provides Ubuntu Linux, Microsoft Windows, and macOS runners to run your workflows. This where you specify the type of runner you want to use. In our case, we are using the Ubuntu Linux runner.
  • A job is made up of a series of steps that are usually executed sequentially on the same runner. In our file above, each step is marked by a hyphen. name represents the name of the step. Each step could either be a shell script that is being executed or an action . You define a step with uses if it's executing an action or you define a step with run if it's executing a shell script.

5. Push your code and it will check using GitHub actions and if your workflow passed then it will mark as green check icon.

6. More info.

If you want to create new workflow then you can click on new workflow button

Choose predefined templates or create your own workflow using Simple workflow.

If you choose Simple workflow then after click on configure you will see page like this.

Left side shows you basic workflow example and right-side marketplace where you can add actions as per your need.

Example of Setup Java JDK action, explore it and choose as per your need.

Demo project:

Conclusion

GitHub Actions is a powerful tool for automating processes in Android development. With its rich ecosystem of Marketplace actions, you can easily build complex workflows without having to write any code.

However, to make the most of GitHub Actions, it is important to understand the basics of how it works and how to use Marketplace actions. With this knowledge, you can quickly and easily create custom workflows to automate various tasks in your Android development process, such as building, testing, and deploying your app.

Thank you for reading. 🙌🙏✌.

Don’t forget to clap 👏 and follow me for more such useful articles about Android Development, Kotlin & KMP.

If you need any help related to Android, Kotlin and KMP. I’m always happy to help you.

Follow me on:

Medium, LinkedIn, Twitter, GitHub, and Instagram.

--

--

Kaushal Vasava

Android Developer | Kotlin | Jetpack Compose | Kotlin MultiPlatform | LinkedIn's Top Voice (3K+ Followers) | Apps with 100K+ Downloads on the Playstore