Road to CI/CD with GitHub Actions v2

Vincent Bouvier
fulll
5 min readSep 9, 2019

--

When development runs into production in a safer way

In this article, we briefly introduce the principle of a workflow in the context of the GitHub Actions. We then discuss our workflow strategy for Continuous Integration and Continuous Deployment.

The Workflow Summary

A workflow consists of a series of actions that are performed to fulfill a task. The workflows automatically run depending on different types of events detailed as followed:

  • Webhook events:

GitHub emits events for almost every activity on a repository (e.g., on push, pull request, deployment). A workflow listens to one or more events with different constraints (e.g., only trigger when pushing on a specific branch). A workflow executes when all the constraints are fulfilled (cf., workflow syntax for GitHub Actions #on).

  • Scheduled events:

A workflow based on a planned event is executed at specific UTC times using POSIX cron syntax. The workflow runs in the context of the latest commit on the default or the base branch (cf., events that trigger workflows #scheduled-events)

  • External events

The GitHub v3 API is capable of triggering the “repository_dispatch” event. This event will never be triggered automatically by GitHub. A workflow can listen for this specific webhook event (cf., events that trigger workflows #external-events).

The Workflow Structure

The Jobs

A workflow is made of jobs where each job runs in a fresh instance. Some limitations are essential to know:

  1. The state of an instance running a job does not persist when running subsequent jobs
  2. Any action performed on GitHub while being in a workflow will not trigger any other workflows. A workaround exists though you must use it very carefully. Please have a look at our other article GitHub’s Actions v2 — Tips and Tricks.

Within a workflow, the jobs run in parallel by default unless you explicitly define a relation between jobs (cf., Figure 1).

Example of a workflow with two jobs running in parallel and one job that required both jobs to terminate successfully.
Figure 1. Example of a workflow with two jobs running in parallel and one job that required both jobs to terminate successfully.

The Steps

A step constitutes an action executed within a job. A Job may contain multiple steps. Each step runs sequentially. A step can either invoke a remote action or directly execute a shell script. GitHub Action Marketplace already provides remote actions. For more specific use cases, you can also develop your actions.

Diving into Continous Integration and Deployment

Your project workflow matter

The way you managed your project workflow has a significant impact on how CI/CD is applied. We designed our CI/CD workflows based on what we think, at In Extenso Digital, is the best and safer scenario for us.

In a project, we use the master branch as the production branch and a development branch. We apply hot-fixes onto the master branch via pull requests. We cherry-pick every hot-fix onto the development branch so that it is always up-to-date with the master branch. Finally, we use pull-requests (PR) to merge the feature branches to the development branch.

You can use the repository settings to ensure that the project workflow works as intended. Here is the set of rules that we defined:

  • Disable direct push on master and dev branches: merging to master or dev branches only rely on pull-requests.
  • Merge only a feature branch that is up-to-date with the destination: this rule makes merging branches easier. Every conflict is resolved onto the feature branch. You can use multiple methods to do so. We personally like “rebase” (cf., Figure 2).
Figure 2. Schema definition of “rebase” (source: hackermoon.com)
  • Merge only a branch that successfully passes the CI workflow: this rule guarantees to never broke the development branch since the feature branch is up to date with the development branch. Running the CI into the feature branch and making sure it passes all the tests is very crucial at this point.

Continuous Integration

Continuous Integration runs on every push event for every feature branch (and hot-fix branch). The CI workflow is straightforward (cf., Figure 3).

Figure 3. Example of a CI workflow for a typical NodeJS project https://gist.github.com/vibou/90cee09d2ee5be76d904bdb98b4ede5c

Continuous Deployment

We divide the continuous deployment workflow into two separate use cases:

  • CD in the development/pre-prod environment
  • CD in the production environment

CD in the development / pre-prod environment: we decided to use two workflows: the first one creates a deployment. The second one is triggered right after the deployment creation. Thus, the second workflow runs in the context of deployment. It allows the workflow to access deployment relative variables such as the deployment id, environment (cf., Figure 4). In the pre-prod environment, the deployment is created on a push event on the master branch. To trigger a workflow from another workflow, please have a look at our other article: GitHub’s Actions v2 — Tips and Tricks.

Figure 4. Deployment from the DEV Branch

CD in the production environment: in production, you always want more control. So we decided to start deployment when we create a release. The release triggers a workflow in charge of building the products and attaching them as assets to the release note. We also add a button on the release note. The deployment of the assets starts as soon as a person clicks on the button. The button sends a signed query to a custom Git Application and updates the deployment status to in_progress. Another workflow listens to deployment status changes. The deployment of the assets starts as soon as the deployment status changes to in_progress(cf., Figure 5).

Figure 5. Deployment from the MASTER Branch

--

--