Automatic deploys with GitLab CI

It's time to take your gitlab ci to the next level. Let Gitlab CI automatically deploy to staging and give you the option to manually deploy to production if all tests pass.

Automatic deploys with GitLab CI

In the first part, I showed you how to run cypress in GitLab CI, now it's time to tell GitLab CI to also deploy to staging if all tests pass and give us an option to manually trigger a production deploy from Slack!

Automated staging deploys

As you might already know, it's time to add a new stage in the .gitlab-ci.yml file, let's call it deploy_staging and also define how the deploy should be done. In my example, I am still using wagon for LocomotiveCMS but you can, of course, use whatever you need for your staging deploy here instead.

deploy_staging:
  stage: deploy_staging
  script:
    - sed -e s/APIKEY/$LOCO_API/g config/deploy-testing.yml > config/deploy.yml
    - bundle install -j $(nproc) --path vendor
    - bundle exec wagon deploy staging -v
  cache:
    key: ${CI_COMMIT_REF_SLUG}
    paths:
      - vendor/ruby

The part which triggers the deploy is bundle exec wagon deploy staging -v and will only be executed if all the GitLab CI jobs in the pipeline were successful before that if not specified otherwise. If you push to GitLab now it will run the tests and if they pass successfully it will automatically deploy to staging. For this, to work, you need to update your deploy-testing.yml file and add an appropriate entry to allow wagon to deploy to staging. Also, make sure the staging page has the GitLab user with admin permissions, otherwise the deploy won't work with LocomotiveCMS.

Manual production deploys

All it takes for a job to be set to manual deploy is adding the option when: manual in the .gitlab-ci.yml file. Taking what I have shown you so far, a production deploy could look like this:

deploy_production:
  stage: deploy_production
  only:
    - master
  script:
    - sed -e s/APIKEY/$LOCO_API/g config/deploy-testing.yml > config/deploy.yml
    - bundle install -j $(nproc) --path vendor
    - bundle exec wagon deploy production -v
  when: manual

Since I don't want to deploy anything else but the master branch to production, I encourage you to add the only: mater setting. Once this is done, you will be able to manually trigger a deploy from the gitlab web interface which looks like this.

GitLab CI cypress pipeline

As you can see the staging deploy was done automatically but the production deploy not, as expected and you can click on the "play" icon to trigger the deploy.

Deploying from Slack

Add a Slack Slash command to Gitlab

Let's take this one step further, let's deploy from slack after tests have passed, staging deploy was done and you have checked that the staging deploy looks good. For the Slack deploy to work you first have to add a "Slack Slash command" integration to GitLab. To do this, go to Settings -> Integrations -> Slack Slash Command in Gitlab.

Adding Slack Slash Command to Gitlab

Follow the instructions there and set up the integration, when this is done you need to update your .gitlab-ci.yml

Triggering deploy from Slack

You need to add an environment setting in your gitlab ci config since this is needed for the deploy to work. The slack command to trigger the deploy looks like this: /<command> deploy <env> to <env> hence the environment setting in the gitlab ci config. You should also add a url option to have the URL's for each environment in the Gitlab user interface. Let's take the deploy_staging job and update it with the new settings:

deploy_staging:
  stage: deploy_staging
  environment:
    name: staging
    url: https://cms.example.com/locomotive/example-demo/preview
  script:
    - sed -e s/APIKEY/$LOCO_API/g config/deploy-testing.yml > config/deploy.yml
    - bundle install -j $(nproc) --path vendor
    - bundle exec wagon deploy staging -v
  cache:
    key: ${CI_COMMIT_REF_SLUG}
    paths:
      - vendor/ruby

and do the same for the production deploy

deploy_production:
  stage: deploy_production
  environment:
    name: production
    url: https://www.example.wien/
  only:
    - master
  script:
    - sed -e s/APIKEY/$LOCO_API/g config/deploy-testing.yml > config/deploy.yml
    - bundle install -j $(nproc) --path vendor
    - bundle exec wagon deploy production -v
  when: manual

If you now push your code, the tests will run and everything deployed to staging automatically. Since you defined two environments staging and production you can now go in slack and type /app deploy staging to production which will trigger the manual deploy job deploy_production

deploying to production from Slack

Now why the URL's in the environment definition? Look at your gitlab operations -> environments. Here you will find your two environments with the links to each of the environments as defined in the .gitlab-ci.yml file.

GitLab Environments

The full gitlab-ci config

Here's the full .gitlab-ci.yml used in this example

image: lcxat/cypress-ruby

stages:
  - build
  - test
  - deploy_staging
  - deploy_production

cache:
  key: ${CI_COMMIT_REF_SLUG}
  paths:
    - vendor/ruby

build:
  stage: build
  script:
    - gem install bundler
    - bundle install -j $(nproc) --path vendor
    - sed -e s/APIKEY/$LOCO_API/g config/deploy-testing.yml > config/deploy.yml
    - bundle exec wagon deploy testing -v -d

cypress:
  stage: test
  script:
    - sed -i -e s#http://localhost:3333/#$CMS_URL#g cypress.json
    - npm test
  artifacts:
    paths:
      - /builds/wko/i2c/cypress/screenshots/
      - /builds/wko/i2c/cypress/videos/

deploy_staging:
  stage: deploy_staging
  environment:
    name: staging
    url: https://cms.example.com/locomotive/example-demo/preview
  script:
    - sed -e s/APIKEY/$LOCO_API/g config/deploy-testing.yml > config/deploy.yml
    - bundle install -j $(nproc) --path vendor
    - bundle exec wagon deploy staging -v
  cache:
    key: ${CI_COMMIT_REF_SLUG}
    paths:
      - vendor/ruby

deploy_production:
  stage: deploy_production
  environment:
    name: production
    url: https://www.examople.wien/
  only:
    - master
  script:
    - sed -e s/APIKEY/$LOCO_API/g config/deploy-testing.yml > config/deploy.yml
    - bundle install -j $(nproc) --path vendor
    - bundle exec wagon deploy production -v
  when: manual