feat(dirty-content-fingerprint): xcecli shows fingerprint in --version

Adds DirtyFingerprint var and composeVersionDisplay() helper to
xcecli/cmd/main.go, a logical duplicate of apiserver's just-approved
implementation (task 4.4, same anchored strings.TrimSuffix strip-and-
append rule). Applied at the sole consumption point: the version string
fed into router.Execute(cm, version), which sets Cobra's rootCmd.Version.
router.go is untouched -- xcecli has no startup log to protect, already
established out of scope by the original build-time-versioning feature.

New main_test.go covers the same 6 cases as apiserver's tests. Verified
independently by review (including a second, independent mutation test)
with real builds across all 3 required scenarios and a full xcecli module
test suite run showing no regressions.

This completes all Go binary work (tasks 4.1-4.5) for this spec.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
Rongsong Shen 2026-08-21 08:21:18 +00:00
parent a4c1b5adee
commit d65d18ad5f
No known key found for this signature in database
GPG key ID: 5BCDAAE0123E9FE2
3 changed files with 104 additions and 7 deletions

View file

@ -40,7 +40,7 @@
- _Boundary: worker/main.c_
- _Depends: 3.1_
- [ ] 4. Core: Go binary --version/-version fingerprint display
- [x] 4. Core: Go binary --version/-version fingerprint display
- [x] 4.1 go_build injects the fingerprint via ldflags
- `go_build` reads `XCE_DIRTY_FINGERPRINT` (empty-safe) and appends `-X main.DirtyFingerprint=...` to the existing `-ldflags` construction; falls back to plain empty string (deliberately NOT `"unknown"`, unlike `GitCommit`/`BuildTime`), matching `dirty_fingerprint`'s convention everywhere else in this feature; the existing `GitCommit`/`BuildTime` `unknown`-fallback logic is completely untouched
- Observable confirmed live (independently re-verified by review, real scratch Go builds traced via `bash -x`): fingerprint unset -> `-X main.DirtyFingerprint=` empty, binary confirms empty (not fabricated); fingerprint set -> flag carries the exact value; all three vars unset -> `GitCommit`/`BuildTime` still fall back to `unknown`, `DirtyFingerprint` stays empty, the two fallback conventions coexist without interference
@ -70,9 +70,9 @@
- _Boundary: apiserver/cmd/main.go_
- _Depends: 4.1_
- [ ] 4.5 (P) xcecli: fingerprint in --version
- `DirtyFingerprint` var in `main.go`; the version string passed into `router.Execute(cm, version)` (which sets `rootCmd.Version`) applies the same strip-and-append rule
- Observable confirmed live: on a dirty build, `xcecli --version` shows `<hash>-<fingerprint>` and exits 0; a clean build shows the commit id alone, unchanged from the original feature; a dirty build where fingerprint computation failed shows `<hash>-dirty`, unchanged from the original feature
- [x] 4.5 (P) xcecli: fingerprint in --version
- `DirtyFingerprint` var + `composeVersionDisplay()` helper, a verbatim logical duplicate of apiserver's just-approved implementation (task 4.4); applied at the sole consumption point (the version string fed into `router.Execute(cm, version)`); `router.go` confirmed untouched (independently re-verified by the parent controller after the review, not just the reviewer, given a mid-review incident where the reviewer's own tooling briefly discarded the uncommitted diff before catching and byte-for-byte restoring it)
- Observable confirmed live (independently re-verified by review, real builds across all 3 scenarios + full xcecli module test suite): `--version`/`-v` shows `<hash>-<fingerprint>` on dirty+fingerprint, `<hash>` alone on clean, `<hash>-dirty` unchanged on dirty+degraded-fingerprint; all exit 0; no regressions in any other xcecli package
- _Requirements: 1.1, 1.2, 1.3, 1.4, 2.1, 4.1_
- _Boundary: xcecli/cmd/main.go_
- _Depends: 4.1_

View file

@ -44,11 +44,42 @@ import (
// string, matching this feature's unknown-fallback requirement (see
// xce_version_field() in src/lib/utils.c for the equivalent C-side
// convention).
//
// DirtyFingerprint is injected the same way (`-X main.DirtyFingerprint=...`,
// see src/tools/go_build task 4.1) but its default is a deliberately EMPTY
// string, not "unknown" -- matching dirty_fingerprint's convention
// everywhere else in the dirty-content-fingerprint feature (empty means
// "no fingerprint available", distinct from GitCommit/BuildTime's
// "unknown" sentinel for "not injected at all").
var (
GitCommit = "unknown"
BuildTime = "unknown"
GitCommit = "unknown"
BuildTime = "unknown"
DirtyFingerprint = ""
)
// composeVersionDisplay applies the dirty-content-fingerprint feature's
// strip-and-append rule to gitCommit: if dirtyFingerprint is non-empty, a
// trailing "-dirty" suffix on gitCommit is stripped (an anchored suffix
// check via strings.TrimSuffix, not a blind substring replace) and
// "-<dirtyFingerprint>" is appended in its place; otherwise gitCommit is
// returned exactly as-is (already correctly showing "-dirty" or not, per
// the original build-time-versioning feature). Mirrors
// xce_compose_version_ex() in src/lib/utils.c (task 3.1) and apiserver's
// own composeVersionDisplay (task 4.4), the equivalent implementations
// already approved for the other version-displaying components.
//
// xcecli has no startup log to protect (already established as out of
// scope by the original build-time-versioning feature, see that feature's
// own task 4.5 commit fb09afe), so this result feeds the ONLY consumption
// point below: the version string passed into router.Execute(cm, version),
// which sets rootCmd.Version for Cobra's native --version/-v handling.
func composeVersionDisplay(gitCommit, dirtyFingerprint string) string {
if dirtyFingerprint == "" {
return gitCommit
}
return strings.TrimSuffix(gitCommit, "-dirty") + "-" + dirtyFingerprint
}
func main() {
// init logger
@ -72,7 +103,7 @@ func main() {
}
// execute the command
version := fmt.Sprintf("%s built %s", GitCommit, BuildTime)
version := fmt.Sprintf("%s built %s", composeVersionDisplay(GitCommit, DirtyFingerprint), BuildTime)
if err := cmd.Execute(configManager, version); err != nil {
fmt.Println(strings.ToLower(err.Error()))
os.Exit(1)

View file

@ -0,0 +1,66 @@
package main
import "testing"
// dirty-content-fingerprint task 4.5: composeVersionDisplay implements the
// --version-only strip-and-append rule mirroring xce_compose_version_ex()
// in src/lib/utils.c (task 3.1) and apiserver's own composeVersionDisplay
// (task 4.4). xcecli has no startup log to protect (already established as
// out of scope by the original build-time-versioning feature), so the only
// consumption point is the version string passed into router.Execute(cm,
// version), which Cobra uses to populate rootCmd.Version for --version/-v.
func TestComposeVersionDisplay(t *testing.T) {
tests := []struct {
name string
gitCommit string
dirtyFingerprint string
want string
}{
{
name: "dirty commit with fingerprint strips -dirty and appends fingerprint",
gitCommit: "abc1234-dirty",
dirtyFingerprint: "deadbeef",
want: "abc1234-deadbeef",
},
{
name: "clean commit with no fingerprint is unchanged",
gitCommit: "abc1234",
dirtyFingerprint: "",
want: "abc1234",
},
{
name: "dirty commit with no fingerprint (degraded) is unchanged, -dirty preserved",
gitCommit: "abc1234-dirty",
dirtyFingerprint: "",
want: "abc1234-dirty",
},
{
name: "unknown commit with no fingerprint is unchanged",
gitCommit: "unknown",
dirtyFingerprint: "",
want: "unknown",
},
{
name: "clean commit with a fingerprint still appends (nothing to strip)",
gitCommit: "abc1234",
dirtyFingerprint: "cafef00d",
want: "abc1234-cafef00d",
},
{
name: "suffix check is anchored, not a blind substring removal",
gitCommit: "abc1234-dirty-not-at-end-dirty",
dirtyFingerprint: "cafef00d",
want: "abc1234-dirty-not-at-end-cafef00d",
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got := composeVersionDisplay(tt.gitCommit, tt.dirtyFingerprint)
if got != tt.want {
t.Errorf("composeVersionDisplay(%q, %q) = %q, want %q",
tt.gitCommit, tt.dirtyFingerprint, got, tt.want)
}
})
}
}