fix(version): produce shorter user agent for tagged release builds
when building from a version-tagged commit with a clean tree, omit the redundant git commit hash from the libp2p user agent string, saving bytes in HTTP requests and libp2p identify. `ipfs version --commit` still reports the full commit hash. before (tagged release): kubo/0.37.0/6898472 after (tagged release): kubo/0.37.0 non-tagged and dirty builds are unaffected.
Marcin Rataj committed
Feb 19, 2026 at 01:29 UTC
1e5e6e35cf2b44acb9058b950f0e6f92c4b03982
5 files changed
+111
-13
cmd/ipfs/Rules.mk
+1
-1
@@ -12,7 +12,7 @@ PATH := $(realpath $(d)):$(PATH)
12
# DEPS_OO_$(d) += merkledag/pb/merkledag.pb.go namesys/pb/namesys.pb.go
13
# DEPS_OO_$(d) += pin/internal/pb/header.pb.go unixfs/pb/unixfs.pb.go
14
15
-$(d)_flags =-ldflags="-X "github.com/ipfs/kubo".CurrentCommit=$(git-hash)"
15
+$(d)_flags =-ldflags="-X "github.com/ipfs/kubo".CurrentCommit=$(git-hash) -X "github.com/ipfs/kubo".taggedRelease=$(git-tag)"
16
17
$(IPFS_BIN_$(d)): GOFLAGS += $(cmd/ipfs_flags)
18
mk/git.mk
+8
@@ -2,3 +2,11 @@
2
# If that fails (e.g., we're building a docker image and have an empty objects
3
# directory), assume the source isn't dirty and build anyways.
4
git-hash:=$(shell git describe --always --match=NeVeRmAtCh --dirty 2>/dev/null || git rev-parse --short HEAD 2>/dev/null)
5
+
6
+# Detect if HEAD is a clean, tagged release. Used to omit redundant commit
7
+# hash from the libp2p user agent (the version number suffices).
8
+ifeq ($(findstring dirty,$(git-hash)),)
9
+ git-tag:=$(shell git tag --points-at HEAD 2>/dev/null | grep '^v' | head -1)
10
+else
11
+ git-tag:=
12
+endif
test/sharness/t0026-id.sh
+5
-5
@@ -16,12 +16,12 @@ test_id_compute_agent() {
16
else
17
AGENT_COMMIT="${AGENT_COMMIT##$AGENT_VERSION-}"
18
fi
19
- AGENT_VERSION="kubo/$AGENT_VERSION/$AGENT_COMMIT"
19
+ AGENT_VERSION="kubo/$AGENT_VERSION"
20
+ if test -n "$AGENT_COMMIT"; then
21
+ AGENT_VERSION="$AGENT_VERSION/$AGENT_COMMIT"
22
+ fi
23
if test -n "$AGENT_SUFFIX"; then
21
- if test -n "$AGENT_COMMIT"; then
22
- AGENT_VERSION="$AGENT_VERSION/"
23
- fi
24
- AGENT_VERSION="$AGENT_VERSION$AGENT_SUFFIX"
24
+ AGENT_VERSION="$AGENT_VERSION/$AGENT_SUFFIX"
25
fi
26
echo "$AGENT_VERSION"
27
}
version.go
+18
-7
@@ -10,6 +10,12 @@ import (
10
// CurrentCommit is the current git commit, this is set as a ldflag in the Makefile.
11
var CurrentCommit string
12
13
+// taggedRelease is set via ldflag when building from a version-tagged commit
14
+// with a clean tree. When set, the commit hash is omitted from the libp2p
15
+// identify agent version and the HTTP user agent, since the version number
16
+// already identifies the exact source.
17
+var taggedRelease string
18
+
19
// CurrentVersionNumber is the current application's version literal.
20
const CurrentVersionNumber = "0.40.0-rc1"
21
@@ -19,15 +25,20 @@ const ApiVersion = "/kubo/" + CurrentVersionNumber + "/" //nolint
25
const RepoVersion = 18
26
27
// GetUserAgentVersion is the libp2p user agent used by go-ipfs.
22
-//
23
-// Note: This will end in `/` when no commit is available. This is expected.
28
func GetUserAgentVersion() string {
25
- userAgent := "kubo/" + CurrentVersionNumber + "/" + CurrentCommit
29
+ // For tagged release builds with a clean tree, the commit hash is
30
+ // redundant since the version number identifies the exact source.
31
+ commit := CurrentCommit
32
+ if taggedRelease != "" {
33
+ commit = ""
34
+ }
35
+
36
+ userAgent := "kubo/" + CurrentVersionNumber
37
+ if commit != "" {
38
+ userAgent += "/" + commit
39
+ }
40
if userAgentSuffix != "" {
27
- if CurrentCommit != "" {
28
- userAgent += "/"
29
- }
30
- userAgent += userAgentSuffix
41
+ userAgent += "/" + userAgentSuffix
42
}
43
return cmdutils.CleanAndTrim(userAgent)
44
}
version_test.go
new
+79
@@ -0,0 +1,79 @@
1
+package ipfs
2
+
3
+import (
4
+ "testing"
5
+
6
+ "github.com/stretchr/testify/assert"
7
+)
8
+
9
+// TestGetUserAgentVersion verifies the user agent string used in libp2p
10
+// identify and HTTP requests. Tagged release builds (where the commit matches
11
+// the tag) skip the commit hash from the agent version, since the version
12
+// number already identifies the exact source.
13
+func TestGetUserAgentVersion(t *testing.T) {
14
+ origCommit := CurrentCommit
15
+ origTagged := taggedRelease
16
+ origSuffix := userAgentSuffix
17
+ t.Cleanup(func() {
18
+ CurrentCommit = origCommit
19
+ taggedRelease = origTagged
20
+ userAgentSuffix = origSuffix
21
+ })
22
+
23
+ tests := []struct {
24
+ name string
25
+ commit string
26
+ tagged string
27
+ suffix string
28
+ expected string
29
+ }{
30
+ // dev builds without ldflags
31
+ {
32
+ name: "no commit, no suffix",
33
+ expected: "kubo/" + CurrentVersionNumber,
34
+ },
35
+ // dev builds with commit set via ldflags
36
+ {
37
+ name: "with commit",
38
+ commit: "abc1234",
39
+ expected: "kubo/" + CurrentVersionNumber + "/abc1234",
40
+ },
41
+ {
42
+ name: "with suffix, no commit",
43
+ suffix: "test-suffix",
44
+ expected: "kubo/" + CurrentVersionNumber + "/test-suffix",
45
+ },
46
+ {
47
+ name: "with commit and suffix",
48
+ commit: "abc1234",
49
+ suffix: "test-suffix",
50
+ expected: "kubo/" + CurrentVersionNumber + "/abc1234/test-suffix",
51
+ },
52
+ // tagged release builds: commit is redundant because the version
53
+ // number already maps to an exact git tag, so it is omitted to
54
+ // save bytes in identify and HTTP user-agent headers.
55
+ {
56
+ name: "tagged release ignores commit",
57
+ commit: "abc1234",
58
+ tagged: "1",
59
+ expected: "kubo/" + CurrentVersionNumber,
60
+ },
61
+ {
62
+ name: "tagged release with suffix ignores commit",
63
+ commit: "abc1234",
64
+ tagged: "1",
65
+ suffix: "test-suffix",
66
+ expected: "kubo/" + CurrentVersionNumber + "/test-suffix",
67
+ },
68
+ }
69
+
70
+ for _, tt := range tests {
71
+ t.Run(tt.name, func(t *testing.T) {
72
+ CurrentCommit = tt.commit
73
+ taggedRelease = tt.tagged
74
+ SetUserAgentSuffix(tt.suffix)
75
+
76
+ assert.Equal(t, tt.expected, GetUserAgentVersion())
77
+ })
78
+ }
79
+}