Simplify mirror planning now that failures are logged at origin
plan returned (Vec<Push>, Vec<TargetError>) only so trigger could drain
both into the old aggregate. With failures logged where they happen, plan
logs config-read failures itself and returns just the pushes, and a
log_failure method reads the repo name from self.repo rather than
threading it through.

Assisted-by: Claude Opus 4.8 via Claude Code
change voqmrltqvtsylktxkplvnnsklskwumsr
commit df6bed1bcecbb79d200f4e051c2814ac569e1ffe
author Alpha Chen <alpha@kejadlen.dev>
date
parent uvzkvluw
diff --git a/quire-server/src/mirror.rs b/quire-server/src/mirror.rs
index 51648cc..66aa000 100644
--- a/quire-server/src/mirror.rs
+++ b/quire-server/src/mirror.rs
@@ -70,27 +70,13 @@ pub fn trigger(quire: &Quire, event: &PushEvent) {
         secrets: &quire.config.secrets,
     };
 
-    let (pushes, errors) = mirror.plan(event);
-    for error in errors {
-        log_target_failure(&event.repo, &error);
-    }
-    for push in pushes {
+    for push in mirror.plan(event) {
         if let Err(cause) = mirror.run(&push) {
-            log_target_failure(&event.repo, &TargetError::Push { push, cause });
+            mirror.log_failure(&TargetError::Push { push, cause });
         }
     }
 }
 
-/// Emit one mirror target failure as a `tracing` error so sentry-tracing
-/// captures it as an individual exception, source chain and all.
-fn log_target_failure(repo: impl std::fmt::Display, error: &TargetError) {
-    tracing::error!(
-        %repo,
-        error = error as &(dyn std::error::Error + 'static),
-        "mirror: target failed",
-    );
-}
-
 /// One mirror push to perform: a ref pushed to a remote, authenticated with
 /// the named secret.
 #[derive(Debug)]
@@ -108,11 +94,9 @@ struct Mirror<'a> {
 
 impl Mirror<'_> {
     /// Expand each updated ref into one `Push` per configured mirror. A ref
-    /// whose config cannot be read yields a `Config` error and contributes
-    /// no pushes.
-    fn plan(&self, event: &PushEvent) -> (Vec<Push>, Vec<TargetError>) {
+    /// whose config cannot be read is logged and contributes no pushes.
+    fn plan(&self, event: &PushEvent) -> Vec<Push> {
         let mut pushes = Vec::new();
-        let mut errors = Vec::new();
         for push_ref in event.updated_refs() {
             match self.repo.repo_config(&push_ref.new_sha) {
                 Ok(config) => pushes.extend(config.mirrors.into_iter().map(|(url, secret)| Push {
@@ -120,13 +104,23 @@ impl Mirror<'_> {
                     url,
                     secret,
                 })),
-                Err(source) => errors.push(TargetError::Config {
+                Err(source) => self.log_failure(&TargetError::Config {
                     ref_name: push_ref.ref_name.clone(),
                     source,
                 }),
             }
         }
-        (pushes, errors)
+        pushes
+    }
+
+    /// Emit one mirror target failure as a `tracing` error so sentry-tracing
+    /// captures it as an individual exception, source chain and all.
+    fn log_failure(&self, error: &TargetError) {
+        tracing::error!(
+            repo = %self.repo.name(),
+            error = error as &(dyn std::error::Error + 'static),
+            "mirror: target failed",
+        );
     }
 
     /// Force-push the ref to the remote, reporting why the push failed.