Skip to content

Instantly share code, notes, and snippets.

Last active Aug 25, 2021
What would you like to do?
Polylith dependency checker
(ns sean
"Placeholder for any dev-specific code I want to write."
(:require [ :as io]
[clojure.set :as set]
[clojure.string :as str]
[ :as t]))
(set! *warn-on-reflection* true)
(defn- libs-from-deps
"Given a list of files, find just the deps.edn files and extract
a set of all libraries from the deps/test deps."
([all-files] (libs-from-deps all-files nil))
([all-files type]
(into #{}
(filter #(str/ends-with? (str %) "/deps.edn"))
(map #(t/slurp-deps %))
(mapcat #(into (set (when-not (= :test type) (:deps %)))
(set (when-not (= :dev type)
(-> % :aliases :test :extra-deps)))))
;; just the actual libraries:
(remove #(:local/root (val %))))
(defn- analyze-deps
"Analyze sets of dependencies in a Polylith project.
Returns a hash map of possible problems:
:missing-dev-deps -- bricks that are missing from :dev deps
:missing-test-paths -- brick tests missing from :test paths
:extra-dev-deps -- overlap between :dev deps and bricks
:project-dev-deps -- project deps missing from :dev deps
:project-test-deps -- project test deps missing from :test deps"
(let [root-deps (t/slurp-deps (io/file (str root "deps.edn")))
main-deps (->> root-deps
(remove #(:local/root (val %)))
;; add in default deps:
(into (set (:deps root-deps))))
all-files (concat (file-seq (io/file (str root "bases")))
(file-seq (io/file (str root "components"))))
sources (into #{}
(filter #(str/ends-with? (str %) "/src"))
;; we want just the project folders:
(map #(str/replace (str %) #"/src$" "")))
tests (into #{}
;; but we do want test folders:
(filter #(str/ends-with? (str %) "/test"))
(map str))
all-deps (libs-from-deps all-files)
projects (file-seq (io/file (str root "projects")))
proj-deps (libs-from-deps projects :dev)
test-deps (libs-from-deps projects :test)]
;; verify all source :local/root deps are present:
(into #{}
(comp (filter :local/root) (map :local/root) (map #(str root %)))
(-> root-deps :aliases :dev :extra-deps (vals))))
;; verify all test :extra-paths are present:
(set (->> root-deps :aliases :test :extra-paths (map #(str root %)))))
;; verify no overlap between :dev :extra-deps and bases/components:
(set/intersection main-deps all-deps)
;; verify all project deps are in :dev deps:
(set/difference proj-deps main-deps)
;; verify all project test deps are in :test deps:
(set (->> root-deps :aliases :test :extra-deps)))}))
(defn missing-deps
"clojure -X:poly sean/missing-deps
Reports inconsistencies between :dev, :test, bricks, and projects."
(let [root (str (System/getProperty "user.dir") "/")
{:keys [missing-dev-deps missing-test-paths extra-dev-deps
project-dev-deps project-test-deps]}
(analyze-deps root)]
(when (seq missing-dev-deps)
(println "\nThe following bricks appear to be missing from :dev > :extra-deps")
(doseq [path (sort missing-dev-deps)]
(println "-" (str/replace path root ""))))
(when (seq missing-test-paths)
(println "\nThe following paths appear to be missing from :test > :extra-paths")
(doseq [path (sort missing-test-paths)]
(println "-" (str/replace path root ""))))
(when (seq extra-dev-deps)
(println "\nThe following :dev dependencies also appear in bricks")
(doseq [[lib version] (sort extra-dev-deps)]
(println "-" lib version)))
(when (seq project-dev-deps)
(println "\nThe following project deps appear to be missing from :dev > :extra-deps")
(doseq [[lib version] (sort project-dev-deps)]
(println "-" lib version)))
(when (seq project-test-deps)
(println "\nThe following project test deps appear to be missing from :test > :extra-deps")
(doseq [[lib version] (sort project-test-deps)]
(println "-" lib version)))))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment