Skip to content

Commit 0c00660

Browse files
authored
refactor: Improve Go Report Card score (target: A+) by addressing static analysis findings (#12)
* chore: Run gofmt -s across repository to standardize formatting. * refactor: Simplify main function by delegating flag parsing and command handling to helper functions to reduce cyclomatic complexity and improve maintainability. * refactor: Extract git status parsing into helper functions for readability. * refactor: Simplify disk and timeline panel rendering logic.
1 parent 5925f44 commit 0c00660

12 files changed

Lines changed: 362 additions & 275 deletions

File tree

cmd/git-scope/main.go

Lines changed: 86 additions & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,12 @@ import (
1717

1818
const version = "1.0.1"
1919

20+
type options struct {
21+
ConfigPath string
22+
ShowVersion bool
23+
ShowHelp bool
24+
}
25+
2026
func usage() {
2127
fmt.Fprintf(os.Stderr, `git-scope v%s — A fast TUI to see the status of all git repositories
2228
@@ -44,111 +50,125 @@ Flags:
4450
flag.PrintDefaults()
4551
}
4652

53+
func printVersion() {
54+
fmt.Printf("git-scope v%s\n", version)
55+
}
56+
4757
func main() {
4858
flag.Usage = usage
49-
configPath := flag.String("config", config.DefaultConfigPath(), "Path to config file")
50-
showVersion := flag.Bool("v", false, "Show version")
51-
flag.Bool("version", false, "Show version")
52-
flag.Parse()
5359

54-
// Handle version flag
55-
if *showVersion || isFlagPassed("version") {
56-
fmt.Printf("git-scope v%s\n", version)
60+
opts := parseFlags()
61+
if opts.ShowVersion {
62+
printVersion()
5763
return
5864
}
59-
60-
args := flag.Args()
61-
cmd := ""
62-
dirs := []string{}
63-
64-
// Parse command and directories
65-
if len(args) >= 1 {
66-
switch args[0] {
67-
case "scan", "tui", "help", "init", "scan-all", "issue", "-h", "--help", "-v", "--version":
68-
cmd = args[0]
69-
dirs = args[1:]
70-
default:
71-
// Assume it's a directory
72-
cmd = "tui"
73-
dirs = args
74-
}
65+
if opts.ShowHelp {
66+
usage()
67+
return
7568
}
7669

77-
// Handle help early
78-
if cmd == "help" || cmd == "-h" || cmd == "--help" {
70+
cmd, dirs := parseCommand(flag.Args())
71+
// Handle help subcommand (e.g. `git-scope help`)
72+
if cmd == "help" {
7973
usage()
8074
return
8175
}
8276

83-
// Handle version
84-
if cmd == "-v" || cmd == "--version" {
85-
fmt.Printf("git-scope v%s\n", version)
86-
return
77+
if err := run(cmd, dirs, opts.ConfigPath); err != nil {
78+
log.Fatal(err)
8779
}
80+
}
8881

89-
// Handle init command
90-
if cmd == "init" {
91-
runInit()
92-
return
82+
// parseFlags defines and parses all supported CLI flags and returns
83+
// the resolved options. It is responsible only for flag handling and
84+
// does not perform any command execution. So if a user runs
85+
// `git-scope -foo bar`, parseFlags only parses the `-foo` flag, if it
86+
// is supported by git-scope.
87+
func parseFlags() options {
88+
configPath := flag.String("config", config.DefaultConfigPath(), "Path to config file")
89+
90+
var showVersion bool
91+
flag.BoolVar(&showVersion, "v", false, "Show version")
92+
flag.BoolVar(&showVersion, "version", false, "Show version")
93+
94+
var showHelp bool
95+
flag.BoolVar(&showHelp, "h", false, "Help")
96+
flag.BoolVar(&showHelp, "help", false, "Help")
97+
98+
flag.Parse()
99+
100+
return options{
101+
ConfigPath: *configPath,
102+
ShowVersion: showVersion,
103+
ShowHelp: showHelp,
93104
}
105+
}
94106

95-
// Handle issue command
96-
if cmd == "issue" {
107+
// parseCommand determines the command and directories from positional
108+
// arguments.
109+
func parseCommand(args []string) (cmd string, dirs []string) {
110+
if len(args) == 0 {
111+
return "", nil
112+
}
113+
114+
switch args[0] {
115+
case "scan", "tui", "help", "init", "scan-all", "issue":
116+
return args[0], args[1:]
117+
default:
118+
return "tui", args // assume it's a directory
119+
}
120+
}
121+
122+
// run executes the requested command using the provided configuration path
123+
// and directories.
124+
func run(cmd string, dirs []string, configPath string) error {
125+
switch cmd {
126+
case "init":
127+
runInit()
128+
return nil
129+
case "issue":
97130
runIssue()
98-
return
131+
return nil
132+
case "scan-all":
133+
runScanAll()
134+
return nil
99135
}
100136

101-
// Load configuration
102-
cfg, err := config.Load(*configPath)
137+
// Only commands below need config
138+
cfg, err := config.Load(configPath)
103139
if err != nil {
104-
log.Fatalf("failed to load config: %v", err)
140+
return fmt.Errorf("failed to load config: %w", err)
105141
}
106142

107-
// Override roots if directories provided via CLI
108143
if len(dirs) > 0 {
109144
cfg.Roots = expandDirs(dirs)
110-
} else if !config.ConfigExists(*configPath) {
111-
// No config file and no CLI dirs - use smart defaults
145+
} else if !config.ConfigExists(configPath) {
112146
cfg.Roots = getSmartDefaults()
113147
}
114148

115149
switch cmd {
116150
case "scan":
117151
repos, err := scan.ScanRoots(cfg.Roots, cfg.Ignore)
118152
if err != nil {
119-
log.Fatalf("scan error: %v", err)
153+
return fmt.Errorf("scan error: %w", err)
120154
}
121155
if err := scan.PrintJSON(os.Stdout, repos); err != nil {
122-
log.Fatalf("print error: %v", err)
156+
return fmt.Errorf("print error: %w", err)
123157
}
124-
125-
case "scan-all":
126-
runScanAll()
127-
return
158+
return nil
128159

129160
case "tui", "":
130161
if err := tui.Run(cfg); err != nil {
131-
log.Fatalf("tui error: %v", err)
162+
return fmt.Errorf("tui error: %w", err)
132163
}
164+
return nil
133165

134166
default:
135-
fmt.Fprintf(os.Stderr, "unknown command: %s\n\n", cmd)
136167
usage()
137-
os.Exit(1)
168+
return fmt.Errorf("unknown command: %s", cmd)
138169
}
139170
}
140171

141-
// isFlagPassed checks if a flag was explicitly passed on the command line
142-
func isFlagPassed(name string) bool {
143-
found := false
144-
flag.Visit(func(f *flag.Flag) {
145-
if f.Name == name {
146-
found = true
147-
}
148-
})
149-
return found
150-
}
151-
152172
// expandDirs converts relative paths and ~ to absolute paths
153173
func expandDirs(dirs []string) []string {
154174
result := make([]string, 0, len(dirs))
@@ -217,10 +237,10 @@ func getSmartDefaults() []string {
217237
// runInit creates a config file interactively
218238
func runInit() {
219239
configPath := config.DefaultConfigPath()
220-
240+
221241
fmt.Println("git-scope init — Setup your configuration")
222242
fmt.Println()
223-
243+
224244
// Check if config already exists
225245
if config.ConfigExists(configPath) {
226246
fmt.Printf("Config file already exists at: %s\n", configPath)
@@ -235,7 +255,7 @@ func runInit() {
235255
}
236256

237257
reader := bufio.NewReader(os.Stdin)
238-
258+
239259
// Get directories
240260
fmt.Println("Enter directories to scan for git repos (one per line, empty line to finish):")
241261
fmt.Println()
@@ -246,7 +266,7 @@ func runInit() {
246266
fmt.Println()
247267
fmt.Println("Examples: ~/code, ~/projects, ~/work")
248268
fmt.Println()
249-
269+
250270
dirs := []string{}
251271
for {
252272
fmt.Print("> ")

internal/config/config.go

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ func defaultConfig() *Config {
2525
// Fallback to home directory if cwd fails
2626
cwd, _ = os.UserHomeDir()
2727
}
28-
28+
2929
return &Config{
3030
Roots: []string{cwd},
3131
Ignore: []string{
@@ -76,7 +76,7 @@ func expandPath(path string) string {
7676
}
7777
path = filepath.Join(home, path[2:])
7878
}
79-
79+
8080
// Handle "." or relative paths - convert to absolute
8181
if path == "." || !filepath.IsAbs(path) {
8282
absPath, err := filepath.Abs(path)
@@ -85,7 +85,7 @@ func expandPath(path string) string {
8585
}
8686
path = absPath
8787
}
88-
88+
8989
return path
9090
}
9191

@@ -140,4 +140,3 @@ func CreateConfig(path string, roots []string, editor string) error {
140140

141141
return nil
142142
}
143-

0 commit comments

Comments
 (0)