Skip to content

Commit c575323

Browse files
committed
refactor: Polish notify and drop stale --force refs
1 parent b5357e6 commit c575323

5 files changed

Lines changed: 93 additions & 99 deletions

File tree

README.org

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -52,9 +52,8 @@ bb export --topics-filter "event" # only reports with topic "event"
5252
# bb export json, bb export rss, bb export stats, …
5353

5454
# 4. Send notification emails
55-
bb notify # send due notifications
55+
bb notify # send notifications
5656
bb notify --dry-run # preview without sending
57-
bb notify --force # ignore intervals
5857
bb notify --debug # verbose filtering diagnostics
5958

6059
# 5. Test SMTP configuration (dry-run by default; --send to actually send)
@@ -82,7 +81,7 @@ bb export [--force] [--index-only] Incremental export of all formats
8281
[--topics-filter TOPICS] Only export matching topics (csv)
8382
[--page-size N] Paginate HTML table (N rows/page)
8483
[--closed-retention DUR] Drop reports closed before cutoff
85-
bb notify [--dry-run] [--force] [--debug] Send notification emails
84+
bb notify [--dry-run] [--debug] Send notification emails
8685
bb maintenance [--delete] [--verbose] [-n source] Purge orphan emails
8786
[--retention DUR] Orphan retention (default 90d)
8887
[--failures] List recent command failures

bb.edn

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
export {:doc "Export reports: bb export [--force] [--index-only] [-n source] [-p 1|2|3] [-s 1-7]"
1010
:task (apply shell "bb scripts/bark-export.clj" *command-line-args*)}
1111

12-
notify {:doc "Send notification emails: bb notify [--dry-run] [--force] [--debug]"
12+
notify {:doc "Send notification emails: bb notify [--dry-run] [--debug]"
1313
:task (apply shell "bb scripts/bark-notify.clj" *command-line-args*)}
1414

1515
clean {:doc "Remove all files in public/"

docs/bark-manual.org

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -618,7 +618,7 @@ Each entry is a map with any of =:words=, =:scope=, =:report-types=
618618
applies to. When absent, the registry default is used.
619619
- Any command ID from the table below can be overridden, both triggers
620620
and directives.
621-
- Controls (role and notify) cannot be overridden.
621+
- Role controls cannot be overridden.
622622

623623
Per-source settings take precedence over the global =:commands=, which
624624
in turn take precedence over the built-in defaults.
@@ -1194,7 +1194,7 @@ The export, notification and maintenance tasks are run through
11941194
| | patches, text, events (for power users) |
11951195
| =bb notify= | Send notification emails |
11961196
| =bb notify --dry-run= | Preview notifications without sending |
1197-
| =bb notify --force= | Ignore per-subscriber interval |
1197+
| =bb notify --debug= | Verbose filtering diagnostics |
11981198
| =bb maintenance= | Show orphan emails (add =--delete= to purge) |
11991199
| =bb maintenance --retention 6m= | Override orphan retention (default 90d) |
12001200
| =bb maintenance --failures= | List recent command failures |

scripts/bark-notify.clj

Lines changed: 87 additions & 92 deletions
Original file line numberDiff line numberDiff line change
@@ -87,21 +87,21 @@
8787
(.getMessage e)))))
8888

8989
(defn- failures-for-subscriber
90-
"Return failures on `source` routed to `email-addr`, posted after
91-
`since-date` (or all of them if since-date is nil).
90+
"Return failures on `:source` routed to `:email`, posted after `:since`
91+
(or all of them if `:since` is nil).
9292
9393
Routing is driven by the `:audience` field on each failure entry:
9494
- `:author` -- shown only to the address that triggered the
9595
failure (someone seeing their own typo); default
9696
for legacy entries that predate the field.
9797
- `:maintainers` -- shown to every subscriber on the source."
98-
[all-failures email-addr source since-date]
99-
(let [addr (str/lower-case email-addr)]
98+
[all-failures {:keys [email source since]}]
99+
(let [addr (str/lower-case email)]
100100
(->> all-failures
101101
(filter (fn [{:keys [from audience date] src :source}]
102102
(and (= source src)
103-
(or (nil? since-date)
104-
(and date (.after ^java.util.Date date since-date)))
103+
(or (nil? since)
104+
(and date (.after ^java.util.Date date since)))
105105
(case (or audience :author)
106106
:author (= addr from)
107107
:maintainers true
@@ -183,16 +183,16 @@
183183
(defn- filter-relevant-reports
184184
"Filter the full report set against scope filters: actionable type,
185185
open, on-source, plus optional :subject-match / :topic substrings."
186-
[reports {:keys [source subj-match topic]}]
187-
(let [subj-lc (some-> subj-match str/lower-case)
188-
topic-lc (some-> topic str/lower-case)]
189-
(cond->> reports
190-
true (filter #(contains? actionable-types (:report/type %)))
191-
true (filter open?)
192-
true (filter #(= source (get-in % [:report/email :email/source])))
193-
subj-lc (filter #(some-> (get-in % [:report/email :email/subject])
186+
[reports {:keys [source subject-match topic]}]
187+
(let [subject-lc (some-> subject-match str/lower-case)
188+
topic-lc (some-> topic str/lower-case)]
189+
(cond->> (->> reports
190+
(filter #(contains? actionable-types (:report/type %)))
191+
(filter open?)
192+
(filter #(= source (get-in % [:report/email :email/source]))))
193+
subject-lc (filter #(some-> (get-in % [:report/email :email/subject])
194194
str/lower-case
195-
(str/includes? subj-lc)))
195+
(str/includes? subject-lc)))
196196
topic-lc (filter #(some-> (:report/topic-value %)
197197
str/lower-case
198198
(str/includes? topic-lc))))))
@@ -202,7 +202,7 @@
202202
and 2 (owned by you, with or without deadline) always show what you
203203
own. Section 3 (unacked & unowned) is the noisy one and is the
204204
only one filtered by min-priority and min-status."
205-
[relevant email {:keys [min-pri min-sts]}]
205+
[relevant email {:keys [min-priority min-status]}]
206206
(let [owned (filter #(owned-by? % email) relevant)]
207207
{:dl (->> owned
208208
(filter :report/deadline-value)
@@ -213,8 +213,8 @@
213213
:unacked (->> relevant
214214
(filter unacked?)
215215
(filter unowned?)
216-
(filter #(>= (report-priority %) min-pri))
217-
(filter #(>= (report-status %) min-sts)))}))
216+
(filter #(>= (report-priority %) min-priority))
217+
(filter #(>= (report-status %) min-status)))}))
218218

219219
(defn- failure-subjects-map
220220
"Build {message-id -> subject} for the message-ids referenced by `failures`."
@@ -250,29 +250,19 @@
250250
"Build the notification email body for one (email, subscription) pair.
251251
`failures` is a seq of cmd-failure entities to include."
252252
[db reports email subscription failures]
253-
(let [source (:source subscription)
254-
prefs {:source source
255-
:min-pri (:min-priority subscription 1)
256-
:min-sts (:min-status subscription 0)
257-
:subj-match (:subject-match subscription)
258-
:topic (:topic subscription)}
259-
relevant (->> (filter-relevant-reports reports prefs)
260-
(sort-by (juxt report-priority report-descendant-count)
261-
#(compare %2 %1)))
262-
{:keys [dl owned unacked]} (build-sections relevant email prefs)
263-
sec-fail (failures-section db source failures)
264-
sec-dl (section
265-
(str "== Upcoming deadlines -- owned by you (" source ") ==")
266-
dl)
267-
sec-owned (section
268-
(str "== Open bugs/patches/requests owned by you (" source ") ==")
269-
owned)
270-
sec-unack (section
271-
(str "== Unacked & unowned bugs/patches/requests (" source ") ==")
272-
unacked)]
253+
(let [source (:source subscription)
254+
prefs (merge {:min-priority 1 :min-status 0} subscription)
255+
relevant (->> (filter-relevant-reports reports prefs)
256+
(sort-by (juxt report-priority report-descendant-count)
257+
#(compare %2 %1)))
258+
{:keys [dl owned unacked]} (build-sections relevant email prefs)]
273259
(log/debug "build-email-body for" email (str "(source: " source ")"))
274260
(log/debug " total reports:" (count reports) "-- relevant:" (count relevant))
275-
(join-sections [sec-fail sec-dl sec-owned sec-unack])))
261+
(join-sections
262+
[(failures-section db source failures)
263+
(section (str "== Upcoming deadlines -- owned by you (" source ") ==") dl)
264+
(section (str "== Open bugs/patches/requests owned by you (" source ") ==") owned)
265+
(section (str "== Unacked & unowned bugs/patches/requests (" source ") ==") unacked)])))
276266

277267
;; ---------------------------------------------------------------------------
278268
;; Per-source kill switch
@@ -306,62 +296,67 @@
306296
;; Main
307297
;; ---------------------------------------------------------------------------
308298

309-
(defn- expand-subscribers
310-
"Expand the :subscribers map into a flat seq of [email subscription] pairs."
311-
[subscribers]
312-
(mapcat (fn [[email subs]]
313-
(map (fn [s] [email s]) subs))
314-
subscribers))
299+
(defn- log-skipped-pairs!
300+
"Debug-log subscribers skipped because their source has
301+
:notifications {:enabled false}."
302+
[src-map pairs]
303+
(doseq [[email s] pairs
304+
:when (not (source-notify-enabled? src-map (:source s)))]
305+
(log/debug "SKIPPED" email
306+
"-- notifications disabled for source" (:source s))))
315307

316308
;; Guard ensures this block only runs when the script is invoked directly,
317309
;; not when loaded via load-file (e.g. from tests or other scripts).
318310
(when (= (System/getProperty "babashka.file") *file*)
319-
(let [flags (set *command-line-args*)
320-
dry-run? (flags "--dry-run")
321-
debug? (flags "--debug")
322-
_ (when debug? (log/merge-config! {:min-level :debug}))
323-
config (load-config)
324-
dbp (db-path config)
325-
notif (:notifications config)]
326-
(when-not (and notif (:enabled notif))
327-
(log/info "Notifications disabled in config.")
328-
(System/exit 0))
329-
(let [smtp (or (:smtp notif)
330-
(do (log/error "No :smtp config under :notifications.")
331-
(System/exit 1)))
332-
subscribers (:subscribers notif)
333-
conn (when (seq subscribers)
334-
(d/get-conn dbp bark-schema {:wal? false}))]
335-
(when (empty? subscribers)
336-
(log/info "No :subscribers configured.")
337-
(System/exit 0))
338-
(try
339-
(let [db (d/db conn)
340-
src-map (build-source-map config)
341-
reports (all-reports db)
342-
all-failures (load-failures)
343-
last-shown (load-last-failures-shown)
344-
pairs (expand-subscribers subscribers)
345-
_ (log/debug (count pairs) "subscription(s) configured")
346-
live-pairs (filter (fn [[_ s]] (source-notify-enabled? src-map (:source s))) pairs)
347-
_ (do (when (< (count live-pairs) (count pairs))
348-
(doseq [[email s] pairs
349-
:when (not (source-notify-enabled? src-map (:source s)))]
350-
(log/debug "SKIPPED" email
351-
"-- notifications disabled for source"
352-
(:source s))))
353-
(log/debug (count live-pairs) "after per-source filter"))
354-
sent (atom 0)
355-
updated-shown (atom last-shown)]
356-
(try
311+
(let [flags (set *command-line-args*)
312+
dry-run? (flags "--dry-run")
313+
debug? (flags "--debug")
314+
_ (when debug? (log/merge-config! {:min-level :debug}))
315+
config (load-config)
316+
dbp (db-path config)
317+
notif (:notifications config)
318+
smtp (:smtp notif)
319+
subscribers (:subscribers notif)]
320+
(cond
321+
(not (and notif (:enabled notif)))
322+
(do (log/info "Notifications disabled in config.")
323+
(System/exit 0))
324+
325+
(nil? smtp)
326+
(do (log/error "No :smtp config under :notifications.")
327+
(System/exit 1))
328+
329+
(empty? subscribers)
330+
(do (log/info "No :subscribers configured.")
331+
(System/exit 0))
332+
333+
:else
334+
(let [conn (d/get-conn dbp bark-schema {:wal? false})
335+
last-shown (load-last-failures-shown)
336+
updated-shown (atom last-shown)
337+
sent (atom 0)]
338+
(try
339+
(let [db (d/db conn)
340+
src-map (build-source-map config)
341+
reports (all-reports db)
342+
all-failures (load-failures)
343+
pairs (for [[email subs] subscribers
344+
s subs]
345+
[email s])
346+
live-pairs (filter (fn [[_ s]] (source-notify-enabled? src-map (:source s))) pairs)]
347+
(log/debug (count pairs) "subscription(s) configured")
348+
(log-skipped-pairs! src-map pairs)
349+
(log/debug (count live-pairs) "after per-source filter")
357350
(if (empty? live-pairs)
358351
(log/info "No active subscriptions.")
359352
(doseq [[email subscription] live-pairs]
360353
(let [source (:source subscription)
361354
k (failures-key email source)
362355
since-ms (get last-shown k)
363356
since (when since-ms (java.util.Date. (long since-ms)))
364-
failures (failures-for-subscriber all-failures email source since)
357+
failures (failures-for-subscriber
358+
all-failures
359+
{:email email :source source :since since})
365360
body (build-email-body db reports email subscription failures)]
366361
(if body
367362
(do (log/info (if dry-run? "[dry-run]" "")
@@ -383,11 +378,11 @@
383378
(println "---")))
384379
(log/info "No open items for" email
385380
(str "(source: " source "),") "skipping.")))))
386-
(log/info "Done." (if dry-run? "Dry run, no emails sent." (str @sent " email(s) sent.")))
387-
(finally
388-
(when-not dry-run?
389-
(try (save-last-failures-shown! @updated-shown)
390-
(catch Exception e
391-
(log/error "Failed to persist last-notify-failures:" (.getMessage e))))))))
392-
(finally
393-
(d/close conn))))))
381+
(log/info "Done." (if dry-run? "Dry run, no emails sent." (str @sent " email(s) sent."))))
382+
(finally
383+
(when-not dry-run?
384+
(try (save-last-failures-shown! @updated-shown)
385+
(catch Exception e
386+
(log/error "Failed to persist last-notify-failures:"
387+
(.getMessage e)))))
388+
(d/close conn)))))))

src/bark/periods.clj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,7 @@
8181
(not= (:end a) (:start b))
8282
(conj errs (str "gap/overlap between periods " ai
8383
" and " bi ": :end " (:end a)
84-
" :start " (:start b)))
84+
" != :start " (:start b)))
8585
:else errs))
8686
[])))
8787

0 commit comments

Comments
 (0)