How can I test gitlab-ci.yml?
Gitlab CiGitlab Ci Problem Overview
I've finally manage to make it work so that when you push to a branch job would launch, but I keep waiting for it to launch around 3min and then I've got errors which I need to fix and then commit again, and then waiting again. How can I just ssh to that public runner and test .gitlab-ci.yml
"script" part just in the bash?
Gitlab Ci Solutions
Solution 1 - Gitlab Ci
For the record: You can also copy paste your gitlab-ci.yml
into the linter-form provided by gitlab:
Depending on which IDE you are using you might be able to find plugins that check for validity. For example in VS Code you can use a plugin called gitlab-vscode-extension which can validate your .gitlab-ci.yml
file.
In case you want to programatically validate your .gitlab-ci.yml
, gitlab provides an API which allows you to POST
your yml to /ci/lint
, e.g.:
curl --header "Content-Type: application/json" https://gitlab.example.com/api/v4/ci/lint --data '{"content": "{ \"image\": \"ruby:2.6\", \"services\": [\"postgres\"], \"before_script\": [\"bundle install\", \"bundle exec rake db:create\"], \"variables\": {\"DB_NAME\": \"postgres\"}, \"types\": [\"test\", \"deploy\", \"notify\"], \"rspec\": { \"script\": \"rake spec\", \"tags\": [\"ruby\", \"postgres\"], \"only\": [\"branches\"]}}"}'
Solution 2 - Gitlab Ci
If you want to go beyond mere linting and actually run your CI script, you can do so using gitlab-runner
. Here's how to do it.
gitlab-runner
Install OS=darwin
#OS=linux # Uncomment on linux
sudo curl --output /usr/local/bin/gitlab-runner https://gitlab-runner-downloads.s3.amazonaws.com/latest/binaries/gitlab-runner-${OS}-amd64
sudo chmod +x /usr/local/bin/gitlab-runner
Official gitlab-runner docs here
Create a command
The following .gitlab-ci.yml
file defines a task named build
:
build:
script:
- echo "Hello World"
(limitations apply!)
Run the command locallygitlab-runner exec shell build
When I run the above locally, I get the following output:
Running with gitlab-runner 11.3.1~beta.4.g0aa5179e (0aa5179e)
Using Shell executor...
Running on cory-klein.local...
Cloning repository...
Cloning into '/Users/coryklein/code/prometheus-redis-exporter/builds/0/project-0'...
done.
Checking out 66fff899 as master...
Skipping Git submodules setup
$ echo "Hello World"
Hello World
Job succeeded
Solution 3 - Gitlab Ci
You can run builds locally (if you control the runner that is) by using the gitlab-runner exec
command as described in the official docs here.
Make sure you also check the limitations of testing jobs this way.
Solution 4 - Gitlab Ci
The correct answer is that you cannot test your build pipeline without committing source code to your repository. You can only test one job - most likely the first job - of your build pipeline with gitlab-runner exec.
Since you cannot run multiple jobs you cannot chain any prepare or build steps with anything else. There is no way to stop gitlab-runner from creating a clean checkout and destroying your prepare/build steps.
The best/only way to test is to create a branch and keep force pushing changes to .gitlab-ci.yml to it.
Solution 5 - Gitlab Ci
See if GitLab 13.3 (August 2020) could help:
> ## Better linting for .gitlab-ci.yml
files
>
> When reviewing your CI definitions, you can now use our CI linter to go deeper into pipeline processing to validate the correctness of your .gitlab-ci.yml
.
>
> The CI linter provides feedback not only for syntax validation, but it also validates other kinds of logical errors and invalid configurations by simulating the pipeline as if you were running on master (without actually running anything).
>
> This helps you produce a properly configured pipeline faster and helps you avoid situations where a pipeline passed the linter but still could not run.
>
> See Documentation and Issue.
And, still with GitLab 13.3 (August 2020)
> ## CI linter now can provide warnings in addition to errors
>
> The CI linter can now provide warnings in addition to error messages when validating your .gitlab-ci.yml
file.
>
> This gives us the opportunity to provide more guidance when evaluating your pipelines, thereby making it easier to avoid more kinds of mistakes by catching them earlier.
>
> Our initial iteration is to provide a warning when the when:always
rule is used without workflow:rules
; this scenario causes duplicate pipelines when an MR is created and has also been a source of confusion.
And in addition to displaying this new warning message on the linter page, it will also appear on the pipeline view and run pipeline page to help you improve your CI configurations.
>
> See Documentation and Issue.
With GitLab 13.8 (January 2021), you can check its validity:
> ## CI/CD configuration validation in Pipeline Editor
>
> Previously, to validate your CI/CD configuration, you had to navigate to the CI lint page or commit your changes and look for any errors.
>
> In this release, we’ve added verification in the pipeline editor itself.
>
> It continuously checks your pipeline configuration before writing your .gitlab-ci.yml
file and provides you with an indicator that your configuration is valid.
This saves you time and effort that could otherwise be spent optimizing your pipeline.
>
>
>
> See Documentation and Issue.
See also GitLab 13.12 (May 2021)
> ## Pipeline status widget in the pipeline editor > > Previously, after committing changes using the pipeline editor, you had to navigate to a different page to know the real time status of your pipeline. > > In this release, we added a pipeline status widget to the pipeline editor so that you can monitor the status of your pipeline without leaving the comfort of the editor. > > > > See Documentation and Issue.
Solution 6 - Gitlab Ci
Use scripting and gitlab's API
My strategy consists on a bash script which is commanded to run via git's pre-commit
hook. Of course it can run on demand, it's an script.
> It's dificult to simulate a pipeline locally, specially for shared runners, but it isn't to lint the yaml configuration file to avoid fiddling.
It uses two gitlab's API endpoints to lint the .gitlab-ci.yml
:
Both API calls depend on an API_KEY
, which I setup within my $HOME
at ~/.gitlab.env
. The script sources that file to load the key on its environment.
The project based endpoint also requires the project ID. It could be extracted from git remote -v
and the like, but for simplicity it's just declared on the script, which is source-controlled within project's respository.
cat script/lint-ci
#!/usr/bin/env bash
# vim:sw=2:ts=2:et:ft=sh
# Written by lorenzogrv. Feel free to share and reuse.
set -Eeuo pipefail
cd "$(dirname "${BASH_SOURCE[0]}")/.."
fail () {
echo "$@" >&2
false
}
PROJECT_ID=XXXXXXXX
main () {
# shellcheck disable=SC1090
test -f ~/.gitlab.env && source ~/.gitlab.env
test -v API_KEY || fail "API_KEY not defined"
test -n "$API_KEY" || fail "API_KEY is empty"
local filename="${1:-".gitlab-ci.yml"}"
local response
response="$(
jq --null-input --arg yaml "$(<"$filename")" '{ content: $yaml }' \
| http --check-status \
POST https://gitlab.com/api/v4/ci/lint \
"PRIVATE-TOKEN: $API_KEY"
)"
if ! test "$(jq '.status' <<<"$response")" != "valid"
then
echo "$filename is invalid CI/CD config!"
jq <<<"$response"
false
else
echo "$filename is valid CI/CD config"
true
fi >&2
response="$(
jq --null-input --arg yaml "$(<"$filename")" '{ content: $yaml }' \
| http --check-status \
POST https://gitlab.com/api/v4/projects/$PROJECT_ID/ci/lint \
"PRIVATE-TOKEN: $API_KEY"
)"
if jq 'if .valid then empty else ("" | halt_error(1)) end' <<<"$response"
then
echo "Project's CI/CD config is valid"
true
else
echo "Project's CI/CD config is not valid"
jq <<<"$response" .errors
jq <<<"$response" .warnings
false
fi >&2
}
main "$@"
Please note the script has some dependencies:
Posible enhacements
- The project endpoint can simulate pipeline creation, if provided a
dry_run
boolean parameter.