Skip to content

Commit 7d8cd8d

Browse files
ranaroussiclaude
andcommitted
feat: show 'git envapor' in help when run via the shim
- Detect the git-envapor invocation and set cobra's display-name annotation so usage and subcommand help read 'git envapor <command>' - Command matching is unchanged (root Name stays 'envapor'); plain 'envapor' invocations are unaffected 🤖 Generated with Claude Code Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
1 parent 6f8ce49 commit 7d8cd8d

2 files changed

Lines changed: 66 additions & 0 deletions

File tree

‎src/internal/cmd/root.go‎

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@ package cmd
33
import (
44
"fmt"
55
"os"
6+
"path/filepath"
7+
"strings"
68

79
"github.com/spf13/cobra"
810
)
@@ -21,8 +23,26 @@ var rootCmd = &cobra.Command{
2123

2224
// Execute runs the root command and maps any error to a non-zero exit code.
2325
func Execute() {
26+
if display, ok := gitInvocation(os.Args[0]); ok {
27+
// Invoked as the `git envapor` shim: show the Git subcommand form in
28+
// help and usage without changing how commands are matched.
29+
if rootCmd.Annotations == nil {
30+
rootCmd.Annotations = map[string]string{}
31+
}
32+
rootCmd.Annotations[cobra.CommandDisplayNameAnnotation] = display
33+
}
2434
if err := rootCmd.Execute(); err != nil {
2535
fmt.Fprintln(os.Stderr, "envapor: "+err.Error())
2636
os.Exit(1)
2737
}
2838
}
39+
40+
// gitInvocation reports whether the binary was run as Git's `git-envapor` shim
41+
// (that is, via `git envapor`), returning the display name to use in help.
42+
func gitInvocation(argv0 string) (string, bool) {
43+
base := strings.TrimSuffix(filepath.Base(argv0), ".exe")
44+
if base == "git-envapor" {
45+
return "git envapor", true
46+
}
47+
return "", false
48+
}

‎src/internal/cmd/root_test.go‎

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
package cmd
2+
3+
import (
4+
"strings"
5+
"testing"
6+
7+
"github.com/spf13/cobra"
8+
)
9+
10+
func TestGitInvocation(t *testing.T) {
11+
// Note: filepath.Base is OS-aware, so a backslash Windows path can only be
12+
// exercised on Windows; here we use forward-slash paths plus a .exe name.
13+
cases := map[string]bool{
14+
"/usr/local/bin/git-envapor": true,
15+
"git-envapor": true,
16+
"git-envapor.exe": true,
17+
"/usr/local/bin/envapor": false,
18+
"envapor": false,
19+
"/opt/bin/git-envapor-extra": false,
20+
}
21+
for argv0, want := range cases {
22+
if _, ok := gitInvocation(argv0); ok != want {
23+
t.Errorf("gitInvocation(%q) = %v, want %v", argv0, ok, want)
24+
}
25+
}
26+
if display, _ := gitInvocation("/x/git-envapor"); display != "git envapor" {
27+
t.Errorf("display name = %q, want %q", display, "git envapor")
28+
}
29+
}
30+
31+
// TestGitDisplayNameInCommandPath verifies the display-name annotation makes
32+
// subcommand help read "git envapor <cmd>" while command matching (Name) is
33+
// unchanged.
34+
func TestGitDisplayNameInCommandPath(t *testing.T) {
35+
root := &cobra.Command{Use: "envapor"}
36+
sub := &cobra.Command{Use: "status"}
37+
root.AddCommand(sub)
38+
root.Annotations = map[string]string{cobra.CommandDisplayNameAnnotation: "git envapor"}
39+
40+
if got := sub.CommandPath(); !strings.HasPrefix(got, "git envapor status") {
41+
t.Fatalf("CommandPath = %q, want it to start with %q", got, "git envapor status")
42+
}
43+
if sub.Name() != "status" {
44+
t.Fatalf("sub.Name() = %q, want status", sub.Name())
45+
}
46+
}

0 commit comments

Comments
 (0)