Skip to content

Commit 109beff

Browse files
committed
feat: add version command to display application version and build info
1 parent d660c2c commit 109beff

File tree

2 files changed

+115
-3
lines changed

2 files changed

+115
-3
lines changed

cmd/root.go

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
11
package cmd
22

33
import (
4+
"fmt"
45
"wavezync/pulse-bridge/cmd/pulsebridge"
56
"wavezync/pulse-bridge/internal/env"
7+
"wavezync/pulse-bridge/internal/version"
68

79
"github.com/rs/zerolog"
810
"github.com/rs/zerolog/log"
@@ -16,10 +18,16 @@ var (
1618
)
1719

1820
var rootCmd = &cobra.Command{
19-
Use: "pulsebridge",
20-
Short: "pulsebridge is a powerful uptime monitoring tool",
21-
Long: `pulsebridge exposes internal service status via HTTP, enabling seamless integration with external monitoring tools like Atlassian Statuspage.`,
21+
Use: "pulsebridge",
22+
Short: "pulsebridge is a powerful uptime monitoring tool",
23+
Long: `pulsebridge exposes internal service status via HTTP, enabling seamless integration with external monitoring tools like Atlassian Statuspage.`,
2224
RunE: func(cmd *cobra.Command, args []string) error {
25+
versionFlag, _ := cmd.Flags().GetBool("version")
26+
if versionFlag {
27+
fmt.Println(version.GetVersionWithBuildInfo())
28+
return nil
29+
}
30+
2331
envConfig := env.Init()
2432

2533
if cmd.Flags().Changed("config") {
@@ -40,6 +48,7 @@ func init() {
4048
rootCmd.PersistentFlags().StringVar(&configPath, "config", "config.yml", "Path to configuration file")
4149
rootCmd.PersistentFlags().StringVar(&host, "host", "0.0.0.0", "Host address to bind the server")
4250
rootCmd.PersistentFlags().IntVar(&port, "port", 8080, "Port to run the server")
51+
rootCmd.PersistentFlags().BoolP("version", "v", false, "Print the version and exit")
4352
}
4453

4554
func Execute() {

internal/version/version.go

Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
package version
2+
3+
import (
4+
"fmt"
5+
"runtime"
6+
"runtime/debug"
7+
"strings"
8+
)
9+
10+
var (
11+
version string
12+
tag string
13+
commit string
14+
dirty bool
15+
)
16+
17+
func init() {
18+
// Always attempt to get build info from the Go runtime, regardless of build type.
19+
if info, ok := debug.ReadBuildInfo(); ok {
20+
if version == "" {
21+
// If version wasn't set via ldflags, try to get it from VCS info
22+
version = getVersionFromVCS(info)
23+
}
24+
commit = getCommit(info)
25+
dirty = getDirty(info)
26+
}
27+
28+
// Fallback version if nothing else is available
29+
if version == "" {
30+
version = "dev"
31+
}
32+
}
33+
34+
func getVersionFromVCS(info *debug.BuildInfo) string {
35+
for _, setting := range info.Settings {
36+
if setting.Key == "vcs.revision" {
37+
// Use commit hash as version if no proper version is available
38+
if len(setting.Value) >= 7 {
39+
return "dev-" + setting.Value[:7]
40+
}
41+
}
42+
}
43+
return ""
44+
}
45+
46+
func getDirty(info *debug.BuildInfo) bool {
47+
for _, setting := range info.Settings {
48+
if setting.Key == "vcs.modified" {
49+
return setting.Value == "true"
50+
}
51+
}
52+
return false
53+
}
54+
55+
func getCommit(info *debug.BuildInfo) string {
56+
for _, setting := range info.Settings {
57+
if setting.Key == "vcs.revision" {
58+
return setting.Value[:7]
59+
}
60+
}
61+
return ""
62+
}
63+
64+
// GetVersion returns the version of pulsebridge. This should be injected at build time
65+
// using: -ldflags="-X 'wavezync/pulse-bridge/internal/version.version=vX.X.X'".
66+
// If not provided, it will attempt to derive a version from VCS info.
67+
func GetVersion() string {
68+
return version
69+
}
70+
71+
// GetVersionWithBuildInfo returns detailed version information including
72+
// commit hash, dirty status, and Go version. This will work when built
73+
// within a Git checkout.
74+
func GetVersionWithBuildInfo() string {
75+
var parts []string
76+
77+
// Add the main version
78+
parts = append(parts, fmt.Sprintf("Version: %s", version))
79+
80+
// Add build metadata
81+
var buildMetadata []string
82+
if tag != "" {
83+
buildMetadata = append(buildMetadata, tag)
84+
}
85+
if commit != "" {
86+
buildMetadata = append(buildMetadata, commit)
87+
}
88+
if dirty {
89+
buildMetadata = append(buildMetadata, "dirty")
90+
}
91+
92+
if len(buildMetadata) > 0 {
93+
parts = append(parts, fmt.Sprintf("Build: %s", strings.Join(buildMetadata, ".")))
94+
}
95+
96+
// Add Go version
97+
parts = append(parts, fmt.Sprintf("Go: %s", runtime.Version()))
98+
99+
// Add architecture
100+
parts = append(parts, fmt.Sprintf("Platform: %s/%s", runtime.GOOS, runtime.GOARCH))
101+
102+
return strings.Join(parts, "\n")
103+
}

0 commit comments

Comments
 (0)