extract run_ref from anonymous closure in trigger
The sentry::with_scope closure in trigger was capturing repo, config,
event, db_path, and sentry_dsn from the enclosing scope while also
handling transport construction and error-level logging. Extracted to
a standalone run_ref function with explicit parameters.

Assisted-by: Claude Opus 4.6 (OpenRouter)
change vxstnqmkyrxqwrwwvskuzyunlvswqout
commit 0b03661c94e9d11bc6ec01265ef9a83e146a926a
author Alpha Chen <alpha@kejadlen.dev>
date
parent ynpmrmzs
diff --git a/quire-server/src/ci/mod.rs b/quire-server/src/ci/mod.rs
index 668760a..e043630 100644
--- a/quire-server/src/ci/mod.rs
+++ b/quire-server/src/ci/mod.rs
@@ -153,57 +153,87 @@ pub fn trigger(quire: &crate::Quire, event: &PushEvent) {
                     trace_id: trace_id.to_string(),
                 });
 
-        sentry::with_scope(
-            |scope| {
-                scope.set_context(
-                    "trace",
-                    sentry::protocol::Context::Trace(Box::new(sentry::protocol::TraceContext {
-                        trace_id,
-                        span_id,
-                        op: Some("quire.ci.run".into()),
-                        ..Default::default()
-                    })),
-                );
-            },
-            || {
-                let transport = Transport::for_new_run(config.ci.transport, config.port);
-                if let Err(e) = trigger_ref(
-                    &repo,
-                    &db_path,
-                    event.pushed_at,
-                    push_ref,
-                    &config.secrets,
-                    config.ci.executor,
-                    &transport,
-                    sentry_handoff.as_ref(),
-                ) {
-                    // QuireCiExit means quire-ci itself ran and reported a
-                    // user-pipeline failure (bad ci.fnl, failing job). That
-                    // shows up in the UI via the run state and CRI log —
-                    // log it at info so it doesn't trigger a Sentry event.
-                    // Everything else (db, git, spawn, materialize) is
-                    // operational and stays at error.
-                    if matches!(e, error::Error::QuireCiExit { .. }) {
-                        tracing::info!(
-                            repo = %event.repo,
-                            sha = %push_ref.new_sha, // cov-excl-line
-                            error = %e,
-                            "ci run finished with non-zero exit",
-                        );
-                    } else {
-                        tracing::error!(
-                            repo = %event.repo,
-                            sha = %push_ref.new_sha, // cov-excl-line
-                            error = &e as &(dyn std::error::Error + 'static),
-                            "CI trigger failed",
-                        );
-                    }
-                }
-            },
+        run_ref(
+            &repo,
+            &db_path,
+            &event.repo,
+            event.pushed_at,
+            push_ref,
+            &config.secrets,
+            config.ci.executor,
+            config.ci.transport,
+            config.port,
+            sentry_handoff.as_ref(),
+            trace_id,
+            span_id,
         );
     }
 }
 
+/// Set up Sentry trace scope and run CI for a single ref.
+///
+/// Wraps `trigger_ref` with Sentry scope setup and error logging.
+/// `QuireCiExit` is logged at info (user-pipeline failure, visible in the
+/// UI via run state); everything else is logged at error (operational).
+#[allow(clippy::too_many_arguments)]
+fn run_ref(
+    repo: &Repo,
+    db_path: &Path,
+    event_repo: &str,
+    pushed_at: jiff::Timestamp,
+    push_ref: &PushRef,
+    secrets: &HashMap<String, quire_core::secret::SecretString>,
+    executor: Executor,
+    transport_mode: TransportMode,
+    port: u16,
+    sentry: Option<&quire_core::ci::dispatch::SentryHandoff>,
+    trace_id: sentry::protocol::TraceId,
+    span_id: sentry::protocol::SpanId,
+) {
+    sentry::with_scope(
+        |scope| {
+            scope.set_context(
+                "trace",
+                sentry::protocol::Context::Trace(Box::new(sentry::protocol::TraceContext {
+                    trace_id,
+                    span_id,
+                    op: Some("quire.ci.run".into()),
+                    ..Default::default()
+                })),
+            );
+        },
+        || {
+            let transport = Transport::for_new_run(transport_mode, port);
+            if let Err(e) = trigger_ref(
+                repo,
+                db_path,
+                pushed_at,
+                push_ref,
+                secrets,
+                executor,
+                &transport,
+                sentry,
+            ) {
+                if matches!(e, error::Error::QuireCiExit { .. }) {
+                    tracing::info!(
+                        repo = %event_repo,
+                        sha = %push_ref.new_sha, // cov-excl-line
+                        error = %e,
+                        "ci run finished with non-zero exit",
+                    );
+                } else {
+                    tracing::error!(
+                        repo = %event_repo,
+                        sha = %push_ref.new_sha, // cov-excl-line
+                        error = &e as &(dyn std::error::Error + 'static),
+                        "CI trigger failed",
+                    );
+                }
+            }
+        },
+    );
+}
+
 /// Create and run CI for a single updated ref.
 #[allow(clippy::too_many_arguments)]
 fn trigger_ref(