package cmd import ( "flag" "fmt" "runtime" "runtime/debug" ) // Version is what this binary was built as. It is stamped at link time and // defaults to something honest. // // "dev" is the truth for a build from a working tree: a binary somebody built // out of a checkout is not a release and must not claim to be one. A release // build says otherwise by naming this variable: // // go build -ldflags "-X git.noodles.cam/claude-skills/marketplace/cli/internal/cmd.Version=v1.2.3" ./cmd/kettle // // which is what `make build`, `make dist` and `make release` do. The path is // exercised by a test that builds with the flag and reads the answer back, // because a -X whose symbol path is one character wrong is silently ignored and // the binary goes on reporting "dev". var Version = "dev" func init() { register(&Command{ Name: "version", Group: GroupProject, Short: "print the version this binary was built as", Long: `A binary that cannot say what it is, is a support problem: an operator with an old copy on PATH and a skill written against a newer one has no way to see the mismatch, and neither does anybody reading their transcript. The version is stamped at link time. A build from source says "dev" and means it — that is not a placeholder to be edited, it is the answer for a binary that came out of somebody's working tree rather than off a tag. The commit is reported when the build recorded one, which ` + "`go build`" + ` does from git and a build from an unpacked tarball cannot. A tree with uncommitted changes in it says so beside the commit.`, Examples: []Example{ {"kettle version", "the version, the toolchain and the commit"}, {"kettle version --short", "just the version, for a script"}, }, Setup: func(fs *flag.FlagSet) func([]string) error { short := fs.Bool("short", false, "print the version alone, with nothing around it") return func(args []string) error { if len(args) > 0 { return Fail("version takes no arguments") } if *short { fmt.Println(Version) return nil } fmt.Printf("kettle %s\n", Version) fmt.Printf("built %s %s/%s\n", runtime.Version(), runtime.GOOS, runtime.GOARCH) if rev := revision(); rev != "" { fmt.Printf("commit %s\n", rev) } return nil } }, }) } // revision is the commit this binary was built from, or "" when the build // recorded none. // // `go build` stamps it out of git; a build from an unpacked tarball has no // repository to ask, and there is nothing to report rather than something to // invent. A dirty tree is named as one: the commit is then a lower bound on // what is in the binary and not a description of it. func revision() string { info, ok := debug.ReadBuildInfo() if !ok { return "" } var rev string var dirty bool for _, s := range info.Settings { switch s.Key { case "vcs.revision": rev = s.Value case "vcs.modified": dirty = s.Value == "true" } } if rev != "" && dirty { rev += " (with uncommitted changes)" } return rev }