Setting up the CI environment

Setting up the CI environment

Now we will setup the CI for my intro page.

Obstacle

A push on any branch should trigger a build in Github Actions and test the latest push for any errors. We must make sure that new pushes against the branch will cancel the old one.

For easy deployment, the frontend image will be available at docker.hub.com. Any docker registry can be used here! To enable a comfortable deployment, I will setup an automated push to the docker registry, after the master branch or any tags has been pushed to github.

With jwilder/nginx-proxy is using environment variables to configure each webservice you want to reverse-proxy on your server. To accomplish this with jwilder I had to inject the configurations while building the image.

Since traefik is using labels this is not necessary and saves up some time setting up the CI pipeline and dockerfile.

I ended up using two workflows in my project, one to build the app and one to build and push my docker image.

The docker build and push action is pretty much documented here and you can apply this for your needs.

Mine looks like this:

name: ci

on:
  schedule:
    - cron: '0 10 * * *' # everyday at 10am
  push:
    branches:
      - 'master'
      - 'release/*'
    tags:
      - 'v*.*.*'
  pull_request:

jobs:
  docker:
    runs-on: ubuntu-latest
    steps:
      -
        name: Checkout
        uses: actions/checkout@v2
              
      - 
        name: Use Node.js 14.x
        uses: actions/setup-node@v1
        with:
          node-version: 14.x
      - 
        name: Prepare
        id: prep
        run: |
          DOCKER_IMAGE=radikrahl/andreaskrahl.de
          VERSION=noop
          if [ "${{ github.event_name }}" = "schedule" ]; then
            VERSION=nightly
            echo -e "Version is schedule \e[44m${VERSION}"
          elif [[ $GITHUB_REF == refs/tags/* ]]; then
            VERSION=${GITHUB_REF#refs/tags/}
            echo -e "Version is refs/tags/ \e[44m${VERSION}"
          elif [[ $GITHUB_REF == refs/heads/* ]]; then
            VERSION=$(echo ${GITHUB_REF#refs/heads/} | sed -r 's#/+#-#g')
            if [ "${{ github.event.repository.default_branch }}" = "$VERSION" ]; then
              VERSION=latest
              echo -e "Version is /refs/heads/default/ \e[44m${VERSION}"
            fi
            echo -e "Version is /refs/head \e[44m${VERSION}"
          elif [[ $GITHUB_REF == refs/pull/* ]]; then
            VERSION=pr-${{ github.event.number }}
            echo -e "Version is /refs/pull/ \e[44m${VERSION}"
          fi
          DOCKER_TAGS="${DOCKER_IMAGE}:${VERSION}"

          if [[ $VERSION =~ ^v[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$ ]]; then
            MINOR=${VERSION%.*}
            MAJOR=${MINOR%.*}
            DOCKER_TAGS="$DOCKER_TAGS,${DOCKER_IMAGE}:${MINOR},${DOCKER_IMAGE}:${MAJOR},${DOCKER_IMAGE}:latest"
          elif [ "${{ github.event_name }}" = "push" ]; then
            DOCKER_TAGS="$DOCKER_TAGS,${DOCKER_IMAGE}:sha-${GITHUB_SHA::8}"
          fi
          echo -e "Docker tag is \e[44m${DOCKER_TAGS}"
          echo -e "Version is \e[44m${VERSION}"
          echo ::set-output name=version::${VERSION}
          echo ::set-output name=tags::${DOCKER_TAGS}
          echo ::set-output name=created::$(date -u +'%Y-%m-%dT%H:%M:%SZ')

      -
        name: bump node version
        run: |

      -
        name: Set up QEMU
        uses: docker/setup-qemu-action@v1
      -
        name: Set up Docker Buildx
        uses: docker/setup-buildx-action@v1
      -
        name: Login to DockerHub
        if: github.event_name != 'pull_request'
        uses: docker/login-action@v1 
        with:
          username: ${{ secrets.DOCKER_USERNAME }}
          password: ${{ secrets.DOCKER_PASSWORD }}
      -
        name: Build and push
        id: docker_build
        uses: docker/build-push-action@v2
        with:
          context: .
          file: ./Dockerfile
          platforms: linux/amd64,linux/arm64,linux/386
          push: ${{ github.event_name != 'pull_request' }}
          tags: ${{ steps.prep.outputs.tags }}
          labels: |
            org.opencontainers.image.title=${{ github.event.repository.name }}
            org.opencontainers.image.description=${{ github.event.repository.description }}
            org.opencontainers.image.url=${{ github.event.repository.html_url }}
            org.opencontainers.image.source=${{ github.event.repository.clone_url }}
            org.opencontainers.image.version=${{ steps.prep.outputs.version }}
            org.opencontainers.image.created=${{ steps.prep.outputs.created }}
            org.opencontainers.image.revision=${{ github.sha }}
            org.opencontainers.image.licenses=${{ github.event.repository.license.spdx_id }}

The node build is standard too.

# name: Publish Docker image
# on:
#   push:
#     branches: [ develop ]
#   pull_request:
#     branches: [ develop ]
name: Node.js CI

on: [push]

jobs:
  build:

    runs-on: ubuntu-latest

    strategy:
      matrix:
        node-version: [14.x, 12.x]

    steps:
    - uses: actions/checkout@v2
    - name: Use Node.js ${{ matrix.node-version }}
      uses: actions/setup-node@v1
      with:
        node-version: ${{ matrix.node-version }}
    - run: npm install
    - run: npm run build --if-present
    - run: npm test
    - run: npm run lint
      env:
        CI: true

I used to use travis-ci in my old setup, which took some time to setup, but I was quite satisfied with it since it got the work done!

Midway through Github Actions were released. I always wanted to transition from travis-ci to github actions but could not take the time to do so.

I like both systems since they well documented and easy to integrate. Currently I would say I still like to work with travis, since it is more mature than github actions and "googling" makes it easier.

If you setup your CI Environment be prepared to have a commit history that will look something like this.

That is it my friends. Thanks for reading.