#!/usr/bin/env lumo (ns project-checkup.core (:gen-class) (:require [clojure.java.shell :as shell] [clojure.string :as string])) (defn get-extension [path] "Extracts the extension of a path. Returns the extension with the period, e.g., '.txt' because that's the format people are used to seeing extensions in." (re-find #"\.[a-zA-Z0-9]+$" path)) (defn gather-project-info "Creates a dictionary of project information" [] (let [all-files (map str (file-seq (clojure.java.io/file "."))) ; files (string/split (:out (shell/sh "hg" "st" "-m" "-a" "-r" "-d" "-c" "-n" )) #"\n") files (map #(clojure.string/replace % #"./(.*)" "$1") all-files ) ] {:files files :extensions (frequencies (map get-extension files )) :path (System/getProperty "user.dir") :untracked-files (string/split (:out (shell/sh "chg" "st" "-u" "-n")) #"\n") :readme (if-let [filename (some #{"README.md" "README.txt" "README.mkd"} files)] (slurp filename) "") }) ) (defn color [color string] (let [color-sequence (case color :green "\u001B[32m" :yellow "\u001B[33m" :blue "\u001B[34m" :red "\u001B[31m" :cyan "\u001B[36m" :magenta "\u001B[35m" ) reset "\u001B[m" ] (str color-sequence string reset)) ) (defn check-vcs [project] (let [{files :files } project] (boolean (some #{".git" ".hg"} files)) )) (defn check-readme [project] (let [{files :files } project] (boolean (some #{"README.md" "README.txt" "README.mkd" "README"} files)) )) (defn check-untracked [project] (let [{untracked :untracked-files } project] (= (count untracked) 0)) ) (defn check-taskpaper [project] (let [{extensions :extensions files :files } project] (or (>= (get ".taskpaper" extensions 0) 1) (some #{"TODO" "TODO.txt" } files)))) (defn check-readme-placeholders [project] (= (count (re-find #"(FIXME|TODO)" (:readme project) )) 0)) (def checks [{:name "Has VCS" :description "" :function check-vcs :level :error :follow-up "Initialize a repository." } {:name "Always True" :function #(or true %) :level :error :follow-up "This is a bug." } {:name "Has Untracked" :description "" :function check-untracked :level :warning :follow-up "Commit or ignore files from 'hg st -u'." } {:name "No Todo" :function check-taskpaper :description "" :level :suggestion :follow-up "Add a todo file using Taskpaper." } {:name "Has Readme" :function check-readme :description "Readme exists" :level :suggestion :follow-up "Add a README." } {:name "README has no placeholders" :function check-readme-placeholders :description "No placeholders in README" :level :error :follow-up "Address placeholders or convert them to tasks." } ]) (defn perform-check [check project] (let [{check-name :name function :function follow-up :follow-up level :level } check result (function project) false-color (case level :suggestion :blue :warning :yellow :error :red :red) ] {:name check-name :result result :output (if result (color :green (str "✓" check-name " passed!")) (str check-name (color false-color " failed! ") "\n\tFollow up: " follow-up))})) (defn -main "Run checks." [& args] (try (doseq [check checks] (println (:output (perform-check check (gather-project-info) )))) (catch Exception ex (.printStackTrace ex) (str "caught exception: " (.getMessage ex))) (finally (shutdown-agents) )) )