Commit d46f0f4e93a6

Vincent Demeester <vincent@sbr.pm>
2026-02-11 06:43:08
refactor: simplify actions to done and skip
Removed mark_read action since GitHub API treats read and done identically for notification fetching. The tool now only has two actions: done (archive) and skip (keep).
1 parent 701cf5b
Changed files (7)
dots
config
github-notif-manager
tools
dots/config/github-notif-manager/config.yaml
@@ -64,7 +64,7 @@ rules:
     filters:
       repository: "openshift-pipelines/operator"
       reason: "review_requested"
-    action: mark_done
+    action: done
     enabled: true
 
   # ─── KEEP remaining review requests ───────────────────────────────────
@@ -82,14 +82,14 @@ rules:
   - name: "Archive CI activity"
     filters:
       reason: "ci_activity"
-    action: mark_done
+    action: done
     enabled: true
 
   # State changes (PR merged/closed) — stale fast
   - name: "Archive state changes"
     filters:
       reason: "state_change"
-    action: mark_done
+    action: done
     enabled: false
 
   # Old read notifications — general cleanup
@@ -98,5 +98,5 @@ rules:
     filters:
       unread: false
       age_days: 7
-    action: mark_done
+    action: done
     enabled: true
tools/github-notif-manager/src/actions.rs
@@ -61,8 +61,7 @@ impl<'a> ActionExecutor<'a> {
 
         // Execute the actual action
         let exec_result = match action {
-            Action::MarkRead => self.client.mark_thread_read(&notification.id),
-            Action::MarkDone => self.client.mark_thread_done(&notification.id),
+            Action::Done => self.client.mark_thread_done(&notification.id),
             Action::Skip => Ok(()), // Already handled above
         };
 
tools/github-notif-manager/src/cache.rs
@@ -93,11 +93,6 @@ impl Cache {
         self.done_ids.insert(notification_id.to_string());
     }
 
-    /// Remove a notification from cache (for mark_read — keep in cache but update)
-    pub fn remove(&mut self, notification_id: &str) {
-        self.notifications.retain(|n| n.id != notification_id);
-    }
-
     /// Get the `since` parameter for incremental fetching
     pub fn since_param(&self) -> Option<String> {
         self.last_fetched.map(|dt| dt.to_rfc3339())
tools/github-notif-manager/src/config.rs
@@ -26,8 +26,7 @@ fn default_enabled() -> bool {
 #[derive(Debug, Deserialize, Serialize, Clone, PartialEq)]
 #[serde(rename_all = "snake_case")]
 pub enum Action {
-    MarkRead,
-    MarkDone,
+    Done,
     Skip,
 }
 
@@ -120,8 +119,7 @@ impl Config {
 impl std::fmt::Display for Action {
     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
         match self {
-            Action::MarkRead => write!(f, "mark_read"),
-            Action::MarkDone => write!(f, "mark_done"),
+            Action::Done => write!(f, "done"),
             Action::Skip => write!(f, "skip"),
         }
     }
tools/github-notif-manager/src/github.rs
@@ -131,26 +131,6 @@ impl GitHubClient {
         Ok(notifications)
     }
 
-    /// Mark a notification thread as read
-    pub fn mark_thread_read(&self, thread_id: &str) -> Result<()> {
-        let url = format!("https://api.github.com/notifications/threads/{}", thread_id);
-        
-        let response = self
-            .client
-            .patch(&url)
-            .header("Authorization", format!("Bearer {}", self.token))
-            .header("Accept", "application/vnd.github+json")
-            .header("X-GitHub-Api-Version", "2022-11-28")
-            .send()
-            .context("Failed to mark thread as read")?;
-
-        if response.status().as_u16() != 205 {
-            anyhow::bail!("Failed to mark thread as read: {}", response.status());
-        }
-
-        Ok(())
-    }
-
     /// Mark a notification thread as done (archive it)
     pub fn mark_thread_done(&self, thread_id: &str) -> Result<()> {
         let url = format!("https://api.github.com/notifications/threads/{}", thread_id);
tools/github-notif-manager/src/main.rs
@@ -276,7 +276,7 @@ fn cmd_process(
     if !dry_run {
         let done_ids: Vec<String> = results
             .iter()
-            .filter(|r| matches!(r.action, Action::MarkDone) && r.success)
+            .filter(|r| matches!(r.action, Action::Done) && r.success)
             .map(|r| r.notification_id.clone())
             .collect();
         for id in &done_ids {
@@ -288,28 +288,11 @@ fn cmd_process(
     cache.save(&cp)?;
 
     // Calculate statistics
-    let mut stats = std::collections::HashMap::new();
-    for action in &[Action::MarkRead, Action::MarkDone, Action::Skip] {
-        stats.insert(
-            action.to_string(),
-            (
-                results
-                    .iter()
-                    .filter(|r| &r.action == action && r.success)
-                    .count(),
-                results
-                    .iter()
-                    .filter(|r| &r.action == action && !r.success)
-                    .count(),
-            ),
-        );
-    }
+    let done_ok = results.iter().filter(|r| r.action == Action::Done && r.success).count();
+    let done_fail = results.iter().filter(|r| r.action == Action::Done && !r.success).count();
+    let skip_ok = results.iter().filter(|r| r.action == Action::Skip).count();
     let no_match = total_notifications - results.len();
 
-    let (done_ok, done_fail) = stats.get("mark_done").unwrap_or(&(0, 0));
-    let (read_ok, read_fail) = stats.get("mark_read").unwrap_or(&(0, 0));
-    let (skip_ok, _) = stats.get("skip").unwrap_or(&(0, 0));
-
     if tty {
         // Display results table
         let visible_results: Vec<_> = results
@@ -333,8 +316,7 @@ fn cmd_process(
 
             for result in &visible_results {
                 let (action_str, action_color) = match result.action {
-                    Action::MarkDone => ("done", Color::Yellow),
-                    Action::MarkRead => ("read", Color::Blue),
+                    Action::Done => ("done", Color::Yellow),
                     Action::Skip => ("skip", Color::DarkGrey),
                 };
 
@@ -368,17 +350,12 @@ fn cmd_process(
             ]);
 
         summary.add_row(vec![
-            Cell::new("Mark as Done"),
+            Cell::new("Done"),
             Cell::new(done_ok).set_alignment(CellAlignment::Right),
             Cell::new(done_fail).set_alignment(CellAlignment::Right),
         ]);
         summary.add_row(vec![
-            Cell::new("Mark as Read"),
-            Cell::new(read_ok).set_alignment(CellAlignment::Right),
-            Cell::new(read_fail).set_alignment(CellAlignment::Right),
-        ]);
-        summary.add_row(vec![
-            Cell::new("Skipped (kept)"),
+            Cell::new("Skipped"),
             Cell::new(skip_ok).set_alignment(CellAlignment::Right),
             Cell::new("-").set_alignment(CellAlignment::Right),
         ]);
@@ -396,8 +373,8 @@ fn cmd_process(
     } else {
         // Non-TTY: simple log-style output
         println!(
-            "done={} read={} skipped={} no_match={} done_failed={} read_failed={}",
-            done_ok, read_ok, skip_ok, no_match, done_fail, read_fail
+            "done={} skipped={} no_match={} failed={}",
+            done_ok, skip_ok, no_match, done_fail
         );
         if dry_run {
             println!("mode=dry-run");
tools/github-notif-manager/config.example.yaml
@@ -10,15 +10,15 @@ rules:
     filters:
       repository: "owner/repo"  # Exact match or pattern with *
       reason: "subscribed"       # Notification reason (see GitHub API docs)
-    action: mark_done           # mark_read, mark_done, or skip
+    action: done                # done or skip
     enabled: true
 
-  # Example: Mark CI/CD notifications as read
-  - name: "Auto-read CI notifications"
-    description: "Mark check suite notifications as read"
+  # Example: Archive CI/CD notifications
+  - name: "Archive CI notifications"
+    description: "Archive check suite notifications"
     filters:
       subject_type: "CheckSuite"  # Release, Issue, PullRequest, CheckSuite, etc.
-    action: mark_read
+    action: done
     enabled: true
 
   # Example: Archive notifications from specific repos
@@ -26,7 +26,7 @@ rules:
     description: "Auto-archive notifications from archived repositories"
     filters:
       repository: "owner/archived-*"  # Supports wildcard patterns
-    action: mark_done
+    action: done
     enabled: true
 
   # Example: Archive old read notifications
@@ -35,7 +35,7 @@ rules:
     filters:
       unread: false
       age_days: 7  # Older than N days
-    action: mark_done
+    action: done
     enabled: true
 
   # Example: Skip notifications from important repos (no action)
@@ -56,6 +56,5 @@ rules:
 # - updated_after: ISO date string (YYYY-MM-DD)
 
 # Available actions:
-# - mark_read: Mark notification as read (but keep in inbox)
-# - mark_done: Mark notification as done (archive it)
+# - done: Mark notification as done/archived (removes from inbox)
 # - skip: Don't process this notification (useful for exclusions)