Skip to content

Instantly share code, notes, and snippets.

@hansbugge
Created September 26, 2020 10:34
Show Gist options
  • Save hansbugge/4be701d771057e8ef6bbbb0912656355 to your computer and use it in GitHub Desktop.
Save hansbugge/4be701d771057e8ef6bbbb0912656355 to your computer and use it in GitHub Desktop.
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)
@RolT
Copy link

RolT commented Jan 20, 2025

Thanks a lot for the code. Tested with gitlab 17.6.2: it did not show up in the MR page until I added the severity key in the report for each finding.

                   :fingerprint unique-fp
                   :severity (case level
                               :error "major"
                               :warning "minor"
                               :info "info"
                               "info")

@hansbugge
Copy link
Author

Thanks! Good to hear that it still works after all these years. By the way, you should probably not use the docker image suggested in the script. The babashka image stopped being based on alpine long ago – babashka/babashka should work fine.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment