# Add read-only source probe command

`acaab9c`→[main](/content/gh/entireio/git-sync/commits/main/index.html)·

## Sessions

6b50977affcfView transcript

## Changes

4

- MREADME.md+10
- internal/syncer
  - Mintegration_test.go+41
  - Mprotocol_v2.go+61/-6
  - Msyncer.go+99

````
79 unmodified lines
````

Probe a source remote without pushing anything:

```bash
go run ./cmd/git-sync probe \
  --stats \
  --tags \
  --protocol auto \
  <source-url>
```

Dry run:

```bash
````

MREADME.md+10

```
222 unmodified lines
```

```go
func TestProbe_IntegrationProtocolV2Source(t *testing.T) {
    sourceRepo, sourceFS := newSourceRepo(t)
    makeCommits(t, sourceRepo, sourceFS, 2)
    head, err := sourceRepo.Reference(plumbing.NewBranchReferenceName(testBranch), true)
    if err != nil {
        t.Fatalf("source head: %v", err)
    }
    if err := sourceRepo.Storer.SetReference(plumbing.NewHashReference(plumbing.NewTagReferenceName("v1"), head.Hash())); err != nil {
        t.Fatalf("set source tag: %v", err)
    }

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

result, err := Probe(context.Background(), Config{
        Source:       Endpoint{URL: sourceServer.RepoURL()},
        ProtocolMode: protocolModeV2,
        IncludeTags:  true,
        ShowStats:    true,
    })
    if err != nil {
        t.Fatalf("probe failed: %v", err)
    }

if result.Protocol != protocolModeV2 {
        t.Fatalf("expected protocol v2, got %s", result.Protocol)
    }
    if len(result.RefPrefixes) != 2 || result.RefPrefixes[0] != "refs/heads/" || result.RefPrefixes[1] != "refs/tags/" {
        t.Fatalf("unexpected ref prefixes: %#v", result.RefPrefixes)
    }
    if len(result.Capabilities) == 0 {
        t.Fatalf("expected capabilities")
    }
    if len(result.Refs) < 2 {
        t.Fatalf("expected refs, got %#v", result.Refs)
    }
    if !result.Stats.Enabled || len(result.Stats.Items) == 0 {
        t.Fatalf("expected stats")
    }
}
```

```go
func TestRun_IntegrationTagsPruneAndForce(t *testing.T) {
    sourceRepo, sourceFS := newSourceRepo(t)
    makeCommits(t, sourceRepo, sourceFS, 2)
}
```

Minternal/syncer/integration_test.go+41
```
7 unmodified lines
```

```go
func decodeV2CapabilityAdvertisement(r io.Reader) (*v2CapabilityAdvertisement, error) {
    reader := newPacketReader(r)

kind, payload, err := reader.ReadPacket()
    if err != nil {
        return nil, err
    }
    if kind != packetTypeData || string(payload) != "version 2\n" {
        return nil, fmt.Errorf("unexpected protocol advertisement %q", payload)
    }
    //... more code ...
}
```

Minternal/syncer/protocol_v2.go+61/-6
```
96 unmodified lines
```

```go
type ProbeResult struct {
    SourceURL     string
    RequestedMode string
    Protocol      string
    RefPrefixes   []string
    Capabilities  []string
    Refs          []RefInfo
    Stats         Stats
}
```

```go
func Probe(ctx context.Context, cfg Config) (ProbeResult, error) {
    //... code logic ...
}
```

Minternal/syncer/syncer.go+99
