Continuous deployment

Deploying the app is an activity that is best done continuously and automatically. I'd optimise to make it as easy and as quick as possible to deploy, this way when bugs affect users they only do so for a short period. We can enable continuous deployment for our app by adding it to the Gitlab CI/CD script.

To do this we first need credentials to interact with Heroku to be available to the Gitlab CI runner. We can do this by adding the following to infrastructure/,

resource "gitlab_project_variable" "heroku_app" {
  key       = "HEROKU_APP"
  value     =
  project   =
  protected = true
resource "gitlab_project_variable" "heroku_token" {
  key       = "HEROKU_API_KEY"
  value     = var.heroku_api_key
  project   =
  protected = true
resource "gitlab_project_variable" "heroku_username" {
  key       = "HEROKU_USERNAME"
  value     = var.heroku_username
  project   =
  protected = true

The deployment requires four steps, firstly we need to login to Heroku's docker repository, then build the docker image, followed by pushing it to Heroku's respository, and finally instruct Heroku to use our new image for the app. This is achieved by adding the following to .gitlab-ci.yml,

  stage: deploy
  image: docker:latest

    - docker:dind

    - apk add --update curl

    - >
        docker login
        --username $HEROKU_USERNAME
        --password $HEROKU_API_KEY

    - >
        docker build --build-arg CI_COMMIT_SHA=$CI_COMMIT_SHA
        -t$HEROKU_APP/web .

    - docker push$HEROKU_APP/web

    - >
        curl --fail
        -X PATCH "$HEROKU_APP/formation"
        -H 'Content-Type:application/json'
        -H 'Accept:application/vnd.herokujson; version=3.docker-releases'
        -H "Authorization:Bearer $HEROKU_API_KEY"
        -d '{"updates":[{"type":"web","docker_image":"'$(docker inspect$HEROKU_APP/web --format={{.Id}})'"}]}'
    - main

To prevent us accidently trying to deploy a broken commit I've introduced stages to the CI, with the above being in the deploy stage. This is achieved by adding the following to .gitlab-ci.yml,

  - lint-test
  - deploy

and adding,

stage: lint-test

to the existing CI jobs.