4/23/2017

Validate Gitlab .gitlab-ci.yml one-liner

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.

»
 
 
Made with on a hot august night from an airplane the 19th of March 2017.
http://bit.ly/1II1u5L