Merge pull request #256 from github/ClojureLint

Clojure lint
This commit is contained in:
Lukas Gravley 2020-06-26 07:38:36 -05:00 committed by GitHub
commit 910901a3bb
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
10 changed files with 205 additions and 2 deletions

View file

@ -0,0 +1,13 @@
# Clojure Test Cases
This folder holds the test cases for **Clojure**.
## Additional Docs
No Additional information is needed for this test case.
## Good Test Cases
The test cases denoted: `LANGUAGE_good_FILE.EXTENSION` are all valid, and should pass successfully when linted.
- **Note:** They are linted utilizing the default linter rules.
## Bad Test Cases
The test cases denoted: `LANGUAGE_bad_FILE.EXTENSION` are **NOT** valid, and should trigger errors when linted.
- **Note:** They are linted utilizing the default linter rules.

View file

@ -0,0 +1,64 @@
(ns foo
(:require
[clojure.string :as str]
;; We're never using this namespace. Also, the namespaces aren't sorted.
[clojure.set :as set]))
;; Here we made a typo, so the symbol is unresolved:
(but-last [1 2 3])
;; Clj-kondo knows about arities of clojure namespaces, but you can also teach
;; it about your libraries or own namespaces
(str/join)
;; foo has an arity of 2, but we're not actually using y
(defn foo-fn [x y]
;; this do is redundant:
(do
;; this is handy for debugging, but please remove it before pushing your code:
(def tmp_x x)
(let [y (fn [] (inc x))]
;; the next let can be squashed together with the previous:
(let [z y]
;; whoopsy, calling a local function with an incorrect number of args:
(y x)
;; also wrong:
(recur)))))
(letfn
[(f [] (h 1))
(h [] (f 1))])
(defn- private-fn [])
;; redefining it...
(defn- private-fn [])
(defn foo [] :foo)
;; Type error, because foo doesn't return a number!
(inc (foo))
;; I'm tired now, let's sleep...
;; Oops, not happening because of wrong amount of args:
(Thread/sleep 1000 1 2)
;; Here we switch to another namespace and require the previous:
(ns bar (:require [foo :as f]))
;; Wrong arity when calling a function from the previous namespace:
(f/foo-fn)
;; private:
(f/private-fn)
;; this won't pass the reader:
{:a 1 :a 2}
;; and neither will this:
#{1 1}
;; nor this:
{:a 1 :b}
(ns bar-test (:require [clojure.test :as t]))
(t/deftest my-tests
;; you're not actually testing something here:
(odd? (inc 1)))

View file

@ -0,0 +1,34 @@
(ns foo
(:require
[clojure.string :as str]))
(butlast [1 2 3])
(str/join "" "")
(defn foo-fn [x]
(let [y (fn [] (inc x))]
(y)))
(letfn
[(f [g] (h g))
(h [i] (f i))])
(defn foo [] 1)
(inc (foo))
(Thread/sleep 1000 1)
;; Here we switch to another namespace and require the previous:
(ns bar (:require [foo :as f]))
(f/foo-fn 1)
{:a 1 :b 2}
#{1 2}
{:a 1 :b 2}
(ns bar-test (:require [clojure.test :as t]))
(t/deftest my-tests
(t/is (odd? (inc 1))))

2
.github/linters/.clj-kondo/config.edn vendored Normal file
View file

@ -0,0 +1,2 @@
{:linters {:unresolved-symbol {:exclude [(compojure.api.sweet/defroutes)]}
:refer-all {:exclude [clj-time.jdbc]}}}

3
.gitignore vendored
View file

@ -59,3 +59,6 @@ typings/
# next.js build output # next.js build output
.next .next
# clj-kondo cache
.cache

View file

@ -131,6 +131,15 @@ RUN curl -Ls "$(curl -Ls https://api.github.com/repos/terraform-linters/tflint/r
RUN wget "https://github.com/dotenv-linter/dotenv-linter/releases/latest/download/dotenv-linter-alpine-x86_64.tar.gz" -O - -q | tar -xzf - \ RUN wget "https://github.com/dotenv-linter/dotenv-linter/releases/latest/download/dotenv-linter-alpine-x86_64.tar.gz" -O - -q | tar -xzf - \
&& mv "dotenv-linter" /usr/bin && mv "dotenv-linter" /usr/bin
#####################
# Install clj-kondo #
#####################
ARG CLJ_KONDO_VERSION='2020.06.12'
RUN curl -sLO https://github.com/borkdude/clj-kondo/releases/download/v${CLJ_KONDO_VERSION}/clj-kondo-${CLJ_KONDO_VERSION}-linux-static-amd64.zip \
&& unzip clj-kondo-${CLJ_KONDO_VERSION}-linux-static-amd64.zip \
&& rm clj-kondo-${CLJ_KONDO_VERSION}-linux-static-amd64.zip \
&& mv clj-kondo /usr/bin/
################## ##################
# Install ktlint # # Install ktlint #
################## ##################
@ -166,6 +175,7 @@ ENV GITHUB_SHA=${GITHUB_SHA} \
VALIDATE_TERRAFORM=${VALIDATE_TERRAFORM} \ VALIDATE_TERRAFORM=${VALIDATE_TERRAFORM} \
VALIDATE_CSS=${VALIDATE_CSS} \ VALIDATE_CSS=${VALIDATE_CSS} \
VALIDATE_ENV=${VALIDATE_ENV} \ VALIDATE_ENV=${VALIDATE_ENV} \
VALIDATE_CLOJURE=${VALIDATE_CLOJURE} \
VALIDATE_KOTLIN=${VALIDATE_KOTLIN} \ VALIDATE_KOTLIN=${VALIDATE_KOTLIN} \
VALIDATE_POWERSHELL=${VALIDATE_POWERSHELL} \ VALIDATE_POWERSHELL=${VALIDATE_POWERSHELL} \
ANSIBLE_DIRECTORY=${ANSIBLE_DIRECTORY} \ ANSIBLE_DIRECTORY=${ANSIBLE_DIRECTORY} \

View file

@ -36,6 +36,7 @@ Developers on **GitHub** can call the **GitHub Action** to lint their code base
| --- | --- | | --- | --- |
| **Ansible** | [ansible-lint](https://github.com/ansible/ansible-lint) | | **Ansible** | [ansible-lint](https://github.com/ansible/ansible-lint) |
| **CSS** | [stylelint](https://stylelint.io/) | | **CSS** | [stylelint](https://stylelint.io/) |
| **Clojure** | [clj-kondo](https://github.com/borkdude/clj-kondo) |
| **CoffeeScript** | [coffeelint](https://coffeelint.github.io/) | | **CoffeeScript** | [coffeelint](https://coffeelint.github.io/) |
| **Dockerfile** | [dockerfilelint](https://github.com/replicatedhq/dockerfilelint.git) | | **Dockerfile** | [dockerfilelint](https://github.com/replicatedhq/dockerfilelint.git) |
| **Golang** | [golangci-lint](https://github.com/golangci/golangci-lint) | | **Golang** | [golangci-lint](https://github.com/golangci/golangci-lint) |
@ -159,6 +160,7 @@ and won't run anything unexpected.
| **VALIDATE_TERRAFORM** | `true` | Flag to enable or disable the linting process of the language. | | **VALIDATE_TERRAFORM** | `true` | Flag to enable or disable the linting process of the language. |
| **VALIDATE_CSS** | `true` | Flag to enable or disable the linting process of the language. | | **VALIDATE_CSS** | `true` | Flag to enable or disable the linting process of the language. |
| **VALIDATE_ENV** | `true` | Flag to enable or disable the linting process of the language. | | **VALIDATE_ENV** | `true` | Flag to enable or disable the linting process of the language. |
| **VALIDATE_CLOJURE** | `true` | Flag to enable or disable the linting process of the language. |
| **VALIDATE_KOTLIN** | `true` | Flag to enable or disable the linting process of the language. | | **VALIDATE_KOTLIN** | `true` | Flag to enable or disable the linting process of the language. |
| **ANSIBLE_DIRECTORY** | `/ansible` | Flag to set the root directory for Ansible file location(s). | | **ANSIBLE_DIRECTORY** | `/ansible` | Flag to set the root directory for Ansible file location(s). |
| **ACTIONS_RUNNER_DEBUG** | `false` | Flag to enable additional information about the linter, versions, and additional output. | | **ACTIONS_RUNNER_DEBUG** | `false` | Flag to enable additional information about the linter, versions, and additional output. |

View file

@ -0,0 +1,2 @@
{:linters {:unresolved-symbol {:exclude [(compojure.api.sweet/defroutes)]}
:refer-all {:exclude [clj-time.jdbc]}}}

View file

@ -607,3 +607,23 @@ import package.b.*
### ktlint disable entire file ### ktlint disable entire file
- There is currently **No** way to disable rules inline of the file(s) - There is currently **No** way to disable rules inline of the file(s)
--------------------------------------------------------------------------------
## Clojure
- [clj-kondo](https://github.com/borkdude/clj-kondo)
- Since clj-kondo approaches static analysis in a very Clojure way, it is advised to read the [configuration docs](https://github.com/borkdude/clj-kondo/blob/master/doc/config.md)
### clj-kondo standard Config file
- `.github/linters/.clj-kondo/config.edn`
### clj-kondo disable single line
- There is currently **No** way to disable rules in a single line
### clj-kondo disable code block
- There is currently **No** way to disable rules in a code block
### clj-kondo disable entire file
```clojure
{:output {:exclude-files ["path/to/file"]}}
```

View file

@ -54,6 +54,9 @@ POWERSHELL_LINTER_RULES="$DEFAULT_RULES_LOCATION/$POWERSHELL_FILE_NAME" # Pat
# CSS Vars # CSS Vars
CSS_FILE_NAME='.stylelintrc.json' # Name of the file CSS_FILE_NAME='.stylelintrc.json' # Name of the file
CSS_LINTER_RULES="$DEFAULT_RULES_LOCATION/$CSS_FILE_NAME" # Path to the CSS lint rules CSS_LINTER_RULES="$DEFAULT_RULES_LOCATION/$CSS_FILE_NAME" # Path to the CSS lint rules
# Clojure Vars
CLOJURE_FILE_NAME='.clj-kondo/config.edn'
CLOJURE_LINTER_RULES="$DEFAULT_RULES_LOCATION/$CLOJURE_FILE_NAME"
####################################### #######################################
# Linter array for information prints # # Linter array for information prints #
@ -61,7 +64,8 @@ CSS_LINTER_RULES="$DEFAULT_RULES_LOCATION/$CSS_FILE_NAME" # Path to th
LINTER_ARRAY=("jsonlint" "yamllint" "xmllint" "markdownlint" "shellcheck" LINTER_ARRAY=("jsonlint" "yamllint" "xmllint" "markdownlint" "shellcheck"
"pylint" "perl" "rubocop" "coffeelint" "eslint" "standard" "pylint" "perl" "rubocop" "coffeelint" "eslint" "standard"
"ansible-lint" "/dockerfilelint/bin/dockerfilelint" "golangci-lint" "tflint" "ansible-lint" "/dockerfilelint/bin/dockerfilelint" "golangci-lint" "tflint"
"stylelint" "dotenv-linter" "powershell" "ktlint") "stylelint" "dotenv-linter" "powershell" "ktlint" "clj-kondo")
############################# #############################
# Language array for prints # # Language array for prints #
@ -69,7 +73,7 @@ LINTER_ARRAY=("jsonlint" "yamllint" "xmllint" "markdownlint" "shellcheck"
LANGUAGE_ARRAY=('YML' 'JSON' 'XML' 'MARKDOWN' 'BASH' 'PERL' 'PHP' 'RUBY' 'PYTHON' LANGUAGE_ARRAY=('YML' 'JSON' 'XML' 'MARKDOWN' 'BASH' 'PERL' 'PHP' 'RUBY' 'PYTHON'
'COFFEESCRIPT' 'ANSIBLE' 'JAVASCRIPT_STANDARD' 'JAVASCRIPT_ES' 'COFFEESCRIPT' 'ANSIBLE' 'JAVASCRIPT_STANDARD' 'JAVASCRIPT_ES'
'TYPESCRIPT_STANDARD' 'TYPESCRIPT_ES' 'DOCKER' 'GO' 'TERRAFORM' 'TYPESCRIPT_STANDARD' 'TYPESCRIPT_ES' 'DOCKER' 'GO' 'TERRAFORM'
'ENV' 'POWERSHELL' 'KOTLIN') 'CSS' 'ENV' 'POWERSHELL' 'KOTLIN' 'CLOJURE')
################### ###################
# GitHub ENV Vars # # GitHub ENV Vars #
@ -99,6 +103,7 @@ VALIDATE_DOCKER="${VALIDATE_DOCKER}" # Boolean to validate lang
VALIDATE_GO="${VALIDATE_GO}" # Boolean to validate language VALIDATE_GO="${VALIDATE_GO}" # Boolean to validate language
VALIDATE_CSS="${VALIDATE_CSS}" # Boolean to validate language VALIDATE_CSS="${VALIDATE_CSS}" # Boolean to validate language
VALIDATE_ENV="${VALIDATE_ENV}" # Boolean to validate language VALIDATE_ENV="${VALIDATE_ENV}" # Boolean to validate language
VALIDATE_CLOJURE="${VALIDATE_CLOJURE}" # Boolean to validate language
VALIDATE_TERRAFORM="${VALIDATE_TERRAFORM}" # Boolean to validate language VALIDATE_TERRAFORM="${VALIDATE_TERRAFORM}" # Boolean to validate language
VALIDATE_POWERSHELL="${VALIDATE_POWERSHELL}" # Boolean to validate language VALIDATE_POWERSHELL="${VALIDATE_POWERSHELL}" # Boolean to validate language
VALIDATE_KOTLIN="${VALIDATE_KOTLIN}" # Boolean to validate language VALIDATE_KOTLIN="${VALIDATE_KOTLIN}" # Boolean to validate language
@ -148,6 +153,7 @@ FILE_ARRAY_TERRAFORM=() # Array of files to check
FILE_ARRAY_POWERSHELL=() # Array of files to check FILE_ARRAY_POWERSHELL=() # Array of files to check
FILE_ARRAY_CSS=() # Array of files to check FILE_ARRAY_CSS=() # Array of files to check
FILE_ARRAY_ENV=() # Array of files to check FILE_ARRAY_ENV=() # Array of files to check
FILE_ARRAY_CLOJURE=() # Array of files to check
FILE_ARRAY_KOTLIN=() # Array of files to check FILE_ARRAY_KOTLIN=() # Array of files to check
############ ############
@ -174,6 +180,7 @@ ERRORS_FOUND_TERRAFORM=0 # Count of errors found
ERRORS_FOUND_POWERSHELL=0 # Count of errors found ERRORS_FOUND_POWERSHELL=0 # Count of errors found
ERRORS_FOUND_CSS=0 # Count of errors found ERRORS_FOUND_CSS=0 # Count of errors found
ERRORS_FOUND_ENV=0 # Count of errors found ERRORS_FOUND_ENV=0 # Count of errors found
ERRORS_FOUND_CLOJURE=0 # Count of errors found
ERRORS_FOUND_KOTLIN=0 # Count of errors found ERRORS_FOUND_KOTLIN=0 # Count of errors found
################################################################################ ################################################################################
@ -755,6 +762,7 @@ GetValidationInfo()
VALIDATE_POWERSHELL=$(echo "$VALIDATE_POWERSHELL" | awk '{print tolower($0)}') VALIDATE_POWERSHELL=$(echo "$VALIDATE_POWERSHELL" | awk '{print tolower($0)}')
VALIDATE_CSS=$(echo "$VALIDATE_CSS" | awk '{print tolower($0)}') VALIDATE_CSS=$(echo "$VALIDATE_CSS" | awk '{print tolower($0)}')
VALIDATE_ENV=$(echo "$VALIDATE_ENV" | awk '{print tolower($0)}') VALIDATE_ENV=$(echo "$VALIDATE_ENV" | awk '{print tolower($0)}')
VALIDATE_CLOJURE=$(echo "$VALIDATE_CLOJURE" | awk '{print tolower($0)')
VALIDATE_KOTLIN=$(echo "$VALIDATE_KOTLIN" | awk '{print tolower($0)}') VALIDATE_KOTLIN=$(echo "$VALIDATE_KOTLIN" | awk '{print tolower($0)}')
################################################ ################################################
@ -782,6 +790,7 @@ GetValidationInfo()
-n "$VALIDATE_POWERSHELL" || \ -n "$VALIDATE_POWERSHELL" || \
-n "$VALIDATE_CSS" || \ -n "$VALIDATE_CSS" || \
-n "$VALIDATE_ENV" || \ -n "$VALIDATE_ENV" || \
-n "$VALIDATE_CLOJURE" || \
-n "$VALIDATE_KOTLIN" ]]; then -n "$VALIDATE_KOTLIN" ]]; then
ANY_SET="true" ANY_SET="true"
fi fi
@ -1095,6 +1104,20 @@ GetValidationInfo()
fi fi
#######################################
# Validate if we should check Clojure #
#######################################
if [[ "$ANY_SET" == "true" ]]; then
# Some linter flags were set - only run those set to true
if [[ -z "$VALIDATE_CLOJURE" ]]; then
# Clojure flag was not set - default to false
VALIDATE_CLOJURE="false"
fi
else
# No linter flags were set - default all to true
VALIDATE_CLOJURE="true"
fi
####################################### #######################################
# Print which linters we are enabling # # Print which linters we are enabling #
####################################### #######################################
@ -1198,6 +1221,11 @@ GetValidationInfo()
else else
PRINT_ARRAY+=("- Excluding [CSS] files in code base...") PRINT_ARRAY+=("- Excluding [CSS] files in code base...")
fi fi
if [[ "$VALIDATE_CLOJURE" == "true" ]]; then
PRINT_ARRAY+=("- Validating [CLOJURE] files in code base...")
else
PRINT_ARRAY+=("- Excluding [CLOJURE] files in code base...")
fi
if [[ "$VALIDATE_ENV" == "true" ]]; then if [[ "$VALIDATE_ENV" == "true" ]]; then
PRINT_ARRAY+=("- Validating [ENV] files in code base...") PRINT_ARRAY+=("- Validating [ENV] files in code base...")
else else
@ -1593,6 +1621,15 @@ BuildFileList()
# Set the READ_ONLY_CHANGE_FLAG since this could be exec # # Set the READ_ONLY_CHANGE_FLAG since this could be exec #
########################################################## ##########################################################
READ_ONLY_CHANGE_FLAG=1 READ_ONLY_CHANGE_FLAG=1
elif [ "$FILE" == "clj" ] || [ "$FILE" == "cljs" ] || [ "$FILE" == "cljc" ] || [ "$FILE" == "edn" ]; then
################################
# Append the file to the array #
################################
FILE_ARRAY_CLOJURE+=("$FILE")
##########################################################
# Set the READ_ONLY_CHANGE_FLAG since this could be exec #
##########################################################
READ_ONLY_CHANGE_FLAG=1
else else
############################################## ##############################################
# Use file to see if we can parse what it is # # Use file to see if we can parse what it is #
@ -2122,6 +2159,7 @@ Footer()
[ "$ERRORS_FOUND_RUBY" -ne 0 ] || \ [ "$ERRORS_FOUND_RUBY" -ne 0 ] || \
[ "$ERRORS_FOUND_CSS" -ne 0 ] || \ [ "$ERRORS_FOUND_CSS" -ne 0 ] || \
[ "$ERRORS_FOUND_ENV" -ne 0 ] || \ [ "$ERRORS_FOUND_ENV" -ne 0 ] || \
[ "$ERRORS_FOUND_CLOJURE" -ne 0 ] || \
[ "$ERRORS_FOUND_KOTLIN" -ne 0 ]; then [ "$ERRORS_FOUND_KOTLIN" -ne 0 ]; then
# Failed exit # Failed exit
echo "Exiting with errors found!" echo "Exiting with errors found!"
@ -2183,6 +2221,7 @@ RunTestCases()
TestCodebase "POWERSHELL" "pwsh" "pwsh -c Invoke-ScriptAnalyzer -EnableExit -Settings $POWERSHELL_LINTER_RULES -Path" ".*\.\(ps1\|psm1\|psd1\|ps1xml\|pssc\|psrc\|cdxml\)\$" TestCodebase "POWERSHELL" "pwsh" "pwsh -c Invoke-ScriptAnalyzer -EnableExit -Settings $POWERSHELL_LINTER_RULES -Path" ".*\.\(ps1\|psm1\|psd1\|ps1xml\|pssc\|psrc\|cdxml\)\$"
TestCodebase "CSS" "stylelint" "stylelint --config $CSS_LINTER_RULES" ".*\.\(css\)\$" TestCodebase "CSS" "stylelint" "stylelint --config $CSS_LINTER_RULES" ".*\.\(css\)\$"
TestCodebase "ENV" "dotenv-linter" "dotenv-linter" ".*\.\(env\)\$" TestCodebase "ENV" "dotenv-linter" "dotenv-linter" ".*\.\(env\)\$"
TestCodebase "CLOJURE" "clj-kondo" "clj-kondo --config $CLOJURE_LINTER_RULES --lint" ".*\.\(clj\|cljs\|cljc\|edn\)\$"
TestCodebase "KOTLIN" "ktlint" "ktlint" ".*\.\(kt\|kts\)\$" TestCodebase "KOTLIN" "ktlint" "ktlint" ".*\.\(kt\|kts\)\$"
################# #################
@ -2515,6 +2554,20 @@ if [ "$VALIDATE_DOCKER" == "true" ]; then
LintCodebase "DOCKER" "/dockerfilelint/bin/dockerfilelint" "/dockerfilelint/bin/dockerfilelint" ".*\(Dockerfile\)\$" "${FILE_ARRAY_DOCKER[@]}" LintCodebase "DOCKER" "/dockerfilelint/bin/dockerfilelint" "/dockerfilelint/bin/dockerfilelint" ".*\(Dockerfile\)\$" "${FILE_ARRAY_DOCKER[@]}"
fi fi
###################
# CLOJURE LINTING #
###################
if [ "$VALIDATE_CLOJURE" == "true" ]; then
#################################
# Get Clojure standard rules #
#################################
GetStandardRules "clj-kondo"
#########################
# Lint the Clojure files #
#########################
LintCodebase "CLOJURE" "clj-kondo" "clj-kondo --config $CLOJURE_LINTER_RULES --lint" ".*\.\(clj\|cljs\|cljc\|edn\)\$" "${FILE_ARRAY_CLOJURE[@]}"
fi
###################### ######################
# POWERSHELL LINTING # # POWERSHELL LINTING #
###################### ######################