Creating a 3 Stage Deployment Pipeline With Github Actions

In this post I will show you how to setup a nice 3 stage deployment pipeline that will lint and test your code before deploying to a specific stage, using Github Actions

I will be simulating a Python application for this post, so you should modify the Python related stuff according to your project.

🔧 Build And Test Workflow

This workflow will lint, type check, and test the project before deploying to any stage. Create a .github/workflows/build-and-test.yml file:

name: build-and-test

on: [push]

env:
  GITHUB_TOKEN: ${{ secrets.ACCESS_TOKEN }}

jobs:

  lint-and-type-check:
    runs-on: ubuntu-latest

    steps:
      - uses: actions/checkout@v2
        with:
          token: ${{ secrets.ACCESS_TOKEN || github.token }}

      - name: Install Python 3.8
        uses: actions/setup-python@v2
        with:
          python-version: 3.8

      - name: Install Dependencies
        run: |
          pip install black
          pip install flake8
          pip install mypy

      - name: Lint
        run: flake8 .

      - name: Check Black
        run: black --check .

      - name: Type Checking
        run: mypy .

  build-and-test:
    needs: lint-and-type-check
    runs-on: ubuntu-latest

    services:
      mysql:
        image: mysql:5.7
        env:
          MYSQL_ROOT_PASSWORD: my-secret-pw
        ports:
          - 3306:3306
        options: --health-cmd="mysqladmin ping" --health-interval=10s --health-timeout=5s --health-retries=3

      redis:
        image: redis:4.0.10
        ports:
          - 6379:6379

    steps:
      - uses: actions/checkout@v2
        with:
          token: ${{ secrets.ACCESS_TOKEN }}
          submodules: true

      - name: Install Python 3.8
        uses: actions/setup-python@v2
        with:
          python-version: 3.8

      - name: Install Dependencies
        run: |
          pip install -r requirements.txt

      - name: Run Test Suite
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
        run: python -m pytest tests/

This workflow will trigger two jobs that will run sequentially. If the first one fails, the build-and-test job will not run. You can make these jobs run in parallel by removing the needs: lint-and-type-check clause.

For illustrative purposes I am making use of Github Actions's service containers feature which allows us to start different containers that our build can use. In this case MySQL and Redis.

When checking out the project repository, we specify the token with ${{ secrets.ACCESS_TOKEN || github.token }} in order to allow Dependabot to run the CI job when the bot creates pull requests.

🚀 Deployment Workflows

We will be working with 3 stages: dev, staging, and production, which will be linked to a develop, staging, and master branch respectively.

Therefore we will create 3 very similar deployment workflow files:

Here is an example of the develop deployment:

name: deploy-dev

on:
  workflow_run:
    workflows: ["build-and-test"]
    branches: [develop]
    types:
      - completed

jobs:
  deploy:
    runs-on: ubuntu-latest
    if: ${{ github.event.workflow_run.conclusion == 'success' }}

    steps:
      - uses: actions/checkout@v2
        with:
          token: ${{ secrets.ACCESS_TOKEN }}
          submodules: true
          ref: develop

      - name: Install Python 3.8
        uses: actions/setup-python@v2
        with:
          python-version: 3.8

      - name: Install Dependencies
        run:
          # Install any required dependencies here

      - name: Deploy
        # ... Run your own deployment process here

The key thing in this workflow is that it will only run if the previous build-and-test workflow we created succeeds. Otherwise this workflow will not run. This happens thanks to the if clause and the completed type specified.

The workflows for the other environments should be the same. We simply need to change the branches for each stage accordingly.

References

  1. https://docs.github.com/en/actions/guides/about-service-containers
github actions

Comments

comments powered by Disqus