Who does not fight everyday to follow the least surprise/astonishment principle? I know I do and my last issue was related with Gitlab-CI.
I had to wait after each git push
to discover if my .gitlab-ci.yml
file was valid or not.

As usual, automation is the answer. Wouldn't it be awesome if we could run this:
gitlab-ci-validate-watch
And then edit our .gitlab-ci.yml
until it's valid? That would be really awesome right?
Sadly at the time of writing Gitlab-CI documentation and API requires us to send our YAML file in stringified JSON format inside a content object to /api/v4/ci/lint
api endpoint. Yep, that's a lot of hard work for such a simple task.

Fortunately we can leverage jq.node (it's like jq but WAY MORE powerful) for that along with watchexec!
If you do not have jq.node and watchexec installed it's never too late:
npm i jq.node -g
brew install watchexec
With these two I was able to write the following helpers (don't forget to add them inside your ~/.zshrc
or equivalent):
function gitlab-ci-validate(){
DATA=$(jq.node -r js-yaml -x 'jsYaml.safeLoad | thru(x => (JSON.stringify({content: JSON.stringify(x)})))' < .gitlab-ci.yml)
curl -s --header "Content-Type: application/json" https://gitlab.com/api/v4/ci/lint --data $DATA | jq.node
}
function gitlab-ci-validate-watch(){
watchexec --watch $(pwd)/.gitlab-ci.yml 'zsh -c "source ~/.zshrc && gitlab-ci-validate"'
}
gitlab-ci-validate
validates .gitlab-ci.yml
file from the current working directory using gitlab.com
(it will also work with self-hosted gitlab instances) and gitlab-ci-validate-watch
runs gitlab-ci-validate
every time I save .gitlab-ci.yaml
.
gitlab-ci-validate
{
"status": "invalid",
"errors": [
"jobs:update:db:script config should be a string or an array of strings"
]
}
For extra sweetness, we might want to run gitlab-ci-validate
before each git push
using git pre-push
hook.