Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
Code Quality report for Clojure projects in Gitlab using babashka and clj-kondo.
#!/usr/bin/env bb
(ns script
"Make a 'Code Quality' report from clj-kondo for use in GitLab CI.
JSON issue format:
https://docs.gitlab.com/ee/user/project/merge_requests/code_quality.html#implementing-a-custom-tool
Usage:
Add the following job in .gitlab-ci.yml:
lint-clojure:
stage: test
needs: []
image: hansbugge/babashka:ubuntu-20.04
script:
- ./lint.clj > lint-report.json
artifacts:
reports:
codequality: lint-report.json
Note that the borkdude/babashka Docker image is based on
alpine so does not work with Gitlab CI."
(:require
[babashka.pods :as pods]
[cheshire.core :as json]
[clojure.java.shell :as shell])
(:import
(java.security MessageDigest)))
(binding [*out* *err*]
(when-not (-> (shell/sh "which" "clj-kondo") :exit (= 0))
(println "Installing clj-kondo...")
(let [install-script (slurp "https://raw.githubusercontent.com/borkdude/clj-kondo/master/script/install-clj-kondo")
result (shell/sh "bash" :in install-script)]
(when-not (-> result :exit (= 0))
(println "Installation failed")
(prn result)
(System/exit (:exit result)))
(println "Installation succeeded"))))
(pods/load-pod "clj-kondo")
(require '[pod.borkdude.clj-kondo :as clj-kondo])
(defn md5sum [s]
;; https://gist.github.com/jizhang/4325757#gistcomment-2633984
(->> s
.getBytes
(.digest (MessageDigest/getInstance "MD5"))
(BigInteger. 1)
(format "%032x")))
(defn fingerprint
"Simple fingerprint of finding which disregards the position in the source file,
so that a finding is not treated as new if it moves around a little bit."
[{:keys [type message level row end-row end-col col filename]}]
(-> [filename type level message (- end-row row) (- end-col col)]
str md5sum))
(def path-prefix "")
(def source-dirs ["src"])
(defn findings->codequality-report
"Make sure fingerprints are unique by appending consecutive numbers to duplicates"
[findings]
(loop [acc [] seen {} remaining findings]
(if-let [{:keys [row filename message] :as finding} (first remaining)]
(let [fp (fingerprint finding)
unique-fp (str fp "-" (seen fp 0))
issue {:description message
:fingerprint unique-fp
:location {:path (str path-prefix filename)
:lines {:begin row}}}]
(recur (conj acc issue)
(update seen fp (fnil inc 0))
(rest remaining)))
acc)))
(-> (clj-kondo/run! {:lint source-dirs})
:findings
findings->codequality-report
json/encode
print)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment