Skip to content

Commit b53bd0e

Browse files
authored
Feature/architecture refactor (#12)
* updates: better cli * plan described * githelpers better support for custom command (undo/back) * logging use +-MN pattern from now * switch from if into case to make linter happier * up * final shavings * reuse shared flags
1 parent b71fba5 commit b53bd0e

33 files changed

+2794
-1669
lines changed

.gitignore

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -37,9 +37,4 @@ go.work.sum
3737

3838
.idea
3939

40-
# generated result of aictx itself
41-
output.txt
42-
43-
.claude
44-
4540
/build

cmd/git-back/main.go

Lines changed: 37 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,44 +1,54 @@
11
package main
22

33
import (
4-
"fmt"
4+
"context"
55
"os"
6-
"runtime/debug"
6+
"os/signal"
7+
"syscall"
78

9+
"github.com/amberpixels/git-undo/cmd/shared"
810
"github.com/amberpixels/git-undo/internal/app"
11+
"github.com/urfave/cli/v3"
912
)
1013

1114
// version is set by the build ldflags
1215
// The default value is "dev+dirty" but it should never be used. In success path, it's always overwritten.
1316
var version = "dev+dirty"
17+
var versionSource = "hardcoded"
1418

15-
func main() {
16-
var verbose, dryRun bool
17-
for _, arg := range os.Args[1:] {
18-
if arg == "-v" || arg == "--verbose" {
19-
verbose = true
20-
}
21-
if arg == "--dry-run" {
22-
dryRun = true
23-
}
24-
}
19+
const (
20+
appNameGitBack = "git-back"
21+
)
2522

26-
// When running binary that was installed via `go install`, here we'll get the proper version
27-
if bi, ok := debug.ReadBuildInfo(); ok && bi.Main.Version != "" {
28-
version = bi.Main.Version
23+
func main() {
24+
// Create a context that can be cancelled with Ctrl+C
25+
ctx, cancel := signal.NotifyContext(context.Background(), syscall.SIGINT, syscall.SIGTERM)
26+
defer cancel()
27+
28+
version, versionSource = app.HandleAppVersion(version, versionSource)
29+
30+
cmd := &cli.Command{
31+
Name: appNameGitBack,
32+
Usage: "Navigate back through git checkout/switch operations",
33+
Flags: shared.CommonFlags(),
34+
Action: func(ctx context.Context, c *cli.Command) error {
35+
a := app.NewAppGitBack(version, versionSource)
36+
37+
if c.Bool("version") {
38+
return a.HandleVersion(c.Bool("verbose"))
39+
}
40+
41+
return a.Run(ctx, app.RunOptions{
42+
Verbose: c.Bool("verbose"),
43+
DryRun: c.Bool("dry-run"),
44+
HookCommand: c.String("hook"),
45+
ShowLog: c.Bool("log"),
46+
Args: c.Args().Slice(),
47+
})
48+
},
2949
}
30-
application := app.NewAppGiBack(version, verbose, dryRun)
3150

32-
if err := application.Run(os.Args[1:]); err != nil {
33-
_, _ = fmt.Fprintln(os.Stderr, redColor+appNameGitBack+" ❌: "+grayColor+err.Error()+resetColor)
34-
os.Exit(1)
51+
if err := cmd.Run(ctx, os.Args); err != nil {
52+
app.HandleError(appNameGitBack, err)
3553
}
3654
}
37-
38-
const (
39-
grayColor = "\033[90m"
40-
redColor = "\033[31m"
41-
resetColor = "\033[0m"
42-
43-
appNameGitBack = "git-back"
44-
)

cmd/git-undo/main.go

Lines changed: 41 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,44 +1,58 @@
11
package main
22

33
import (
4-
"fmt"
4+
"context"
55
"os"
6-
"runtime/debug"
6+
"os/signal"
7+
"syscall"
78

9+
"github.com/amberpixels/git-undo/cmd/shared"
810
"github.com/amberpixels/git-undo/internal/app"
11+
"github.com/urfave/cli/v3"
912
)
1013

1114
// version is set by the build ldflags
1215
// The default value is "dev+dirty" but it should never be used. In success path, it's always overwritten.
1316
var version = "dev+dirty"
17+
var versionSource = "hardcoded"
1418

15-
func main() {
16-
var verbose, dryRun bool
17-
for _, arg := range os.Args[1:] {
18-
if arg == "-v" || arg == "--verbose" {
19-
verbose = true
20-
}
21-
if arg == "--dry-run" {
22-
dryRun = true
23-
}
24-
}
19+
const (
20+
appNameGitUndo = "git-undo"
21+
)
2522

26-
// When running binary that was installed via `go install`, here we'll get the proper version
27-
if bi, ok := debug.ReadBuildInfo(); ok && bi.Main.Version != "" {
28-
version = bi.Main.Version
23+
func main() {
24+
// Create a context that can be cancelled with Ctrl+C
25+
ctx, cancel := signal.NotifyContext(context.Background(), syscall.SIGINT, syscall.SIGTERM)
26+
defer cancel()
27+
28+
version, versionSource = app.HandleAppVersion(version, versionSource)
29+
30+
cmd := &cli.Command{
31+
Name: appNameGitUndo,
32+
Usage: "Universal \"Ctrl + Z\" for Git commands",
33+
DisableSliceFlagSeparator: true,
34+
HideHelp: true,
35+
Flags: shared.CommonFlags(),
36+
Action: func(ctx context.Context, c *cli.Command) error {
37+
application := app.NewAppGitUndo(version, versionSource)
38+
if c.Bool("version") {
39+
return application.HandleVersion(c.Bool("verbose"))
40+
}
41+
42+
// Use the new structured approach with parsed options
43+
opts := app.RunOptions{
44+
Verbose: c.Bool("verbose"),
45+
DryRun: c.Bool("dry-run"),
46+
HookCommand: c.String("hook"),
47+
ShowLog: c.Bool("log"),
48+
Args: c.Args().Slice(),
49+
}
50+
51+
return application.Run(ctx, opts)
52+
},
2953
}
30-
application := app.NewAppGitUndo(version, verbose, dryRun)
3154

32-
if err := application.Run(os.Args[1:]); err != nil {
33-
_, _ = fmt.Fprintln(os.Stderr, redColor+appNameGitUndo+" ❌: "+grayColor+err.Error()+resetColor)
34-
os.Exit(1)
55+
if err := cmd.Run(ctx, os.Args); err != nil {
56+
app.HandleError(appNameGitUndo, err)
3557
}
3658
}
37-
38-
const (
39-
grayColor = "\033[90m"
40-
redColor = "\033[31m"
41-
resetColor = "\033[0m"
42-
43-
appNameGitUndo = "git-undo"
44-
)

cmd/shared/flags.go

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
package shared
2+
3+
import (
4+
"github.com/urfave/cli/v3"
5+
)
6+
7+
// CommonFlags returns the standard set of CLI flags used by both git-undo and git-back commands.
8+
func CommonFlags() []cli.Flag {
9+
return []cli.Flag{
10+
&cli.BoolFlag{
11+
Name: "help",
12+
Aliases: []string{"h"},
13+
Usage: "Show help",
14+
},
15+
&cli.BoolFlag{
16+
Name: "verbose",
17+
Aliases: []string{"v"},
18+
Usage: "Enable verbose output",
19+
},
20+
&cli.BoolFlag{
21+
Name: "dry-run",
22+
Usage: "Show what would be executed without running commands",
23+
},
24+
&cli.BoolFlag{
25+
Name: "version",
26+
Usage: "Print the version",
27+
},
28+
&cli.StringFlag{
29+
Name: "hook",
30+
Usage: "Hook command for shell integration (internal use)",
31+
},
32+
&cli.BoolFlag{
33+
Name: "log",
34+
Usage: "Display the git-undo command log",
35+
},
36+
}
37+
}

go.mod

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ toolchain go1.24.3
77
require (
88
github.com/mattn/go-shellwords v1.0.12
99
github.com/stretchr/testify v1.10.0
10+
github.com/urfave/cli/v3 v3.3.8
1011
)
1112

1213
require (

go.sum

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@ github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY=
88
github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA=
99
github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
1010
github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
11+
github.com/urfave/cli/v3 v3.3.8 h1:BzolUExliMdet9NlJ/u4m5vHSotJ3PzEqSAZ1oPMa/E=
12+
github.com/urfave/cli/v3 v3.3.8/go.mod h1:FJSKtM/9AiiTOJL4fJ6TbMUkxBXn7GO9guZqoZtpYpo=
1113
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
1214
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
1315
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=

0 commit comments

Comments
 (0)