How to build basic CI with GitLab


GitLab is more than a git repository. It comes with the powerful CI/CD runner that you can use for free, or even self host. In this post we are going to get familiar with it, and setup the most basic pipeline.

In order to add GitLab CI/CD to you project, all you need to do is to add .gitlab-ci.yml file to the root of your project. This file contains all the pipeline configuration and tasks. Once you add this file to your repository, and push it upstream, GitLab will detect the configuration, and it will execute it.

The GitLab script is, in general, comprised of two sections: stages, and jobs. A collection of jobs composes a pipeline. Stages define stages of the pipeline.

We will use a simple Python program to show how to build a pipeline. First make a git project:

mkdir example-project
cd example-project
git init
touch add.py test_add.py .gitlab-ci.yml
python3 -m venv env
. env/bin/activate
pip install flake8
pip freeze > requirements.txt

And write some Python code:

# add.py
def add(*args):
    return sum(args)


# test_add.py
import unittest
from add import add


class AddTestCase(unittest.TestCase):

    def test_add_two(self):
        self.assertEqual(add(1, 2), 3)

    def test_add_positive_and_negative(self):
        self.assertEqual(add(-1, 1), 0)

    def test_add_many(self):
        self.assertEqual(add(1, 2, 3), 6)

Now we have enough elements to build a pipeline with several stages. We have flake8 to lint our program, unit tests to test our function, and let’s say that we were asked to tar this script and consider that a build.

Open your .gitlab-ci.yml and define pipeline stages:

stages:
    - lint
    - test
    - build

The basic anatomy of a job is the following:

title:  # a title of the job - any string you want
    stage: test  # stage must correspond to one of the predefined stages
    image: python:latest  # docker image to be used for this job
    before_script:  # preparations you need to make before doing the actual job
        - ...
    script:  # the actual steps of the job
        - ...
    after_script:  # if you need to do some cleanups
        - ...
    artifacts:  # persist files from the pipeline
        paths:
            - dir

Before we start writing our first job, we have to identify that there are some common elements between them. Namely, we have to install dependencies with pip. Luckily, we can write before_script as a global config, and it will be executed before each job in the .gitlab-ci.yml:

before_script:
    - pip install -r requirements.txt

Now, let’s write our first job:

lint:
    stage: lint
    image: python:latest
    script:
        - flake8 .

It’s very simple! The GitLab runner will pull the latest Python Docker image from the Docker Hub, and execute contents of script in it. We will write other jobs in a similar fashion:

test:
    stage: test
    image: python:latest
    script:
        - python -m unittest test_add

build:
    stage: build
    image: alpine:latest
    before_script:
        - mkdir dist
    script:
        - tar cvzf dist/add.tar add.py
    artifacts:
        paths:
            - dist

Notice that in the build job we have overridden global before_script with a new script that is specific to the task. Moreover, we have saved the tar as a pipeline artifact so we can use it later.

Commit your changes and push this repo to your GitLab account. Go to the CI/CD tab of your project, and watch your pipeline passing. This is essentially it, a basic example that shows you how to start working with GitLab CI today!

We're not spammers, and you can opt-out at any moment. We hate spam as much as you do.

powered by TinyLetter

See also