Skip to content

fix(ci): inject version/commit/date ldflags in make build and install#94

Merged
dipto0321 merged 1 commit into
mainfrom
fix/build/ldflags
Jul 3, 2026
Merged

fix(ci): inject version/commit/date ldflags in make build and install#94
dipto0321 merged 1 commit into
mainfrom
fix/build/ldflags

Conversation

@dipto0321

Copy link
Copy Markdown
Owner

Summary

Makefile:38's build target ran go build -trimpath -ldflags "-s -w" -o bin/nodeup ./cmd/nodeup — no -X main.version=... -X main.commit=... -X main.date=... injection, despite cmd/nodeup/main.go:17-26 declaring all three as var ... = "dev"|"none"|"unknown" precisely so they could be ldflag-injected, and despite .goreleaser.yaml:37 injecting them on every real release build.

The result: every locally-built binary (make build, go install .../cmd/nodeup, go install .../cmd/nodeup@latest) shipped with the package-level defaults. nodeup version then printed literal dev / none / unknown — defeating the install-verification flow documented in docs/installation.md#verifying ("Should print a version, git commit, build date, and Go runtime info") and undermining the bug-report triage instructions in CONTRIBUTING.md that ask reporters to paste nodeup version output. A locally-built binary was indistinguishable from any other local build, so triage couldn't tell if a bug reproed on the latest commit or on a stale checkout.

This PR fixes the regression by introducing three Makefile vars that capture the values at parse time and feeding them into a single LDFLAGS variable used by both build and install:

  • VERSION from git describe --tags --always --dirty — closest semver tag (when the repo has tags) or short SHA + -dirty if the working tree is dirty; falls back to dev when git is unavailable (snapshot tarball build).
  • COMMIT from git rev-parse --short HEAD — falls back to none.
  • DATE from date -u +%Y-%m-%dT%H:%M:%SZ — RFC3339 UTC, matches .goreleaser.yaml:37's {{.CommitDate}} shape.

Each shell call is wrapped with || echo <fallback> so a build inside a snapshot tarball or vendored copy without .git/ falls back to safe defaults rather than crashing. internal/cli/version_test.go (new, 5 tests) pins the exact output shape of nodeup version so a future refactor can't silently drop a field.

Linked issues

Closes #68

Type of change

  • fix — bug fix (PATCH bump)
  • feat — new feature (MINOR bump)
  • refactor — no behavior change
  • perf — performance improvement
  • docs — documentation only
  • test — tests only
  • chore — maintenance / dependency bump
  • ci — CI/CD only
  • build — build system only
  • Breaking change (MAJOR bump) — explain below

Checklist

  • Title follows Conventional Commits (feat(scope): subject)
  • I ran make ci locally and it passes (Go-side tidy/fmt/vet/lint/test all green; the new version_test.go brings internal/cli coverage from 29.2% → 31.1%)
  • I added or updated tests for the change (internal/cli/version_test.go — 5 new tests: TestVersionCmd_OutputFormat, TestVersionCmd_OutputIsMultiLine, TestVersionCmd_GoVersionPattern, TestVersionCmd_PlatformLine, TestVersionCmd_CheckFlagIsNoOpNotError)
  • I updated relevant docs (CHANGELOG.md, inline comment block in the Makefile explaining the ldflag shape + the fallback strategy)
  • No new linter warnings (make lint green)
  • If breaking: I documented the migration path in the PR body and updated CHANGELOG.md

Screenshots / output

Pre-fix, make build produced a binary whose nodeup version was useless for triage:

$ make build
go build -trimpath -ldflags "-s -w" -o bin/nodeup ./cmd/nodeup
Built bin/nodeup
$ ./bin/nodeup version
nodeup version dev
  commit:     none
  built:      unknown
  go version: go1.24.0
  platform:   darwin/arm64

Post-fix:

$ make build
go build -trimpath -ldflags "-s -w -X main.version=15cde14-dirty -X main.commit=15cde14 -X main.date=2026-07-03T05:38:24Z" -o bin/nodeup ./cmd/nodeup
Built bin/nodeup (version=15cde14-dirty, commit=15cde14, date=2026-07-03T05:38:24Z)
$ ./bin/nodeup version
nodeup version 15cde14-dirty
  commit:     15cde14
  built:      2026-07-03T05:38:24Z
  go version: go1.26.4
  platform:   darwin/arm64

After a git tag v1.2.3 on a clean working tree, VERSION would resolve to v1.2.3 (the tag) instead of the short SHA — matching what goreleaser release would inject on a real release build.

Tests

$ go test -race -run TestVersionCmd ./internal/cli/...
ok  	github.com/dipto0321/nodeup/internal/cli	1.538s

Files touched

  • Makefile
    • Adds three vars at parse time: VERSION (git describe --tags --always --dirty), COMMIT (git rev-parse --short HEAD), DATE (date -u +%Y-%m-%dT%H:%M:%SZ). Each wrapped with || echo <fallback> so a build without .git/ (snapshot tarball, vendored copy) doesn't crash the build.
    • Combines them into LDFLAGS := -s -w -X main.version=$(VERSION) -X main.commit=$(COMMIT) -X main.date=$(DATE). Both build and install now use -ldflags "$(LDFLAGS)".
    • build echoes (version=…, commit=…, date=…) after a successful build so the operator can confirm the injected values without running the binary.
    • Inline comment block explains the parity-with-.goreleaser.yaml:37 invariant + the fallback strategy + why we wrap each shell call.
  • internal/cli/version_test.go — new, 5 tests:
    • TestVersionCmd_OutputFormat — every labeled field is present, in the right shape.
    • TestVersionCmd_OutputIsMultiLine — at least 5 lines (one per field), so a future collapse-into-one-line refactor fails the test.
    • TestVersionCmd_GoVersionPatterngo version: go1.X.Y regex match (the contract implied by docs/installation.md#verifying).
    • TestVersionCmd_PlatformLineplatform: <goos>/<goarch> regex match.
    • TestVersionCmd_CheckFlagIsNoOpNotErrornodeup version --check prints the placeholder, doesn't error (preserves existing scripts that pre-set the flag).
  • CHANGELOG.md### Fixed entry under [Unreleased] documenting the Makefile change + the version_test.go addition. References build: make build doesn't inject version/commit/date ldflags, nodeup version useless on local builds #68.

Closes #68

Pre-fix, Makefile:38 ran `go build -trimpath -ldflags "-s -w" -o
bin/nodeup ./cmd/nodeup` — no -X main.X=... injection — so every
locally-built binary (make build, go install, go install @latest)
shipped with the package-level defaults from cmd/nodeup/main.go:
17-26: version=dev, commit=none, date=unknown. nodeup version
then printed those literals on every local build, defeating the
install-verification flow documented in
docs/installation.md#verifying ("Should print a version, git
commit, build date, and Go runtime info") and undermining the
bug-report triage instructions in CONTRIBUTING.md that ask
reporters to paste nodeup version output — a locally-built
binary was indistinguishable from any other local build, so
triage couldn't tell if the bug reproed on the latest commit or
on a stale checkout.

Fix: capture three Makefile vars at parse time and feed them
into a single LDFLAGS variable used by both `build` and
`install`:

- VERSION from `git describe --tags --always --dirty` (closest
  semver tag, or short SHA + -dirty; falls back to `dev` if
  git is unavailable, e.g. snapshot tarball builds)
- COMMIT from `git rev-parse --short HEAD` (falls back to `none`)
- DATE from `date -u +%Y-%m-%dT%H:%M:%SZ` (RFC3339 UTC, matches
  .goreleaser.yaml:37's {{.CommitDate}} shape)

Each shell call is wrapped with `|| echo <fallback>` so a build
without .git/ doesn't crash. The combined LDFLAGS string is
"-s -w -X main.version=$(VERSION) -X main.commit=$(COMMIT)
-X main.date=$(DATE)" — same shape that goreleaser releases
use, so a local build is indistinguishable from a release
build via `nodeup version`.

internal/cli/version_test.go: 5 new tests pin the exact output
shape (line-by-line format, multi-line output, go1.X.Y runtime
pattern, <goos>/<goarch> platform pattern, --check flag is a
no-op not an error) so a future refactor can't silently drop a
field. Brings internal/cli coverage from 29.2% to 31.1%.

CHANGELOG: ### Fixed entry under [Unreleased].

Co-Authored-By: puku-ai-2.8 <noreply@puku.sh>
@dipto0321 dipto0321 changed the title fix(build): inject version/commit/date ldflags in make build and install fix(ci): inject version/commit/date ldflags in make build and install Jul 3, 2026
@dipto0321 dipto0321 force-pushed the fix/build/ldflags branch from 68125be to b440ea4 Compare July 3, 2026 05:42
@cocogitto-bot

cocogitto-bot Bot commented Jul 3, 2026

Copy link
Copy Markdown

✔️ b440ea4 - Conventional commits check succeeded.

@dipto0321 dipto0321 merged commit 03d9d5e into main Jul 3, 2026
10 checks passed
@dipto0321 dipto0321 deleted the fix/build/ldflags branch July 3, 2026 05:44
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

build: make build doesn't inject version/commit/date ldflags, nodeup version useless on local builds

1 participant