aboutsummaryrefslogtreecommitdiffstats
path: root/sb_builder/fmt.py
diff options
context:
space:
mode:
Diffstat (limited to 'sb_builder/fmt.py')
-rw-r--r--sb_builder/fmt.py17
1 files changed, 16 insertions, 1 deletions
diff --git a/sb_builder/fmt.py b/sb_builder/fmt.py
index 5c50628..3676fd0 100644
--- a/sb_builder/fmt.py
+++ b/sb_builder/fmt.py
@@ -17,10 +17,12 @@
"""Text formatting shared by the tabs."""
import time
+from collections import Counter
NA = "n/a"
ICON = {"starting": "…", "running": "▶", "ok": "✔", "failed": "✘",
"killed": "■", "lost": "?"}
+BAD_RESULTS = ("failed", "aborted", "bad") # slackrepo item results that fail a job
def fmt_bytes(n):
@@ -54,10 +56,22 @@ def job_title(j):
return " ".join([j["kind"], *j["args"]])
+def counts(results):
+ """'3 ok, 1 failed' from a slackrepo job's {item: result}."""
+ return ", ".join(f"{n} {r}" for r, n in Counter(results.values()).most_common())
+
+
+def failed_items(j):
+ """The items of a slackrepo job whose result failed it, sorted."""
+ return sorted(i for i, r in (j.get("results") or {}).items() if r in BAD_RESULTS)
+
+
def outcome(j):
"""How an ended job went, as a sentence for its notification."""
took = fmt_duration(j["end"] - j["start"]) if "end" in j and "start" in j else None
after = f" after {took}" if took else ""
+ if failed_items(j):
+ return f"Failed: {', '.join(failed_items(j))} ({counts(j['results'])}){after}"
return {"ok": f"Succeeded in {took}" if took else "Succeeded",
"failed": f"Failed with exit code {j.get('exit', '?')}{after}",
"killed": f"Killed{after}",
@@ -68,4 +82,5 @@ def describe(j):
"""One-line job summary: icon, kind and args, start time, duration."""
dur = None if "start" not in j else j.get("end", time.time()) - j["start"]
return (f"{ICON.get(j['status'], '?')} {job_title(j)} "
- f"{fmt_time(j.get('start', j['created']))} {fmt_duration(dur)}")
+ f"{fmt_time(j.get('start', j['created']))} {fmt_duration(dur)}"
+ + (f" {counts(j['results'])}" if j.get("results") else ""))