01fb5a2703
There is no CI: the instance has no act_runner and none is planned, so releases are cut by hand. That makes `make check` the only thing standing between a mistake and the tracker, and it is one command: gofmt, vet, the suite with the cache defeated, `go mod verify`, a vendored build, and `kettle gen skills --check`. The last one is the invariant worth having — the plugin's SKILL.md command reference is generated from the binary's registry, so a flag that changed cannot ship with documentation that recommends the old one. `cli/cmd/release` publishes to Gitea using the same SDK the binary already vendors, which is a pleasing thing to be able to say: nothing third-party handles the artifacts. It is a second binary rather than a `kettle` subcommand on purpose — `kettle`'s command tree is what generates the plugin's skills, so a verb there ships to every operator, and publishing a release is build infrastructure. It is idempotent end to end: an existing release for the tag is reused, an asset of the same name is replaced rather than doubled, and a retried run converges instead of duplicating. `make release` refuses three things, each with its own message: a dirty working tree, a TAG that is not what `git describe` reports, and a tag the remote does not have. A release built from uncommitted code is unreproducible and nobody finds out until they need to reproduce it. `kettle version` reports the stamp, the toolchain and the VCS revision. The default is `dev`, and a hand build says so and means it — a binary out of somebody's working tree is not a release and must not claim to be one. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
94 lines
3.0 KiB
Go
94 lines
3.0 KiB
Go
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
|
|
}
|