a73x

542bae49

Wire commit_link::scan_and_link into the sync pipeline

alex emery   2026-04-12 07:03

Called after reconcile_refs so the dedup cache reflects merged remote
state, and before collect_push_refs so new link events ride out in
the same sync. End-to-end test: Alice writes a commit with an
Issue: trailer, sync emits+pushes, Bob fetches and materializes the
linked commit on the issue.

diff --git a/src/sync.rs b/src/sync.rs
index bf2cbe5..550e156 100644
--- a/src/sync.rs
+++ b/src/sync.rs
@@ -364,6 +364,14 @@ pub fn sync(repo: &Repository, remote_name: &str) -> Result<(), Error> {
    reconcile_refs(&repo, "issues", &author, &sk)?;
    reconcile_refs(&repo, "patches", &author, &sk)?;

    // Step 2.5: Scan local branches for Issue: trailers and emit link events.
    // Never breaks sync — scan_and_link absorbs per-commit/per-issue errors.
    match crate::commit_link::scan_and_link(&repo, &author, &sk) {
        Ok(n) if n > 0 => println!("Linked {} commit(s) to issues.", n),
        Ok(_) => {}
        Err(e) => eprintln!("warning: commit link scan failed: {}", e),
    }

    // Step 3: Push collab refs individually
    println!("Pushing to '{}'...", remote_name);
    let refs_to_push = collect_push_refs(&repo)?;
diff --git a/tests/sync_test.rs b/tests/sync_test.rs
index 96bca94..afd9e63 100644
--- a/tests/sync_test.rs
+++ b/tests/sync_test.rs
@@ -1249,3 +1249,27 @@ fn commit_link_scan_emits_event_for_matching_trailer() {
    assert_eq!(issue.linked_commits.len(), 1);
    assert_eq!(issue.linked_commits[0].commit, commit_oid.to_string());
}

#[test]
fn sync_entry_point_emits_commit_link_events_and_pushes_them() {
    let cluster = TestCluster::new();
    let alice_repo = cluster.alice_repo();

    // Alice opens an issue and syncs it up so Bob will see it too.
    let (_issue_ref, issue_id) = open_issue(&alice_repo, &alice(), "bug");
    sync::sync(&alice_repo, "origin").unwrap();

    // Alice makes a real commit with an Issue: trailer.
    let message = format!("Fix the thing\n\nIssue: {}", &issue_id[..8]);
    make_commit_with_message(&cluster, &alice_repo, &message);

    // Running sync should scan, emit the link, and push it.
    sync::sync(&alice_repo, "origin").unwrap();

    // Bob fetches and should see the link in the materialized issue.
    let bob_repo = cluster.bob_repo();
    sync::sync(&bob_repo, "origin").unwrap();
    let bob_issue_ref = format!("refs/collab/issues/{}", issue_id);
    let bob_issue = IssueState::from_ref_uncached(&bob_repo, &bob_issue_ref, &issue_id).unwrap();
    assert_eq!(bob_issue.linked_commits.len(), 1);
}