Use GitLab CI to run tests locally?

Gitlab Ci

Gitlab Ci Problem Overview


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.

Gitlab Ci Solutions


Solution 1 - Gitlab Ci

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 <ayufan@ayufan.eu> 
   
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 - Gitlab Ci

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.

Note: There are some limitations running locally. Have a look at limitations of gitlab runner locally.

Solution 3 - Gitlab Ci

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 - Gitlab Ci

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)

Solution 5 - Gitlab Ci

If you are running Gitlab using the docker image there: https://hub.docker.com/r/gitlab/gitlab-ce, it's possible to run pipelines by exposing the local docker.sock with a volume option: -v /var/run/docker.sock:/var/run/docker.sock. Adding this option to the Gitlab container will allow your workers to access to the docker instance on the host.

Solution 6 - Gitlab Ci

The GitLab runner appears to not work on Windows yet and there is an open issue to resolve this.

So, in the meantime I am moving my script code out to a bash script, which I can easily map to a docker container running locally and execute.

In this case I want to build a docker container in my job, so I create a script 'build':

#!/bin/bash

docker build --pull -t myimage:myversion .

in my .gitlab-ci.yaml I execute the script:

image: docker:latest

services:
- docker:dind

before_script:
- apk add bash

build:
stage: build
script:
- chmod 755 build
- build

To run the script locally using powershell I can start the required image and map the volume with the source files:

$containerId = docker run --privileged -d -v ${PWD}:/src docker:dind

install bash if not present:

docker exec $containerId apk add bash

Set permissions on the bash script:

docker exec -it $containerId chmod 755 /src/build

Execute the script:

docker exec -it --workdir /src $containerId bash -c 'build'

Then stop the container:

docker stop $containerId

And finally clean up the container:

docker container rm $containerId

Solution 7 - Gitlab Ci

The idea is to keep check commands outside of .gitlab-ci.yml. I use Makefile to run something like make check and my .gitlab-ci.yml runs the same make commands that I use locally to check various things before committing.
This way you'll have one place with all/most of your commands (Makefile) and .gitlab-ci.yml will have only CI-related stuff.

Solution 8 - Gitlab Ci

I am on Windows using VSCode with WSL

I didn't want to register my work PC as a runner so instead I'm running my yaml stages locally to test them out before I upload them

$ sudo apt-get install gitlab-runner
$ gitlab-runner exec shell build

yaml

image: node:10.19.0 # https://hub.docker.com/_/node/
# image: node:latest

cache:
  # untracked: true
  key: project-name
  # key: ${CI_COMMIT_REF_SLUG} # per branch
  # key:
  #   files:
  #     - package-lock.json # only update cache when this file changes (not working) @jkr
  paths:
    - .npm/
    - node_modules
    - build

stages:
  - prepare # prepares builds, makes build needed for testing
  - test # uses test:build specifically @jkr
  - build
  - deploy

# before_install:

before_script:
  - npm ci --cache .npm --prefer-offline

prepare:
  stage: prepare
  needs: []
  script:
    - npm install

test:
  stage: test
  needs: [prepare]
  except:
    - schedules
  tags:
    - linux
  script:
    - npm run build:dev
    - npm run test:cicd-deps
    - npm run test:cicd # runs puppeteer tests @jkr
  artifacts:
    reports:
      junit: junit.xml
    paths:
      - coverage/

build-staging:
  stage: build
  needs: [prepare]
  only:
    - schedules
  before_script:
    - apt-get update && apt-get install -y zip
  script:
    - npm run build:stage
    - zip -r build.zip build
  # cache:
  #   paths:
  #     - build
  #   <<: *global_cache
  #   policy: push
  artifacts:
    paths:
      - build.zip

deploy-dev:
  stage: deploy
  needs: [build-staging]
  tags: [linux]
  only:
    - schedules
  #   # - branches@gitlab-org/gitlab
  before_script:
    - apt-get update && apt-get install -y lftp
  script:
    # temporarily using 'verify-certificate no'
    # for more on verify-certificate @jkr: https://www.versatilewebsolutions.com/blog/2014/04/lftp-ftps-and-certificate-verification.html
    # variables do not work with 'single quotes' unless they are "'surrounded by doubles'"
    - lftp -e "set ssl:verify-certificate no; open mediajackagency.com; user $LFTP_USERNAME $LFTP_PASSWORD; mirror --reverse --verbose build/ /var/www/domains/dev/clients/client/project/build/; bye"
  # environment:
  #   name: staging
  #   url: http://dev.mediajackagency.com/clients/client/build
  #   # url: https://stg2.client.co
  when: manual
  allow_failure: true

build-production:
  stage: build
  needs: [prepare]
  only:
    - schedules
  before_script:
    - apt-get update && apt-get install -y zip
  script:
    - npm run build
    - zip -r build.zip build
  # cache:
  #   paths:
  #     - build
  #   <<: *global_cache
  #   policy: push
  artifacts:
    paths:
      - build.zip

deploy-client:
  stage: deploy
  needs: [build-production]
  tags: [linux]
  only:
    - schedules
    # - master
  before_script:
    - apt-get update && apt-get install -y lftp
  script:
    - sh deploy-prod
  environment:
    name: production
    url: http://www.client.co
  when: manual
  allow_failure: true

Solution 9 - Gitlab Ci

Years ago I build this simple solution with Makefile and docker-compose to run the gitlab runner in docker, you can use it to execute jobs locally as well and should work on all systems where docker works:

https://gitlab.com/1oglop1/gitlab-runner-docker

There are few things to change in the docker-compose.override.yaml

version: "3"
services:
    runner:
      working_dir: <your project dir>
      environment:
        - REGISTRATION_TOKEN=<token if you want to register>
      volumes:
        - "<your project dir>:<your project dir>"

Then inside your project you can execute it the same way as mentioned in other answers:

docker exec -it -w $PWD runner gitlab-runner exec <commands>..

Solution 10 - Gitlab Ci

I have written a tool to run all GitLab-CI job locally without have to commit or push, simply with the command ci-toolbox my_job_name.

The URL of the project : https://gitlab.com/mbedsys/citbx4gitlab

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionMatthieu NapoliView Question on Stackoverflow
Solution 1 - Gitlab CielboletaireView Answer on Stackoverflow
Solution 2 - Gitlab CijschnasseView Answer on Stackoverflow
Solution 3 - Gitlab CiFirecowView Answer on Stackoverflow
Solution 4 - Gitlab CifruggieroView Answer on Stackoverflow
Solution 5 - Gitlab CiPiercoView Answer on Stackoverflow
Solution 6 - Gitlab CiGlen ThomasView Answer on Stackoverflow
Solution 7 - Gitlab CiOnlyjobView Answer on Stackoverflow
Solution 8 - Gitlab CiJacksonkrView Answer on Stackoverflow
Solution 9 - Gitlab CioglopView Answer on Stackoverflow
Solution 10 - Gitlab CiEmeric VerschuurView Answer on Stackoverflow