Created
February 14, 2025 14:03
-
-
Save jimka2001/9a88d93eb040f5a4cdb203df0e7c103e to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
(ns check-activities | |
(:require | |
[clojure.java.shell :refer [sh]] | |
[clojure.data.csv :as csv] | |
[clojure.java.io :as io]) | |
) | |
(defn member | |
"Determines whether the given target is an element of the given sequence (or given set)." | |
[target items] | |
(boolean (cond | |
(empty? items) false | |
(nil? target) (some nil? items) | |
(false? target) (some false? items) | |
(set? items) (contains? items target) | |
:else (reduce (fn [_acc item] | |
(if (= item target) | |
(reduced true) | |
false)) false items)))) | |
(defn download-csv | |
"Returns a lazy sequence of hashmaps each with the following keys | |
corresponding to the headers of the output csv generated from | |
forge submissions tags-report. | |
i.e.: id, status, error, ref, groupSlug, assignmentUri, | |
receivedAt, author, job_id, job_successPercent, job_status | |
`expected` is a sequence of strings (typically user and tag), any line in the csv | |
which DOES NOT contain BOTH of these will be ignored and not included as a hashmap | |
in the return value. | |
" | |
[tenant course expected] | |
;; e.g. tenant = "epita-ing" | |
;; course = "2025-clojure-elective-promo-2027" | |
(let [forge (or (first (filter (fn [path] | |
(.exists (io/file path))) | |
[(format "%s/.local/bin/forge" (System/getProperty "user.home")) | |
"/usr/local/bin/forge"])) | |
"forge") | |
csv-file (format "%s.csv" course) | |
;; to install the `forge` program | |
;; pip install 'git+ssh://[email protected]/forge/tools/cli' | |
;; | |
;; to authenticate the first time | |
;; forge auth token | |
;; | |
;; if the authenticate gets corrupted | |
;; rm ~/.config/forge-cli-credentials.json | |
;; forge auth token | |
cmd [forge "submissions" "tags-report" | |
(format "%s/%s" tenant course) | |
csv-file] | |
_ (println [:cmd cmd]) | |
csv-out (apply sh cmd) | |
_ (println [:csv-out csv-out]) | |
_ (println [:reading csv-file]) | |
lines (csv/read-csv (slurp csv-file) :separator \,) | |
headers ["id" "status" "error" "ref" "groupSlug" "assignmentUri" | |
"receivedAt" "author" "job_id" "job_successPercent" "job_status"]] | |
(assert (= 0 (:exit csv-out)) | |
(:err csv-out)) | |
(assert (= (first lines) | |
headers)) | |
(for [line (rest lines) | |
:when (every? (fn [word] (member word line)) expected) ] | |
(zipmap headers line)))) | |
(defn validate [grouped known-status errors succeeded others] | |
(doseq [key (keys grouped)] | |
(assert (member key known-status) | |
(format "unknown status %s" key))) | |
(assert (empty? (for [hash errors] | |
(do (println [:status (get hash "status") | |
:error (get hash "error") | |
:tag (get hash "ref") | |
:hash hash]) | |
hash)))) | |
(doseq [hash succeeded] | |
(println [:status (get hash "status") | |
:grade (get hash "job_successPercent") | |
:tag (get hash "ref")]) | |
(assert (= "xyzzy" (get hash "job_successPercent")) | |
(format "Grade %s != xyzzy for %s" (get hash "job_successPercent") (get hash "ref")))) | |
(doseq [hash others] | |
(println [:status (get hash "status") | |
:tag (get hash "ref")]))) | |
(defn check [] | |
(let [[user tenant course & tags] *command-line-args* | |
get-status (fn [hash] (get hash "status")) | |
get-ref (fn [hash] (get hash "ref")) | |
known-status ["SUCCEEDED" "ERROR" "PROCESSING" "IDLE"] | |
] | |
(loop [tags tags] | |
(let [hashes (filter (fn [hash] | |
(and (= user (get hash "author")) | |
(some (fn [tag] | |
(= tag (get hash "ref"))) | |
tags))) | |
(download-csv tenant course [user])) | |
grouped (group-by get-status | |
hashes) | |
errors (get grouped "ERROR") | |
error-tags (map get-ref errors) | |
succeeded (get grouped "SUCCEEDED") | |
succeeded-tags (map get-ref succeeded) | |
completed-tags (concat succeeded-tags error-tags) | |
;; compute the hashes which are not completed | |
others (filter (fn [hash] | |
(not (member (get-ref hash) completed-tags))) | |
hashes)] | |
(validate grouped known-status errors succeeded others) | |
(let [waiting (filter (fn [tag] (not (member tag completed-tags))) | |
tags)] | |
(if (empty? waiting) | |
;; exit immediately, if we allow clojure to exit on its own, it takes a long | |
;; time for some reason I don't understand. | |
(System/exit 0)) | |
(Thread/sleep 10000) | |
(println [:waiting waiting]) | |
(recur waiting)))))) | |
(check) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment