Add failing tests for HEAD propagation: source/target HEAD in Result + ProbeResult · Entire

Add failing tests for HEAD propagation: source/target HEAD in Result + ProbeResult

7d1c3b8·

Soph·2mo ago·1 file·+103 added/-0 removed

issue #45: git-sync mirrors refs but never propagates the source's HEAD
symref target to the target. A repo mirrored from a default=main source
into a default=master target ends up with a dangling target HEAD; a
subsequent git clone target checks out master instead of main.

Step 1 of the implementation: pin the public contract via three
failing integration tests that drive the API shape.

The tests fail to build today (Result and ProbeResult don't have the
SourceHEAD/TargetHEAD fields yet); subsequent commits add the fields
and the capture logic.

Refs #45.

Co-Authored-By: Claude Opus 4.7 (1M context) noreply@anthropic.com

Sessions

ce76aab97a1fView transcript

Changes

1

1849 unmodified lines

... // ProbeResult.SourceHEAD and TargetHEAD let `git-sync probe` preview the  
// default-branch mismatch without actually mutating the target.  
func TestProbe_IntegrationSurfacesBothHEADs(t *testing.T) {  
    sourceRepo, sourceFS := newSourceRepo(t)  
    makeCommits(t, sourceRepo, sourceFS, 1)

targetRepo, err := git.Init(memory.NewStorage(), nil, git.WithDefaultBranch("refs/heads/main"))  
    if err != nil {  
        t.Fatalf("init target repo: %v", err)  
    }

sourceServer := newSmartHTTPRepoServerV2(t, sourceRepo)  
    targetServer := newSmartHTTPRepoServer(t, targetRepo)  
    defer sourceServer.Close()  
    defer targetServer.Close()

result, err := Probe(context.Background(), Config{  
        Source:       Endpoint{URL: sourceServer.RepoURL()},  
        Target:       Endpoint{URL: targetServer.RepoURL()},  
        ProtocolMode: protocolModeAuto,  
    })  
    if err != nil {  
        t.Fatalf("probe: %v", err)  
    }  
    wantSource := plumbing.NewBranchReferenceName(testBranch)  
    if result.SourceHEAD != wantSource {  
        t.Errorf("SourceHEAD = %q, want %q", result.SourceHEAD, wantSource)  
    }  
    wantTarget := plumbing.ReferenceName("refs/heads/main")  
    if result.TargetHEAD != wantTarget {  
        t.Errorf("TargetHEAD = %q, want %q", result.TargetHEAD, wantTarget)  
    }  
}

func TestFetch_IntegrationProtocolV2Source(t *testing.T) {  
    sourceRepo, sourceFS := newSourceRepo(t)  
    makeCommits(t, sourceRepo, sourceFS, 4)  
    ...
}

// Result.SourceHEAD and Result.TargetHEAD capture each side's symref HEAD  
// target, so library callers can detect a default-branch mismatch without  
// scraping the notice stream. Bootstrap into an empty target whose bare-repo  
// HEAD default differs from the source's surfaces this case.  
func TestRun_IntegrationBootstrapSurfacesHEADInResult(t *testing.T) {  
    sourceRepo, sourceFS := newSourceRepo(t)  
    makeCommits(t, sourceRepo, sourceFS, 1)

// go-git Init defaults HEAD to refs/heads/master; pin target to  
    // refs/heads/main so the symrefs diverge.  
    targetRepo, err := git.Init(memory.NewStorage(), nil, git.WithDefaultBranch("refs/heads/main"))  
    if err != nil {  
        t.Fatalf("init target repo: %v", err)  
    }

result, err := Run(context.Background(), Config{  
        Source:       Endpoint{URL: sourceServer.RepoURL()},  
        Target:       Endpoint{URL: targetServer.RepoURL()},  
        ProtocolMode: protocolModeAuto,  
    })  
    if err != nil {  
        t.Fatalf("sync: %v", err)  
    }  
    wantSourceHEAD := plumbing.NewBranchReferenceName(testBranch)  
    if result.SourceHEAD != wantSourceHEAD {  
        t.Errorf("SourceHEAD = %q, want %q", result.SourceHEAD, wantSourceHEAD)  
    }  
    wantTargetHEAD := plumbing.ReferenceName("refs/heads/main")  
    if result.TargetHEAD != wantTargetHEAD {  
        t.Errorf("TargetHEAD = %q, want %q", result.TargetHEAD, wantTargetHEAD)  
    }  
}

// When source HEAD and target HEAD match, the sync surfaces both fields  
// identically — no mismatch from the consumer's perspective.  
func TestRun_IntegrationBootstrapHEADMatch(t *testing.T) {  
    ...  
}

// --exclude-ref-prefix trims namespaces from --all-refs auto-discovery. The  
// GitHub use case is `--all-refs --exclude-ref-prefix refs/pull/`: mirror  
// branches/tags/notes but skip the fork-commit blowup from PR refs.