Simplify mirror: push all updated refs, drop branch filter and tag creation
Per review: just mirror the pushed ref as-is. Removes the `github.branch`
config key and all tag-creation logic from the mirror path.

https://claude.ai/code/session_01MtUMXi7Z3GCDWQFY8puWpu
change
commit ceea8347e9664011f266a7c4bedeb5216f1e5a3c
author Claude <noreply@anthropic.com>
date
parent 635fe320
diff --git a/quire-core/src/ci/repo_config.rs b/quire-core/src/ci/repo_config.rs
index a1899c9..bba9f78 100644
--- a/quire-core/src/ci/repo_config.rs
+++ b/quire-core/src/ci/repo_config.rs
@@ -11,26 +11,12 @@ pub struct RepoConfig {
 }
 
 /// Per-repo GitHub configuration.
-#[derive(serde::Deserialize, Debug, Clone)]
+#[derive(serde::Deserialize, Debug, Default, Clone)]
 #[serde(default, rename_all = "kebab-case")]
 pub struct GithubRepoConfig {
-    /// Remote URL to mirror to on every push to `:branch`.
+    /// Remote URL to mirror every pushed ref to.
     /// E.g. `"https://github.com/user/repo.git"`.
-    /// When set, quire injects a `quire/mirror` built-in job into
-    /// every pipeline for this repo.
     pub mirror: Option<String>,
-    /// Ref that triggers the mirror (default: `refs/heads/main`).
-    /// Pushes to any other ref are ignored by the mirror job.
-    pub branch: String,
-}
-
-impl Default for GithubRepoConfig {
-    fn default() -> Self {
-        Self {
-            mirror: None,
-            branch: "refs/heads/main".to_string(),
-        }
-    }
 }
 
 #[cfg(test)]
@@ -48,7 +34,6 @@ mod tests {
     fn defaults_when_empty_table() {
         let cfg = load("{}");
         assert!(cfg.github.mirror.is_none());
-        assert_eq!(cfg.github.branch, "refs/heads/main");
     }
 
     #[test]
@@ -59,18 +44,4 @@ mod tests {
             Some("https://github.com/user/repo.git")
         );
     }
-
-    #[test]
-    fn parses_custom_branch() {
-        let cfg = load(
-            r#"{:github {:mirror "https://github.com/u/r.git" :branch "refs/heads/release"}}"#,
-        );
-        assert_eq!(cfg.github.branch, "refs/heads/release");
-    }
-
-    #[test]
-    fn default_branch_when_only_mirror_set() {
-        let cfg = load(r#"{:github {:mirror "https://github.com/u/r.git"}}"#);
-        assert_eq!(cfg.github.branch, "refs/heads/main");
-    }
 }
diff --git a/quire-server/src/mirror.rs b/quire-server/src/mirror.rs
index d8ccd20..b19943e 100644
--- a/quire-server/src/mirror.rs
+++ b/quire-server/src/mirror.rs
@@ -1,4 +1,4 @@
-//! Server-side mirror: push a branch (and a version tag) to a remote on every push.
+//! Server-side mirror: push updated refs to a remote on every push.
 //!
 //! Triggered from the push event handler, independent of CI.
 
@@ -9,9 +9,8 @@ use crate::quire::Quire;
 /// Mirror updated refs to a configured remote.
 ///
 /// Reads `github.mirror-token` from global config for auth. For each updated
-/// ref, reads `.quire/config.fnl` at the new SHA to obtain `github.mirror` (URL)
-/// and `github.branch` (the ref that triggers mirroring). Skips refs that don't
-/// match the configured branch, and repos with no mirror URL set.
+/// ref, reads `.quire/config.fnl` at the new SHA to obtain the `github.mirror`
+/// URL. Skips repos with no mirror URL configured.
 pub fn trigger(quire: &Quire, event: &PushEvent) {
     let repo = match quire.repo(&event.repo) {
         Ok(r) if r.exists() => r,
@@ -69,13 +68,8 @@ pub fn trigger(quire: &Quire, event: &PushEvent) {
             continue;
         };
 
-        if push_ref.ref_name != repo_config.github.branch {
-            continue;
-        }
-
         push_to_mirror(
             &repo,
-            &push_ref.new_sha,
             &push_ref.ref_name,
             &mirror_url,
             mirror_token.as_deref(),
@@ -85,51 +79,22 @@ pub fn trigger(quire: &Quire, event: &PushEvent) {
 
 fn push_to_mirror(
     repo: &crate::quire::Repo,
-    sha: &str,
     ref_name: &str,
     mirror_url: &str,
     token: Option<&str>,
 ) {
-    let tag = make_tag(sha);
-
-    // Create the tag locally; ignore "already exists" errors.
-    let tag_out = repo
-        .git(&["tag", &tag, sha])
-        .stdout(std::process::Stdio::null())
-        .stderr(std::process::Stdio::piped())
-        .output();
-    match tag_out {
-        Err(e) => {
-            tracing::error!(sha, tag, error = %e, "mirror: failed to run git tag");
-            return;
-        }
-        Ok(out) if !out.status.success() => {
-            let stderr = String::from_utf8_lossy(&out.stderr);
-            if !stderr.contains("already exists") {
-                tracing::error!(sha, tag, %stderr, "mirror: git tag failed");
-                return;
-            }
-        }
-        Ok(_) => {}
-    }
-
-    // Force-push the branch and push the tag.
-    // The `+` prefix in the branch refspec allows fast-forward and force pushes.
-    let refspec_branch = format!("+{ref_name}:{ref_name}");
-    let refspec_tag = format!("refs/tags/{tag}:refs/tags/{tag}");
-    let mut cmd = repo.git(&[
-        "push",
-        "--porcelain",
-        mirror_url,
-        &refspec_branch,
-        &refspec_tag,
-    ]);
+    // Force-push the ref to the mirror. The `+` prefix allows rewrites.
+    let refspec = format!("+{ref_name}:{ref_name}");
+    let mut cmd = repo.git(&["push", "--porcelain", mirror_url, &refspec]);
 
     // Pass the auth token via git config env vars so it never appears in argv.
     if let Some(token) = token {
         cmd.env("GIT_CONFIG_COUNT", "1")
             .env("GIT_CONFIG_KEY_0", "http.extraHeader")
-            .env("GIT_CONFIG_VALUE_0", format!("Authorization: Bearer {token}"));
+            .env(
+                "GIT_CONFIG_VALUE_0",
+                format!("Authorization: Bearer {token}"),
+            );
     }
 
     match cmd
@@ -138,48 +103,23 @@ fn push_to_mirror(
         .output()
     {
         Ok(out) if out.status.success() => {
-            tracing::info!(ref_name, tag, mirror_url, "mirror: push succeeded");
+            tracing::info!(ref_name, mirror_url, "mirror: push succeeded");
         }
         Ok(out) => {
             tracing::error!(
                 ref_name,
-                tag,
                 mirror_url,
                 stderr = %String::from_utf8_lossy(&out.stderr),
                 "mirror: push failed",
             );
         }
         Err(e) => {
-            tracing::error!(ref_name, mirror_url, error = %e, "mirror: failed to run git push");
+            tracing::error!(
+                ref_name,
+                mirror_url,
+                error = %e,
+                "mirror: failed to run git push",
+            );
         }
     }
 }
-
-fn make_tag(sha: &str) -> String {
-    let date = jiff::Timestamp::now().strftime("%Y-%m-%d").to_string();
-    let sha8 = &sha[..sha.len().min(8)];
-    format!("v{date}-{sha8}")
-}
-
-#[cfg(test)]
-mod tests {
-    use super::*;
-
-    #[test]
-    fn make_tag_format() {
-        let sha = "abc12345def67890";
-        let tag = make_tag(sha);
-        assert!(tag.starts_with('v'), "tag should start with 'v': {tag}");
-        // v<date>-<sha8>
-        let parts: Vec<&str> = tag.splitn(2, '-').collect();
-        assert_eq!(parts.len(), 2);
-        assert_eq!(&tag[tag.len() - 8..], "abc12345");
-    }
-
-    #[test]
-    fn make_tag_short_sha() {
-        let sha = "abc";
-        let tag = make_tag(sha);
-        assert!(tag.ends_with("abc"), "short sha should be used as-is: {tag}");
-    }
-}
diff --git a/quire-server/src/quire/mod.rs b/quire-server/src/quire/mod.rs
index 93493f7..7bc5384 100644
--- a/quire-server/src/quire/mod.rs
+++ b/quire-server/src/quire/mod.rs
@@ -43,8 +43,6 @@ pub struct GlobalConfig {
 #[serde(rename_all = "kebab-case")]
 pub struct GlobalGithubConfig {
     /// Bearer token used to authenticate push access to the mirror remote.
-    /// Exposed to the built-in `quire/mirror` job as the
-    /// `"github/mirror-token"` secret.
     #[serde(default)]
     pub mirror_token: Option<SecretString>,
 }
@@ -161,10 +159,7 @@ impl Repo {
     /// Read and parse `.quire/config.fnl` at the given commit SHA.
     ///
     /// Returns defaults if the file does not exist at that commit.
-    pub fn repo_config(
-        &self,
-        sha: &str,
-    ) -> AppResult<quire_core::ci::repo_config::RepoConfig> {
+    pub fn repo_config(&self, sha: &str) -> AppResult<quire_core::ci::repo_config::RepoConfig> {
         let output = self
             .git(&["show", &format!("{sha}:.quire/config.fnl")])
             .stdout(std::process::Stdio::piped())