Use GitLab CI to run tests locally?

If a GitLab project is configured on GitLab CI, is there a way to run the build locally?

I don't want to turn my laptop into a build "runner", I just want to take advantage of Docker and .gitlab-ci.yml to run tests locally (i.e. it's all pre-configured). Another advantage of that is that I'm sure that I'm using the same environment locally and on CI.

Here is an example of how to run Travis builds locally using Docker, I'm looking for something similar with GitLab.


Solution 1:

Since a few months ago this is possible using gitlab-runner:

gitlab-runner exec docker my-job-name

Note that you need both docker and gitlab-runner installed on your computer to get this working.

You also need the image key defined in your .gitlab-ci.yml file. Otherwise won't work.

Here's the line I currently use for testing locally using gitlab-runner:

gitlab-runner exec docker test --docker-volumes "/home/elboletaire/.ssh/id_rsa:/root/.ssh/id_rsa:ro"

Note: You can avoid adding a --docker-volumes with your key setting it by default in /etc/gitlab-runner/config.toml. See the official documentation for more details. Also, use gitlab-runner exec docker --help to see all docker-based runner options (like variables, volumes, networks, etc.).

Due to the confusion in the comments, I paste here the gitlab-runner --help result, so you can see that gitlab-runner can make builds locally:

   gitlab-runner --help
NAME:
   gitlab-runner - a GitLab Runner

USAGE:
   gitlab-runner [global options] command [command options] [arguments...]
   
VERSION:
   1.1.0~beta.135.g24365ee (24365ee)
   
AUTHOR(S):
   Kamil Trzciński <[email protected]> 
   
COMMANDS:
   exec         execute a build locally
   [...]
   
GLOBAL OPTIONS:
   --debug          debug mode [$DEBUG]
   [...]

As you can see, the exec command is to execute a build locally.

Even though there was an issue to deprecate the current gitlab-runner exec behavior, it ended up being reconsidered and a new version with greater features will replace the current exec functionality.

Note that this process is to use your own machine to run the tests using docker containers. This is not to define custom runners. To do so, just go to your repo's CI/CD settings and read the documentation there. If you wanna ensure your runner is executed instead of one from gitlab.com, add a custom and unique tag to your runner, ensure it only runs tagged jobs and tag all the jobs you want your runner to be responsible of.

Solution 2:

I use this docker-based approach.

0. Create a git repo to test this answer

mkdir my-git-project
cd my-git-project
git init
git commit --allow-empty -m"Initialize repo to showcase gitlab-runner locally."

1. Go to your git directory

cd my-git-project

2. Create a .gitlab-ci.yml

Example .gitlab-ci.yml

image: alpine

test:
  script:
    - echo "Hello Gitlab-Runner"

3. Create a docker container with your project dir mounted

docker run -d \
  --name gitlab-runner \
  --restart always \
  -v $PWD:$PWD \
  -v /var/run/docker.sock:/var/run/docker.sock \
  gitlab/gitlab-runner:latest

(-d) run container in background and print container ID

(--restart always) or not?

(-v $PWD:$PWD) Mount current directory into the current directory of the container - Note: On Windows you could bind your dir to a fixed location, e.g. -v ${PWD}:/opt/myapp. Also $PWD will only work at powershell not at cmd

(-v /var/run/docker.sock:/var/run/docker.sock) This gives the container access to the docker socket of the host so it can start "sibling containers" (e.g. Alpine).

(gitlab/gitlab-runner:latest) Just the latest available image from dockerhub.

4. Execute with

docker exec -it -w $PWD gitlab-runner gitlab-runner exec docker test
#                ^          ^           ^            ^     ^      ^
#                |          |           |            |     |      |
#               (a)        (b)         (c)          (d)   (e)    (f)

(a) Working dir within the container. Note: On Windows you could use a fixed location, e.g. /opt/myapp.

(b) Name of the docker container

(c) Execute the command "gitlab-runner" within the docker container

(d)(e)(f) run gitlab-runner with "docker executer" and run a job named "test"

5. Prints

...
Executing "step_script" stage of the job script
$ echo "Hello Gitlab-Runner"
Hello Gitlab-Runner
Job succeeded
...

Note: The runner will only work on the commited state of your code base. Uncommited changes will be ignored. Exception: The .gitlab-ci.yml itself does not have be commited to be taken into account.

Solution 3:

I'm currently working on making a gitlab runner that works locally. Still in the early phases, but eventually it will become very relevant. It doesn't seem like gitlab want/have time to make this, so here you go. https://github.com/firecow/gitlab-runner-local

Solution 4:

Another approach is to have a local build tool that is installed on your pc and your server at the same time. So basically, your .gitlab-ci.yml will basically call your preferred build tool.

Here an example .gitlab-ci.yml that i use with nuke.build:

stages:
    - build
    - test
    - pack

variables:
    TERM: "xterm" # Use Unix ASCII color codes on Nuke

before_script:
    - CHCP 65001  # Set correct code page to avoid charset issues

.job_template: &job_definition
  except:
    - tags

build:
    <<: *job_definition
    stage: build
    script:
        - "./build.ps1"

test:
    <<: *job_definition
    stage: test
    script:
        - "./build.ps1 test"
    variables:
        GIT_CHECKOUT: "false"

pack:
    <<: *job_definition
    stage: pack
    script:
        - "./build.ps1 pack"
    variables:
        GIT_CHECKOUT: "false"
    only:
        - master
    artifacts:
        paths:
            - output/

And in nuke.build i've defined 3 targets named like the 3 stages (build, test, pack)

In this way you have a reproducible setup (all other things are configured with your build tool) and you can test directly the different targets of your build tool.

(i can call .\build.ps1 , .\build.ps1 test and .\build.ps1 pack when i want)