{"id":19345914,"url":"https://github.com/tolitius/boot-check","last_synced_at":"2025-05-09T01:27:07.120Z","repository":{"id":62434942,"uuid":"48823921","full_name":"tolitius/boot-check","owner":"tolitius","description":"check, analyze and inspect Clojure/Script code","archived":false,"fork":false,"pushed_at":"2019-11-29T17:49:01.000Z","size":193,"stargazers_count":70,"open_issues_count":6,"forks_count":9,"subscribers_count":5,"default_branch":"master","last_synced_at":"2024-11-10T04:08:19.175Z","etag":null,"topics":["boot","clojure","code-quality"],"latest_commit_sha":null,"homepage":"","language":"Clojure","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"epl-1.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/tolitius.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2015-12-30T23:36:52.000Z","updated_at":"2024-05-31T07:50:21.000Z","dependencies_parsed_at":"2022-11-01T21:02:38.215Z","dependency_job_id":null,"html_url":"https://github.com/tolitius/boot-check","commit_stats":null,"previous_names":[],"tags_count":12,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tolitius%2Fboot-check","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tolitius%2Fboot-check/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tolitius%2Fboot-check/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tolitius%2Fboot-check/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/tolitius","download_url":"https://codeload.github.com/tolitius/boot-check/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":225115291,"owners_count":17423063,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["boot","clojure","code-quality"],"created_at":"2024-11-10T04:08:21.457Z","updated_at":"2024-11-18T02:03:40.699Z","avatar_url":"https://github.com/tolitius.png","language":"Clojure","funding_links":[],"categories":[],"sub_categories":[],"readme":"# boot-check\n\n[Boot](https://github.com/boot-clj/boot) tasks to check, analyze and inspect Clojure/Script code.\n\nIt relies on universe tested [kibit](https://github.com/jonase/kibit),\n[eastwood](https://github.com/jonase/eastwood), [yagni](https://github.com/venantius/yagni), [bikeshed](https://github.com/dakrone/lein-bikeshed) and other titans.\n\n[![Clojars Project](http://clojars.org/tolitius/boot-check/latest-version.svg)](http://clojars.org/tolitius/boot-check)\n\n- [Why](#why)\n- [Kibit](#kibit)\n  - [From Command Line](#from-command-line)\n  - [From within \"build.boot\"](#from-within-buildboot)\n  - [Help](#help)\n- [Yagni](#yagni)\n  - [From Command Line](#from-command-line-1)\n  - [From within \"build.boot\"](#from-within-buildboot-1)\n  - [Help](#help-1)\n  - [Yagni entry points](#yagni-entry-points)\n- [Eastwood](#eastwood)\n  - [From Command Line](#from-command-line-2)\n  - [From within \"build.boot\"](#from-within-buildboot-2)\n  - [Help](#help-2)\n- [Bikeshed](#bikeshed)\n  - [From Command Line](#from-command-line-2)\n  - [From within \"build.boot\"](#from-within-buildboot-2)\n  - [Help](#help-2)\n  - [Bikeshed options](#bikeshed-options)\n- [Handling Errors](#handling-errors)\n  - [Kibit Exceptions](#kibit-exceptions)\n  - [Yagni Exceptions](#yagni-exceptions)\n  - [Eastwood Exceptions](#eastwood-exceptions)\n  - [Bikeshed Exceptions](#bikeshed-exceptions)\n  - [Aggregating Errors](#aggregating-errors)\n- [Reporting](#reporting)  \n- [Demo](#demo)\n- [License](#license)\n\n## Why\n\nTo be able to reach out to multiple code analyzers as well as compose them as [Boot tasks](https://github.com/boot-clj/boot/wiki/Tasks):\n\n```clojure\n(require '[tolitius.boot-check :as check])\n```\n\n```clojure\n(deftask check-sources []\n  (set-env! :source-paths #{\"src\" \"test\"})\n  (comp\n    (check/with-yagni)\n    (check/with-eastwood)\n    (check/with-kibit)\n    (check/with-bikeshed)))\n```\n\nYou can choose the tools (tasks) that apply, i.e. use one or several, and `boot-check` will do the rest: integration with analyzers, dependencies, reports, etc..\n\nAll these tasks will run inside [Boot pods](https://github.com/boot-clj/boot/wiki/Pods).\n\n## Kibit\n\n[kibit](https://github.com/jonase/kibit) is a static code analyzer for Clojure, ClojureScript, cljx and other Clojure variants.\n\n### From Command Line\n\nTo check your code directly from shell:\n\n```bash\n$ boot check/with-kibit\nlatest report from kibit.... [You Rock!]\n```\n\nIn case there are [problems](test/test/with_kibit.clj):\n\n```clojure\n(defn when-vs-if []\n  (if 42 42 nil))\n\n(defn vec-vs-into []\n  (into [] 42))\n```\n\nkibit will show suggestions:\n\n```clojure\n$ boot check/with-kibit\nAt ../.boot/cache/tmp/../fun/boot-check/yeg/-grrwi1/test/with_kibit.clj:4:\nConsider using:\n  (when 42 42)\ninstead of:\n  (if 42 42 nil)\n\nAt ../.boot/cache/tmp/../fun/boot-check/yeg/-grrwi1/test/with_kibit.clj:7:\nConsider using:\n  (vec 42)\ninstead of:\n  (into [] 42)\n\nWARN: kibit found some problems:\n\n{:problems #{{:expr (if 42 42 nil), :line 4, :column 3, :alt (when 42 42)}\n             {:expr (into [] 42), :line 7, :column 3, :alt (vec 42)}}}\n```\n\n### From within \"build.boot\"\n\nTo use `boot-check` tasks within `build.boot` is easy:\n\n```clojure\n(require '[tolitius.boot-check :as check])\n\n(deftask check-sources []\n  (set-env! :source-paths #{\"src\" \"test\"})\n  (comp\n    (check/with-kibit)))\n```\n\n### Help\n\n```shell\n$ boot check/with-kibit -h\nStatic code analyzer for Clojure, ClojureScript, cljx and other Clojure variants.\n\nThis task will run all the kibit checks within a pod.\n\nAt the moment it takes no arguments, but behold..! it will. (files, rules, reporters, etc..)\n\nOptions:\n  -h, --help  Print this help info.\n  -t, --throw-on-errors  throw an exception if the check does not pass\n```\n\n## Yagni\n\n[yagni](https://github.com/venantius/yagni) is a static code analyzer that helps you find unused code in your applications and libraries.\n\n### From Command Line\n\nTo check your code directly from shell:\n\n```shell\n$ boot check/with-yagni\nlatest report from yagni.... [You Rock!]\n```\n\nif Yagni finds [unused code](test/test/with_yagni.clj) it will gladly report the news:\n\n```shell\nWARN: could not find any references to the following:\n\ntolitius.yagni/check\ntest.with-yagni/func-the-second\ntest.with-yagni/other-func\ntolitius.yagni/report\ntest.with-kibit/vec-vs-into\ntest.with-yagni/-main\n\nWARN: the following have references to them, but their parents do not:\n\ntolitius.yagni/yagni-deps\ntolitius.yagni/pp\ntest.with-kibit/when-vs-if\ntest.with-yagni/func\ntest.with-yagni/notafunc\n```\n\n### From within \"build.boot\"\n\nTo use `boot-check` tasks within `build.boot` is easy:\n\n```clojure\n(require '[tolitius.boot-check :as check])\n\n(deftask check-sources []\n  (set-env! :source-paths #{\"src\" \"test\"})\n  (comp\n    (check/with-yagni)))\n```\n\n### Help\n\n```shell\n$ boot check/with-yagni -h\nStatic code analyzer for Clojure that helps you find unused code in your applications and libraries.\n\nThis task will run all the yagni checks within a pod.\n\nOptions:\n  -h, --help             Print this help info.\n  -o, --options OPTIONS  OPTIONS sets yagni options EDN map.\n  -t, --throw-on-errors  throw an exception if the check does not pass\n```\n\n#### Yagni entry points\n\nYagni works by searching your codebase from an initial set of entrypoints. As libraries, multi-main programs, and certain other types of projects either tend to have no `:main` or many entrypoint methods, you can instead, optionally, enumerate a `list of entrypoints` for your project in options:\n\n```clojure\n(check/with-yagni :options {:entry-points [\"test.with-yagni/-main\"\n                                           \"test.with-yagni/func-the-second\"\n                                           42]})))\n```\n\ncheck out the [example](https://github.com/tolitius/boot-check/blob/master/build.boot#L21-L23) in the `boot.build` of this project.\n\n## Eastwood\n\n[eastwood](https://github.com/jonase/eastwood) is a Clojure [lint](http://en.wikipedia.org/wiki/Lint_%28software%29) tool that uses the [tools.analyzer](https://github.com/clojure/tools.analyzer) and [tools.analyzer.jvm](https://github.com/clojure/tools.analyzer.jvm) libraries to inspect namespaces and report possible problems.\n\n### From Command Line\n\nTo check your code directly from shell:\n\n```shell\n$ boot check/with-eastwood\nlatest report from eastwood.... [You Rock!]\n```\nif eastwood finds [problems](test/test/with_eastwood.clj) it will gladly report the news:\n\n```shell\n== Linting test.with-kibit ==\n... /test/with_kibit.clj:4:3: constant-test: Test expression is always logical true or always logical false: 42 in form (if 42 42 nil)\n\n== Linting test.with-eastwood ==\n... /test/with_eastwood.clj:5:8: def-in-def: There is a def of a nested inside def nested-def\n\n== Warnings: 2 (not including reflection warnings)  Exceptions thrown: 0\n\nWARN: eastwood found some problems ^^^\n```\n\n### From within \"build.boot\"\n\nTo use `boot-check` tasks within `build.boot` is easy:\n\n```clojure\n(require '[tolitius.boot-check :as check])\n\n(deftask check-sources []\n  (set-env! :source-paths #{\"src\" \"test\"})\n  (comp\n    (check/with-eastwood)))\n```\n\n### Help\n\n```shell\n$ boot check/with-eastwood -h\nClojure lint tool that uses the tools.analyzer and tools.analyzer.jvm libraries to inspect namespaces and report possible problems\n\nThis task will run all the eastwood checks within a pod.\n\nAt the moment it takes no arguments, but behold..! it will. (linters, namespaces, etc.)\n\nOptions:\n  -h, --help  Print this help info.\n  -t, --throw-on-errors  throw an exception if the check does not pass\n```\n\n## Bikeshed\n\n[bikeshed](https://github.com/dakrone/lein-bikeshed) is a Clojure \"checkstyle/pmd\" tool that designed to tell you your code is bad, and that you should feel bad.\n\n### From Command Line\n\nTo check your code directly from shell:\n\n```shell\n$ boot check/with-bikeshed\nlatest report from bikeshed.... [You Rock!]\n```\nif bikeshed finds problems it will gladly report the news:\n\n```shell\nChecking for lines longer than 80 characters.\nBadly formatted files:\n../tolitius/boot_check.clj:8:            [boot.core :as core :refer [deftask user-files tmp-file set-env! get-env]]\n../tolitius/boot_check.clj:25:  \"Static code analyzer for Clojure, ClojureScript, cljx and other Clojure variants.\n../tolitius/boot_check.clj:29:  At the moment it takes no arguments, but behold..! it will. (files, rules, reporters, etc..)\"\n../tolitius/boot_check.clj:30:  ;; [f files FILE #{sym} \"the set of files to check.\"]      ;; TODO: convert these to \"tmp-dir/file\"\n\nChecking for lines with trailing whitespace.\nBadly formatted files:\n../tolitius/boot/helper.clj:6:  (mapv #(.getAbsolutePath %)\n../tolitius/checker/bikeshed.clj:7:  '[[lein-bikeshed \"0.2.0\" :exclusions [org.clojure/tools.cli\n../tolitius/checker/yagni.clj:33:      (let [graph# (binding [*ns* (the-ns *ns*)]\n../tolitius/boot/helper.clj:6:  (mapv #(.getAbsolutePath %)\n../tolitius/checker/bikeshed.clj:7:  '[[lein-bikeshed \"0.2.0\" :exclusions [org.clojure/tools.cli\n../tolitius/checker/yagni.clj:33:      (let [graph# (binding [*ns* (the-ns *ns*)]\n\nChecking for files ending in blank lines.\nNo files found.\n\nChecking for redefined var roots in source directories.\nNo with-redefs found.\n\nChecking whether you keep up with your docstrings.\n9/50 [18.00%] functions have docstrings.\nUse -v to list functions without docstrings\n\nWARN: bikeshed found some problems ^^^\n```\n\n### From within \"build.boot\"\n\nTo use `boot-check` tasks within `build.boot` is easy:\n\n```clojure\n(require '[tolitius.boot-check :as check])\n\n(deftask check-sources []\n  (set-env! :source-paths #{\"src\" \"test\"})\n  (comp\n    (check/with-bikeshed)))\n```\n\n### Help\n\n```shell\n$ boot check/with-bikeshed -h\n\nThis task is backed by 'lein-bikeshed' which is designed to tell you your code is bad, and that you should feel bad\n\nThis task will run bikeshed checks within a pod.\n\nOptions:\n  -h, --help             Print this help info.\n  -o, --options OPTIONS  OPTIONS sets bikeshed options EDN map.\n  -t, --throw-on-errors  throw an exception if the check does not pass\n```\n\n### Bikeshed Options\n\nBikeshed takes some options:\n\n```clojure\n(check/with-bikeshed :options {:check? #{:long-lines}\n                               :verbose true\n                               :max-line-length 42})\n```\n\nor\n\n```\n$ boot check/with-bikeshed -o '{:check? #{:long-lines :trailing-whitespace :var-redefs :bad-methods :name-collisions}}'\n```\n\ncheck out the [example](https://github.com/tolitius/boot-check/blob/master/build.boot#L34-L36) in the boot.build of this project.\n\n## Handling Errors\n\nAll tasks (i.e. for kibit, yagni, eastwood, bikeshed, etc.) accept an optional flag:\n\n```\n-t, --throw-on-errors  throw an exception if the check does not pass\n```\n\nthat if set will report all the problems found with the task, and then throw an exception.\n\nHere are some examples:\n\n```clojure\nboot.user=\u003e (set-env! :source-paths #{\"src\" \"test\"})\n```\n\n### Kibit Exceptions\n\n```clojure\nboot.user=\u003e (boot (check/with-kibit \"-t\"))\n ... reporting problems here then throws:\n\nclojure.lang.ExceptionInfo: kibit checks fail\n\nboot.user=\u003e *e\n#error {}\n :cause \"kibit checks fail\"\n :data {:causes ({:expr (if 42 42 nil), :line 4, :column 3, :alt (when 42 42)} {:expr (into [] 42), :line 7, :column 3, :alt (vec 42)})}\n ...\n```\n\n### Yagni Exceptions\n\n```clojure\nboot.user=\u003e (boot (check/with-yagni \"-t\"))\n ... reporting problems here then throws:\n\nclojure.lang.ExceptionInfo: yagni checks fail\n\nboot.user=\u003e *e\n#error {}\n :cause \"yagni checks fail\"\n :data {:causes {:no-refs #{tolitius.boot-check/with-eastwood test.with-yagni/other-func tolitius.boot-check/with-yagni tolitius.boot-check/with-bikeshed tolitius.boot-check/with-kibit test.with-eastwood/nested-def test.with-kibit/vec-vs-into test.with-eastwood/always-true}, :no-parent-refs #{tolitius.boot.helper/make-pod-pool tolitius.boot.helper/fileset-\u003epaths tolitius.checker.yagni/yagni-deps tolitius.checker.yagni/entry-points-file tolitius.checker.bikeshed/bikeshed-deps tolitius.checker.yagni/create-entry-points test.with-kibit/when-vs-if tolitius.checker.yagni/check tolitius.checker.yagni/pp tolitius.boot.helper/tmp-dir-paths test.with-eastwood/a tolitius.checker.yagni/report tolitius.checker.yagni/check-graph tolitius.checker.kibit/kibit-deps tolitius.checker.eastwood/check tolitius.checker.kibit/check tolitius.boot-check/pod-deps tolitius.boot-check/with-throw test.with-yagni/func tolitius.checker.bikeshed/check tolitius.checker.eastwood/eastwood-deps tolitius.boot-check/bootstrap}}}\n ...\n```\n\n\n### Eastwood Exceptions\n\n```clojure\nboot.user=\u003e (boot (check/with-eastwood \"-t\"))\n ... reporting problems here then throws:\n\nclojure.lang.ExceptionInfo: eastwood checks fail\n\nboot.user=\u003e *e\n#error {}\n :cause \"eastwood checks fail\"\n :data {:causes {:err nil, :warning-count 12, :exception-count 0}}\n ...\n```\n\nIn case of Eastwood warnings are not returned, just their number of them. They are however reported (printed) as found.\n\n### Bikeshed Exceptions\n\n```clojure\nboot.user=\u003e (boot (check/with-bikeshed \"-t\"))\n ... reporting problems here then throws:\n\nboot.user=\u003e *e\n#error {}\n :cause \"bikeshed checks fail\"\n :data {:causes true}\n ...\n```\n\nIn case of Bikeshed, no errors / warnings are retured, since its own internal checks just return true/false values. But the exception is raised nevertheless to indicate that some checks have failed.\n\n### Aggregating Errors\n\nThere are a couple of ways `boot-check` deals with exceptions:\n\n* report problems, but throw no exceptions\n\nthis is a default behavior, here is an [example](build.boot#L53-L58) from build.boot:\n\n```clojure\n(deftask check-all []\n  (comp\n    (test-kibit)\n    (test-yagni)\n    (test-eastwood)\n    (test-bikeshed))\n```\n\n* force to throw exceptions when errors are found\n\nThis is done by the `throw-on-error` boot task. Here are a couple of examples.\n\nThis [example]( build.boot#L40-L44) would run eastwood checker and would throw an exception right after it in case eastwood finds problems:\n\n```clojure\n(deftask test-eastwood-and-throw []\n  (set-env! :source-paths #{\"src\" \"test\"})\n  (comp\n    (check/with-eastwood :options {:gen-report true :exclude-linters [:unused-ret-vals]})\n    (check/throw-on-errors)))\n```\n\nthis [example](build.boot#L60-L66) would run all the checkers and if any of these checkers report errors it will _aggregate_ all of these errors and throw an exception including all of them:\n\n```clojure\n(deftask check-all-and-throw []\n  (comp\n    (test-kibit)\n    (test-yagni)\n    (test-eastwood)\n    (test-bikeshed)\n    (check/throw-on-errors)))\n```\n\nif errors are found their aggregate is thrown:\n\n```clojure\nclojure.lang.ExceptionInfo: Some of code checkers have failed.\n    causes: ({:category nil,\n              :linter-tool :kibit,\n              :key \"kibit\",\n              :coords\n              {:file nil, :line 5, :column 28, :line-end nil, :column-end nil},\n              :snippet nil,\n              :issue-form nil,\n              :id \"5616d90d-d957-4b15-bf53-082a0f82892a\",\n              :severity :normal,\n              :hint-form nil,\n              :message\n              \"Consider changing [ (fn [options] (:reporter options)) ] with [ :reporter ]\"}\n             {:category nil,\n              :linter-tool :yagni,\n              :key :no-parent-refs,\n              :coords\n              {:file \"tolitius/boot/helper.clj\",\n               :line 0,\n               :column 0,\n               :line-end nil,\n               :column-end nil},\n              :snippet nil,\n              :issue-form nil,\n              :id \"90249104-8b32-4125-9286-05f9fe3f13bf\",\n              :severity :normal,\n              :hint-form nil,\n              :message\n              \"Var tolitius.boot.helper/make-pod-pool is referenced by unused code\"}\n              ... ...\n```\n\n\n## Reporting\n\nBesides reporting errors to standard output (stdout) which could be diffficult to inspect `boot-check` can generate other reports in different formats (default and built in is HTML) with a help of a `:gen-report` option which forces a particular checker task to report its warnings.\n\nAll checkers with this option set to true will write found issues into a shared interim warnings file. Later this file will be used to generate the final report. `boot-check` allows plugging in new reporters. This can be done by implementing the following multimethod:\n\n```clojure\n(defmethod tolitius.core.reporting/report :your-own-generator [issues options])\n```\n\nAfter providing source code with a custom report generator a namespace containing that generator must be evaluated.\n\nThere is an already implemented, built in HTML report generator that can be set as a default by including this namespace in `build.boot`:\n\n```Clojure\n(require '[tolitius.reporter.html])\n```          \n\nwhich will load an HTML multimethod implementation.\n\nHere is an example of how to include a checker task into reporting:\n```clojure\n(check/with-kibit :options {:gen-report :true})\n```\n\nand how to override default html report generator:\n\n```clojure\n(set-env! :boot-check-reporter :your-own-generator)\n(comp\n  (check/with-kibit :options {:gen-report :true}))\n```\n\nA typical pipeline with reporting enabled (and additional `throw-on-errors` task) may look like this:\n\n```clojure\n(deftask check-with-report []\n  (set-env! :boot-check-reporter :your-own-generator) ;;setup report generator\n  (comp\n    (test-kibit)                                      ;; do not include in report - only stdout\n    (test-eastwood :options {:gen-report true})       ;; include in report and print stdout\n    (test-yagni)                                      ;; do not include in report - only stdout\n    (test-bikeshed :options {:gen-report true})       ;; include in report and print stdout\n    (check/throw-on-errors)))                         ;;throw errors after all.\n```\n\n### Other Reporting Options\n\nCurrently boot-check supports following reporting options:\n\n* `boot-check-reporter`: a hook to a custom report generator implementation (described above)\n* `report-file-name`: a file name pattern to be used when generating report files\n* `report-path`: a file path where this report should be written to\n* `report-skip-time?`: whether a timestamp should be included in the file name. By default a timestamp is included but you may want to disable it for example to enable fast refreshing when report is already opened in the browser\n\n### Report samples\n\nA \"grid\" view:\n\n![sample boot check report](doc/img/sample-report.png)\n\n\"Issue details\" view (currently only code snippet is showing in here):\n\n![issue details view](doc/img/issue-details.png)\n\n### Report limitations\n\nDue to implementation details of some of checkers (bikeshed, kibit) some limitations exist regarding amount of information visible on report.\n- kibit currently does not return filenames, which makes it impossible to include it in the report (only stdout directly from kibit reports filenames)\n- bikeshed does not return issue details at all - it only returns some summary containing list of tests which has not passed. Because of that - reports only contain that summary returned from bikeshed.\n\n## Demo\n\nHere is a boot check [demo project](https://github.com/tolitius/check-boot-check) which can be cloned and played with.\n\n## License\n\nCopyright © 2018 toliitus\n\nDistributed under the Eclipse Public License either version 1.0 or (at)\nyour option any later version.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftolitius%2Fboot-check","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ftolitius%2Fboot-check","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftolitius%2Fboot-check/lists"}