Gitlab Perl CI and CD Pipeline

Posted: 2017-09-10 12:38:47 by Alasdair Keyes

Direct Link | RSS feed


I've been looking at Gitlab's CI pipeline to automate testing and deployment of a Perl App I've been writing.

Gitlab's documentation on the subject is very comprehensive https://docs.gitlab.com/ee/ci/pipelines.html however there's no Perl example https://docs.gitlab.com/ee/ci/examples/README.html so I did a bit of playing to get a working configuration for those who are interested.

Gitlab makes it extremely easy to use their CI by creating a gitlab-ci.yml file to control the pipeline.

Firstly we define the container image we wish the use. Gitlab uses Docker containers so you can choose any image from Docker Hub https://hub.docker.com/

image: ubuntu:artful

Secondly we define the before_script section, this is a script that is run to prepare the containers for your tests. The before_script section can be limited to specific sections as you will see under the deployment sections later. But this global area will be executed for every stage of the build process.

before_script:
  - echo "Before script installation"
  - apt update
  - apt install libdevel-cover-perl libjson-xs-perl -y

Next, we define the stages of the CI pipeline. This is a fairly small app so there's just a test and deploy stage which we'll hook into.

stages:
  - test
  - deploy

We then define the execution of the unit tests. The test phase runs a single Perl harness script, which will in turn run all the test files under the t/ directory. It returns 0 if all tests are succesful, otherwise 1. This makes it slightly easier than putting each test file into it's own section.

The test is executed with the Devel::Cover module to produce code coverage output, which we then harvest with the coverage regex. This allows us to place the Coverage: X% badge on our website/README.md files.

test:unit:
  stage: test
  script:
    - perl -MDevel::Cover t/test_harness_script.pl
  coverage: /Total\s+.+\s(\d+\.\d+?)$/

Next, the deployment stages

This could be pretty complicated depending on your setup, so to simplify it for this example, I've just set it to login to the remote server with ssh and perform a git pull.

On staging this is set to only run when pushing changes to the master branch. For production this runs only when pushing tags.

You will notice the $STAGING_PRIV_KEY and $PRODUCTION_PRIV_KEY variables. These are defined in the settings for your repository in the Github UI under Settings -> Pipelines. They contain the private part of an SSH key to enable access to the environments. Make sure that you limit each variable to the environment it relates to, this saves any deployment to the wrong environment if you make a mistake on your pipeline configuration.

deploy_staging:
  stage: deploy
  before_script:
    - 'which ssh-agent || ( apt-get update -y && apt-get install openssh-client -y )'
    - eval $(ssh-agent -s)
    - ssh-add <(echo "$STAGING_PRIV_KEY")
  script:
    - echo "Deploy to staging server"
    - ssh -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no user@hostname "cd gitfolder && git pull"
  environment:
    name: staging
    url: http://staging.example.com
  only:
  - master

deploy_production:
  stage: deploy
  before_script:
    - 'which ssh-agent || ( apt-get update -y && apt-get install openssh-client -y )'
    - eval $(ssh-agent -s)
    - ssh-add <(echo "$PRODUCTION_PRIV_KEY")
  script:
    - echo "Deploy to production server"
    - ssh -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no user@hostname "cd gitfolder && git pull"
  environment:
    name: production
    url: http://www.example.com
  only:
  - tags

And that's it. Your testing and deployment pipeline are now automatically building and deploying

You can add the badges into your README.md site with the following markdown

[![pipeline status](https://gitlab.com/account/repo/badges/master/pipeline.svg)](https://gitlab.com/account/repo/commits/master)
[![coverage report](https://gitlab.com/account/repo/badges/master/coverage.svg)](https://gitlab.com/account/repo/commits/master)

The full configuration for .gitlab-ci.yml is here.

image: ubuntu:artful

before_script:
  - echo "Before script installation"
  - apt update
  - apt install libdevel-cover-perl libjson-xs-perl -y

stages:
  - test
  - deploy

test:unit:
  stage: test
  script:
    - perl -MDevel::Cover t/test_harness_script.pl
  coverage: /Totals+.+s(d+.d+?)$/

deploy_staging:
  stage: deploy
  before_script:
    - 'which ssh-agent || ( apt-get update -y && apt-get install openssh-client -y )'
    - eval $(ssh-agent -s)
    - ssh-add <(echo "$STAGING_PRIV_KEY")
  script:
    - echo "Deploy to staging server"
    - ssh -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no user@hostname "cd gitfolder && git pull"
  environment:
    name: staging
    url: http://staging.example.com
  only:
  - master

deploy_production:
  stage: deploy
  before_script:
    - 'which ssh-agent || ( apt-get update -y && apt-get install openssh-client -y )'
    - eval $(ssh-agent -s)
    - ssh-add <(echo "$PRODUCTION_PRIV_KEY")
  script:
    - echo "Deploy to production server"
    - ssh -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no user@hostname "cd gitfolder && git pull"
  environment:
    name: production
    url: http://www.example.com
  only:
  - tags


If you found this useful, please feel free to donate via bitcoin to 1NT2ErDzLDBPB8CDLk6j1qUdT6FmxkMmNz

© Alasdair Keyes

IT Consultancy Services

I'm now available for IT consultancy and software development services - Cloudee LTD.



Happy user of Digital Ocean (Affiliate link)


Version:master-047e2a75d6


Validate HTML 5