Posted: 2017-09-10 12:38:47 by Alasdair Keyes
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
I'm now available for IT consultancy and software development services - Cloudee LTD.
Happy user of Digital Ocean (Affiliate link)