Skip to content

Commit ed0a21a

Browse files
committed
cmd: add version command
Report the build version and commit hash through both `llformat version` and `llformat --version`. Inject version data from the Makefile for local builds and fall back to Go build info for module installs.
1 parent 71a5f48 commit ed0a21a

3 files changed

Lines changed: 137 additions & 4 deletions

File tree

Makefile

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
GO ?= go
22
BIN_DIR ?= bin
33
BIN := $(BIN_DIR)/llformat
4+
VERSION ?= $(shell git describe --tags --dirty --always 2>/dev/null || echo dev)
5+
COMMIT ?= $(shell git rev-parse HEAD 2>/dev/null || echo unknown)
6+
LDFLAGS ?= -X main.buildVersion=$(VERSION) -X main.buildCommit=$(COMMIT)
47

58
.PHONY: all build install unit test clean
69
.PHONY: fmt fmt-check lint self-check
@@ -10,13 +13,16 @@ all: build
1013
# Build the llformat CLI
1114
build: $(BIN)
1215

13-
$(BIN): $(shell find formatter -name '*.go') $(shell find cmd -name '*.go') go.mod go.sum
16+
$(BIN): FORCE $(shell find formatter -name '*.go') $(shell find cmd -name '*.go') go.mod go.sum Makefile
1417
@mkdir -p $(BIN_DIR)
15-
$(GO) build -o $@ ./cmd/llformat
18+
$(GO) build -ldflags "$(LDFLAGS)" -o $@ ./cmd/llformat
19+
20+
.PHONY: FORCE
21+
FORCE:
1622

1723
# Install llformat to GOPATH/bin
1824
install: build
19-
$(GO) install ./cmd/llformat
25+
$(GO) install -ldflags "$(LDFLAGS)" ./cmd/llformat
2026

2127
# Run unit tests
2228
unit test:
@@ -38,7 +44,7 @@ fmt-check: build
3844
self-binary-check: build
3945
@tmp=$$(mktemp -t llformat_bin.XXXXXX); \
4046
cp $(BIN) $$tmp; \
41-
$(GO) build -o $(BIN) ./cmd/llformat; \
47+
$(GO) build -ldflags "$(LDFLAGS)" -o $(BIN) ./cmd/llformat; \
4248
cmp -s $$tmp $(BIN); \
4349
rm -f $$tmp; \
4450
echo "Self-binary-check ok: reproducible build."

cmd/llformat/main.go

Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import (
55
"fmt"
66
"io"
77
"os"
8+
"runtime/debug"
89
"sort"
910
"strings"
1011

@@ -18,6 +19,7 @@ func main() {
1819

1920
type cliFlags struct {
2021
write bool
22+
version bool
2123
colLimit int
2224
tabStop int
2325
moveInline bool
@@ -50,6 +52,10 @@ func run(args []string, stdout, stderr io.Writer) int {
5052
&f.write, "write", false,
5153
"write result to (source) file instead of stdout",
5254
)
55+
fs.BoolVar(
56+
&f.version, "version", false,
57+
"print version information and exit",
58+
)
5359
fs.IntVar(&f.colLimit, "col", 80, "column limit for formatting")
5460
fs.IntVar(
5561
&f.tabStop, "tab", 8, "tab stop width for column calculations",
@@ -112,6 +118,10 @@ func run(args []string, stdout, stderr io.Writer) int {
112118
return 2
113119
}
114120

121+
if f.version || isVersionCommand(fs.Args()) {
122+
return runVersion(stdout)
123+
}
124+
115125
cfg, err := buildPipelineConfig(f)
116126
if err != nil {
117127
fmt.Fprintln(stderr, err)
@@ -184,6 +194,7 @@ func printUsage(w io.Writer) {
184194
)
185195
fmt.Fprintln(w, " llformat --print-plan")
186196
fmt.Fprintln(w, " llformat --print-logcalls-patterns")
197+
fmt.Fprintln(w, " llformat version")
187198
fmt.Fprintln(w)
188199
fmt.Fprintln(w, "flags:")
189200
fmt.Fprintln(
@@ -236,6 +247,10 @@ func printUsage(w io.Writer) {
236247
w, " --print-logcalls-patterns print log/printf matching "+
237248
"patterns and exit",
238249
)
250+
fmt.Fprintln(
251+
w, " --version print version information "+
252+
"and exit",
253+
)
239254
fmt.Fprintln(
240255
w, " --trace-dsl trace applied DSL edits to "+
241256
"stderr",
@@ -246,6 +261,77 @@ func printUsage(w io.Writer) {
246261
)
247262
}
248263

264+
func isVersionCommand(args []string) bool {
265+
return len(args) == 1 && args[0] == "version"
266+
}
267+
268+
func runVersion(w io.Writer) int {
269+
info := versionInfo()
270+
fmt.Fprintf(w, "llformat version %s\n", info.Version)
271+
fmt.Fprintf(w, "commit %s\n", info.Commit)
272+
273+
return 0
274+
}
275+
276+
type versionDetails struct {
277+
Version string
278+
Commit string
279+
}
280+
281+
var (
282+
buildVersion = ""
283+
buildCommit = ""
284+
)
285+
286+
func versionInfo() versionDetails {
287+
version := buildVersion
288+
commit := buildCommit
289+
290+
if bi, ok := debug.ReadBuildInfo(); ok {
291+
if version == "" && bi.Main.Version != "" &&
292+
bi.Main.Version != "(devel)" {
293+
294+
version = bi.Main.Version
295+
}
296+
297+
for _, setting := range bi.Settings {
298+
switch setting.Key {
299+
case "vcs.revision":
300+
if commit == "" {
301+
commit = shortCommit(setting.Value)
302+
}
303+
304+
case "vcs.modified":
305+
if setting.Value == "true" && version != "" &&
306+
!strings.HasSuffix(version, "-dirty") {
307+
308+
version += "-dirty"
309+
}
310+
}
311+
}
312+
}
313+
314+
if version == "" {
315+
version = "dev"
316+
}
317+
if commit == "" {
318+
commit = "unknown"
319+
}
320+
321+
return versionDetails{
322+
Version: version,
323+
Commit: commit,
324+
}
325+
}
326+
327+
func shortCommit(commit string) string {
328+
if len(commit) <= 12 {
329+
return commit
330+
}
331+
332+
return commit[:12]
333+
}
334+
249335
func buildPipelineConfig(f cliFlags) (formatter.PipelineConfig, error) {
250336
excludes := parseCommaList(f.multilineExclude)
251337
logCallsNames := parseCommaList(f.logCallsNames)

cmd/llformat/main_test.go

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,3 +64,44 @@ func TestRunMultiplePathsRequireWrite(t *testing.T) {
6464
"multiple paths require -w/--write",
6565
)
6666
}
67+
68+
func TestRunVersionCommand(t *testing.T) {
69+
oldVersion, oldCommit := buildVersion, buildCommit
70+
buildVersion, buildCommit = "v1.2.3-test", "abcdef123456"
71+
t.Cleanup(func() {
72+
buildVersion, buildCommit = oldVersion, oldCommit
73+
})
74+
75+
var stdout, stderr bytes.Buffer
76+
code := run([]string{"version"}, &stdout, &stderr)
77+
78+
require.Equal(t, 0, code)
79+
require.Empty(t, stderr.String())
80+
require.Equal(
81+
t, "llformat version v1.2.3-test\ncommit abcdef123456\n",
82+
stdout.String(),
83+
)
84+
}
85+
86+
func TestRunVersionFlag(t *testing.T) {
87+
oldVersion, oldCommit := buildVersion, buildCommit
88+
buildVersion, buildCommit = "v1.2.3-test", "abcdef123456"
89+
t.Cleanup(func() {
90+
buildVersion, buildCommit = oldVersion, oldCommit
91+
})
92+
93+
var stdout, stderr bytes.Buffer
94+
code := run([]string{"--version"}, &stdout, &stderr)
95+
96+
require.Equal(t, 0, code)
97+
require.Empty(t, stderr.String())
98+
require.Equal(
99+
t, "llformat version v1.2.3-test\ncommit abcdef123456\n",
100+
stdout.String(),
101+
)
102+
}
103+
104+
func TestShortCommit(t *testing.T) {
105+
require.Equal(t, "abcdef123456", shortCommit("abcdef1234567890"))
106+
require.Equal(t, "abc", shortCommit("abc"))
107+
}

0 commit comments

Comments
 (0)