Integrating `jsonlint` in your CI

Today I received a pull request on a JSON file and it was wrong. We decided to look for a linting solution to run on our CI with some requirements:

  • It should validate and point out broken JSON.
  • It should fix the indentation.
  • It should not sort JSON objects.

After some research, we found different options with different levels of quality and liveliness. Actually, the most difficult part of looking for solutions sometimes is strongly influenced by those 2 factors. But I wouldn’t compare them today, so we finally decided to go for npm jsonlint.

Is easy to install:

npm install -g jsonlint

And easy to use:

Usage: jsonlint [file] [options]

file     file to parse; otherwise uses stdin

Options:
  -v, --version            print version and exit
  -s, --sort-keys          sort object keys
  -i, --in-place           overwrite the file
  -t CHAR, --indent CHAR   character(s) to use for indentation  [  ]
  -c, --compact            compact error display
  -V, --validate           a JSON schema to use for validation
  -e, --environment        which specification of JSON Schema the validation file uses  [json-schema-draft-03]
  -q, --quiet              do not print the parsed json to STDOUT  [false]
  -p, --pretty-print       force pretty printing even if invalid

Test integration

In our case we basically deploy a set of Makefiles with every project where we define some standard targets like release, test, or fix so basically I decided to add another linting check to the test target like so:

test: json.validate
json.validate:
    @for f in $(find . -type f -name "*.json"); do \
      jsonlint $f -p | sed -e '$a\' | diff $f -; \
      if [ $? -ne 0 ]; then \
        echo "Error validating $f." ; \
        exit 1 ; \
      fi \
    done

The for loop iterates through all the JSON files found doing a diff using jsonlint with the pretty-print flag.

jsonlint $f -p | sed -e '$a\' | diff $f -;

Note the use of sed to append a new line to the stream so that diff does not throw an error “No newline at end of file”. After the target is set in the Makefile everything is done as in our Jenkinsfile we have something like this already:

stage("Test") {
  steps {
    sh 'make test'
  }
}

Fix integration

As done for the testing the fixed target does exactly the same operation but applies the changes to the files directly. This target is going to be executed by developers before creating a Pull request as a cleanup step so is not critical to be fast so some more checks are executed to make it clean.

fix: json.fix
json.fix:
    @for f in $(find . -type f -name "_.json"); do \ jsonlint $f -q && jsonlint $f -qpi && sed -i -e '$a\' $f ; \ echo "Formatted $f" ; \ if [ $? -ne 0 ]; then \ echo "Error validating $f" ; \ exit 1 ; \ fi \ done_

The fixing process first validates the JSON in order to avoid errors and also minimize the output on the CI. If jsonlint fails validation with the pretty-print option this will output all the files to stdout. That is why you see jsonlint* called twice.

jsonlint $f -q && jsonlint $f -qpi && sed -i -e '$a\' $f

Note the ‘-i’ flag to edit the file in place. Also, note the usage of sed to append the new line to the file so that after this automatic fix the file is guaranteed to pass the validation step.


← Blog