feat(stale): add gt stale command for binary staleness check
Exposes CheckStaleBinary() via CLI for scripting. Supports --json for machine-readable output and --quiet for exit-code-only mode (0=stale, 1=fresh, 2=error). Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
committed by
Steve Yegge
parent
b990094010
commit
025586e16b
122
internal/cmd/stale.go
Normal file
122
internal/cmd/stale.go
Normal file
@@ -0,0 +1,122 @@
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"os"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
"github.com/steveyegge/gastown/internal/style"
|
||||
"github.com/steveyegge/gastown/internal/version"
|
||||
)
|
||||
|
||||
var staleJSON bool
|
||||
var staleQuiet bool
|
||||
|
||||
var staleCmd = &cobra.Command{
|
||||
Use: "stale",
|
||||
GroupID: GroupDiag,
|
||||
Short: "Check if the gt binary is stale",
|
||||
Long: `Check if the gt binary was built from an older commit than the current repo HEAD.
|
||||
|
||||
This command compares the commit hash embedded in the binary at build time
|
||||
with the current HEAD of the gastown repository.
|
||||
|
||||
Examples:
|
||||
gt stale # Human-readable output
|
||||
gt stale --json # Machine-readable JSON output
|
||||
gt stale --quiet # Exit code only (0=stale, 1=fresh)
|
||||
|
||||
Exit codes:
|
||||
0 - Binary is stale (needs rebuild)
|
||||
1 - Binary is fresh (up to date)
|
||||
2 - Error (could not determine staleness)`,
|
||||
RunE: runStale,
|
||||
}
|
||||
|
||||
func init() {
|
||||
staleCmd.Flags().BoolVar(&staleJSON, "json", false, "Output as JSON")
|
||||
staleCmd.Flags().BoolVarP(&staleQuiet, "quiet", "q", false, "Exit code only (0=stale, 1=fresh)")
|
||||
rootCmd.AddCommand(staleCmd)
|
||||
}
|
||||
|
||||
// StaleOutput represents the JSON output structure.
|
||||
type StaleOutput struct {
|
||||
Stale bool `json:"stale"`
|
||||
BinaryCommit string `json:"binary_commit"`
|
||||
RepoCommit string `json:"repo_commit"`
|
||||
CommitsBehind int `json:"commits_behind,omitempty"`
|
||||
Error string `json:"error,omitempty"`
|
||||
}
|
||||
|
||||
func runStale(cmd *cobra.Command, args []string) error {
|
||||
// Find the gastown repo
|
||||
repoRoot, err := version.GetRepoRoot()
|
||||
if err != nil {
|
||||
if staleQuiet {
|
||||
os.Exit(2)
|
||||
}
|
||||
if staleJSON {
|
||||
return outputStaleJSON(StaleOutput{Error: err.Error()})
|
||||
}
|
||||
return fmt.Errorf("cannot find gastown repo: %w", err)
|
||||
}
|
||||
|
||||
// Check staleness
|
||||
info := version.CheckStaleBinary(repoRoot)
|
||||
|
||||
// Handle errors
|
||||
if info.Error != nil {
|
||||
if staleQuiet {
|
||||
os.Exit(2)
|
||||
}
|
||||
if staleJSON {
|
||||
return outputStaleJSON(StaleOutput{Error: info.Error.Error()})
|
||||
}
|
||||
return fmt.Errorf("staleness check failed: %w", info.Error)
|
||||
}
|
||||
|
||||
// Quiet mode: just exit with appropriate code
|
||||
if staleQuiet {
|
||||
if info.IsStale {
|
||||
os.Exit(0)
|
||||
}
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
// Build output
|
||||
output := StaleOutput{
|
||||
Stale: info.IsStale,
|
||||
BinaryCommit: info.BinaryCommit,
|
||||
RepoCommit: info.RepoCommit,
|
||||
CommitsBehind: info.CommitsBehind,
|
||||
}
|
||||
|
||||
if staleJSON {
|
||||
return outputStaleJSON(output)
|
||||
}
|
||||
|
||||
return outputStaleText(output)
|
||||
}
|
||||
|
||||
func outputStaleJSON(output StaleOutput) error {
|
||||
enc := json.NewEncoder(os.Stdout)
|
||||
enc.SetIndent("", " ")
|
||||
return enc.Encode(output)
|
||||
}
|
||||
|
||||
func outputStaleText(output StaleOutput) error {
|
||||
if output.Stale {
|
||||
fmt.Printf("%s Binary is stale\n", style.Warning.Render("⚠"))
|
||||
fmt.Printf(" Binary: %s\n", version.ShortCommit(output.BinaryCommit))
|
||||
fmt.Printf(" Repo: %s\n", version.ShortCommit(output.RepoCommit))
|
||||
if output.CommitsBehind > 0 {
|
||||
fmt.Printf(" %s\n", style.Dim.Render(fmt.Sprintf("(%d commits behind)", output.CommitsBehind)))
|
||||
}
|
||||
fmt.Printf("\n Run 'go install ./cmd/gt' to rebuild\n")
|
||||
} else {
|
||||
fmt.Printf("%s Binary is fresh\n", style.Success.Render("✓"))
|
||||
fmt.Printf(" Commit: %s\n", version.ShortCommit(output.BinaryCommit))
|
||||
}
|
||||
return nil
|
||||
}
|
||||
Reference in New Issue
Block a user