fix(bugseti): add gh CLI availability check with helpful error

Adds a startup check that verifies gh is in PATH and authenticated
before initializing services. Provides clear install/auth instructions
on failure instead of cryptic exec errors at runtime.

Closes #61

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Athena 2026-02-10 15:27:53 +00:00 committed by Snider
parent fd8360cda8
commit ded85b081f
3 changed files with 72 additions and 0 deletions

View file

@ -39,6 +39,11 @@ func main() {
log.Printf("Warning: Could not load config: %v", err) log.Printf("Warning: Could not load config: %v", err)
} }
// Check gh CLI availability
if err := bugseti.CheckGHCLI(); err != nil {
log.Fatalf("GitHub CLI check failed: %v", err)
}
// Initialize core services // Initialize core services
notifyService := bugseti.NewNotifyService(configService) notifyService := bugseti.NewNotifyService(configService)
statsService := bugseti.NewStatsService(configService) statsService := bugseti.NewStatsService(configService)

View file

@ -0,0 +1,30 @@
package bugseti
import (
"fmt"
"os/exec"
)
// CheckGHCLI verifies that the gh CLI is installed and authenticated.
// Returns nil if gh is available and logged in, or an error with
// actionable instructions for the user.
func CheckGHCLI() error {
// Check if gh is in PATH
if _, err := exec.LookPath("gh"); err != nil {
return fmt.Errorf("gh CLI not found in PATH: %w\n\n"+
"BugSETI requires the GitHub CLI (gh) to fetch issues and submit PRs.\n"+
"Install it from: https://cli.github.com\n\n"+
" macOS: brew install gh\n"+
" Linux: https://github.com/cli/cli/blob/trunk/docs/install_linux.md\n"+
" Windows: winget install --id GitHub.cli", err)
}
// Check if gh is authenticated
cmd := exec.Command("gh", "auth", "status")
if out, err := cmd.CombinedOutput(); err != nil {
return fmt.Errorf("gh CLI is not authenticated: %w\n%s\n\n"+
"Run 'gh auth login' to authenticate with GitHub.", err, out)
}
return nil
}

View file

@ -0,0 +1,37 @@
package bugseti
import (
"os/exec"
"strings"
"testing"
)
func TestCheckGHCLI_Good(t *testing.T) {
// Only run if gh is actually available (CI-friendly skip)
if _, err := exec.LookPath("gh"); err != nil {
t.Skip("gh CLI not installed, skipping")
}
err := CheckGHCLI()
// We can't guarantee auth status in all environments,
// but if gh is present the function should at least not panic.
if err != nil {
t.Logf("CheckGHCLI returned error (may be expected if not authenticated): %v", err)
}
}
func TestCheckGHCLI_Bad_MissingBinary(t *testing.T) {
// Save and clear PATH to simulate missing gh
t.Setenv("PATH", t.TempDir())
err := CheckGHCLI()
if err == nil {
t.Fatal("expected error when gh is not in PATH")
}
if !strings.Contains(err.Error(), "gh CLI not found") {
t.Errorf("error should mention 'gh CLI not found', got: %v", err)
}
if !strings.Contains(err.Error(), "https://cli.github.com") {
t.Errorf("error should include install URL, got: %v", err)
}
}