# Merge pull request \#69 from entireio/user-agent

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

pjbgf·1mo ago·7 files·+86 added/-9 removed

useragent: identify git-sync in outbound User-Agent

## Changes

7

- cmd/git-sync

- Mmain.go+3

- internal

- gitproto

- Mcapability.go+2/-1

- Mcapability_test.go+3/-2

- Msmarthttp.go+4/-4

- strategy/bootstrap

- Mbootstrap.go+2/-2

- useragent

- Auseragent.go+27

- Auseragent_test.go+45

```
6 unmodified lines

7
8
9
10
11
12
13
14
15
16
17
18
19

6 unmodified lines

"os"
	"strings"

"entire.io/entire/git-sync/cmd/git-sync/internal/versioninfo"
	"entire.io/entire/git-sync/internal/useragent"
	"github.com/spf13/cobra"
)

func main() {
	useragent.Version = versioninfo.Version
	err := run(context.Background(), os.Args[1:])
	if err == nil {
		return
```

Mcmd/git-sync/main.go+3

```
5 unmodified lines

6
7
8
9
10
11
12
54 unmodified lines

67
68
69
69
70
71
72
73

5 unmodified lines

"sort"
	"strings"

"entire.io/entire/git-sync/internal/useragent"
	"github.com/go-git/go-git/v6/plumbing/protocol/capability"
)

54 unmodified lines

func (c *V2Capabilities) RequestCapabilities() []string {
	var caps []string
	if agent := c.Value("agent"); agent != "" {
		caps = append(caps, "agent="+capability.DefaultAgent())
		caps = append(caps, "agent="+useragent.GoGit())
	}
	return caps
}
```

Minternal/gitproto/capability.go+2/-1

```
2 unmodified lines

3
4
5
6
7
8
9
159 unmodified lines

169
170
171
171
172
172
173
174
175
176

2 unmodified lines

import (
	"testing"

"entire.io/entire/git-sync/internal/useragent"
	"github.com/go-git/go-git/v6/plumbing/protocol/capability"
)

159 unmodified lines

if len(got) != 1 {
		t.Fatalf("RequestCapabilities() returned %d items, want 1", len(got))
	}
	if got[0] != "agent="+capability.DefaultAgent() {
		t.Errorf("RequestCapabilities()[0] = %q, want %q", got[0], "agent="+capability.DefaultAgent())
	}
	if got[0] != "agent="+useragent.GoGit() {
		t.Errorf("RequestCapabilities()[0] = %q, want %q", got[0], "agent="+useragent.GoGit())
	}

// Without agent, RequestCapabilities should return empty.
```

Minternal/gitproto/capability_test.go+3/-2

```
13 unmodified lines

14
15
16
17
17
18
19
20
507 unmodified lines

528
529
530
531
531
532
533
534
128 unmodified lines

663
664
665
666
666
667
668
669
153 unmodified lines

823
824
825
826
826
827
828
829

13 unmodified lines

"os"
	"strings"

"github.com/go-git/go-git/v6/plumbing/protocol/capability"
	"entire.io/entire/git-sync/internal/useragent"
	transporthttp "github.com/go-git/go-git/v6/plumbing/transport/http"
)

507 unmodified lines

}
	req.Header.Set("Content-Type", fmt.Sprintf("application/x-%s-request", service))
	req.Header.Set("Accept", fmt.Sprintf("application/x-%s-result", service))
	req.Header.Set("User-Agent", capability.DefaultAgent())
	req.Header.Set("User-Agent", useragent.GoGit())
	req.Header.Set(StatsPhaseHeader, phase)
	if v2 {
		req.Header.Set("Git-Protocol", GitProtocolV2)
128 unmodified lines

}
	req.Header.Set("Content-Type", fmt.Sprintf("application/x-%s-request", service))
	req.Header.Set("Accept", fmt.Sprintf("application/x-%s-result", service))
	req.Header.Set("User-Agent", capability.DefaultAgent())
	req.Header.Set("User-Agent", useragent.GoGit())
	req.Header.Set(StatsPhaseHeader, service+" auth-probe")
	res, err := c.HTTP.Do(req)
	if err != nil {
```

Minternal/gitproto/smarthttp.go+4/-4

```
17 unmodified lines

18
19
20
21
21
22
23
24
25
26
27
28
1309 unmodified lines

1338
1339
1340
1341
1341
1342
1343
1344

17 unmodified lines

git "github.com/go-git/go-git/v6"
	"github.com/go-git/go-git/v6/plumbing"
	"github.com/go-git/go-git/v6/plumbing/protocol/capability"

"entire.io/entire/git-sync/internal/convert"
	"entire.io/entire/git-sync/internal/gitproto"
	"entire.io/entire/git-sync/internal/planner"
	"entire.io/entire/git-sync/internal/useragent"
)

const (
1309 unmodified lines

}
	req.Header.Set("Accept", "application/vnd.github+json")
	req.Header.Set("X-Github-Api-Version", "2022-11-28")
	req.Header.Set("User-Agent", capability.DefaultAgent())
	req.Header.Set("User-Agent", useragent.Plain())
	req.Header.Set(gitproto.StatsPhaseHeader, "github repo metadata")
	resp, err := httpConn.HTTP.Do(req)
	if err != nil {
```

Minternal/strategy/bootstrap/bootstrap.go+2/-2

```
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27

// Package useragent builds the User-Agent strings git-sync advertises to
// remote services. Two flavours: GoGit for git wire-protocol traffic
// (HTTP smart-protocol requests and the protocol-level "agent="
// capability), and Plain for non-git HTTP requests such as provider
// metadata APIs.
package useragent

import "github.com/go-git/go-git/v6/plumbing/protocol/capability"

// Version is the git-sync version advertised in User-Agent strings.
// CLI builds set this from versioninfo.Version; SDK consumers may
// overwrite it before issuing any requests if they want to identify a
// different version.
var Version = "dev"

// GoGit returns the User-Agent for git wire-protocol traffic. Format:
// "git-sync/<version> go-git/<go-git-version>". The go-git suffix is
// preserved because servers and operators commonly key off it.
func GoGit() string {
	return "git-sync/" + Version + " " + capability.DefaultAgent()
}

// Plain returns the User-Agent for non-git HTTP requests (e.g. provider
// REST APIs). Format: "git-sync/<version>".
func Plain() string {
	return "git-sync/" + Version
}
```

Ainternal/useragent/useragent.go+27

```
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45

package useragent

import (
	"strings"
	"testing"

"github.com/go-git/go-git/v6/plumbing/protocol/capability"
)

func TestGoGit(t *testing.T) {
	t.Parallel()

got := GoGit()
	wantPrefix := "git-sync/" + Version + " "
	if !strings.HasPrefix(got, wantPrefix) {
		t.Errorf("GoGit() = %q, want prefix %q", got, wantPrefix)
	}
	if !strings.Contains(got, capability.DefaultAgent()) {
		t.Errorf("GoGit() = %q, want it to contain %q", got, capability.DefaultAgent())
	}
}

func TestPlain(t *testing.T) {
	t.Parallel()

got := Plain()
	want := "git-sync/" + Version
	if got != want {
		t.Errorf("Plain() = %q, want %q", got, want)
	}
}

func TestVersionOverride(t *testing.T) {
	// Not parallel — mutates package-level Version.
	orig := Version
	t.Cleanup(func() { Version = orig })

Version = "1.2.3"
	if got, want := Plain(), "git-sync/1.2.3"; got != want {
		t.Errorf("Plain() with overridden Version = %q, want %q", got, want)
	}
	if got, want := GoGit(), "git-sync/1.2.3 "+capability.DefaultAgent(); got != want {
		t.Errorf("GoGit() with overridden Version = %q, want %q", got, want)
	}
}
}
```

Ainternal/useragent/useragent_test.go+45
