fix(lint): resolve all errcheck warnings
Fix ~50 errcheck warnings across the codebase:
- Add explicit `_ =` for intentionally ignored error returns (cleanup,
best-effort operations, etc.)
- Use `defer func() { _ = ... }()` pattern for defer statements
- Handle tmux SetEnvironment, KillSession, SendKeysRaw returns
- Handle mail router.Send returns
- Handle os.RemoveAll, os.Rename in cleanup paths
- Handle rand.Read returns for ID generation
- Handle fmt.Fprint* returns when writing to io.Writer
- Fix for-select with single case to use for-range
- Handle cobra MarkFlagRequired returns
All tests pass. Code compiles without errors.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -70,7 +70,7 @@ func TestIsBeadsRepo(t *testing.T) {
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer os.RemoveAll(tmpDir)
|
||||
defer func() { _ = os.RemoveAll(tmpDir) }()
|
||||
|
||||
b := New(tmpDir)
|
||||
// This should return false since there's no .beads directory
|
||||
|
||||
@@ -501,8 +501,8 @@ func runCrewAt(cmd *cobra.Command, args []string) error {
|
||||
}
|
||||
|
||||
// Set environment
|
||||
t.SetEnvironment(sessionID, "GT_RIG", r.Name)
|
||||
t.SetEnvironment(sessionID, "GT_CREW", name)
|
||||
_ = t.SetEnvironment(sessionID, "GT_RIG", r.Name)
|
||||
_ = t.SetEnvironment(sessionID, "GT_CREW", name)
|
||||
|
||||
// Start claude with skip permissions (crew workers are trusted like Mayor)
|
||||
// Use SendKeysDelayed to allow shell initialization after NewSession
|
||||
@@ -723,8 +723,8 @@ func runCrewRefresh(cmd *cobra.Command, args []string) error {
|
||||
}
|
||||
|
||||
// Set environment
|
||||
t.SetEnvironment(sessionID, "GT_RIG", r.Name)
|
||||
t.SetEnvironment(sessionID, "GT_CREW", name)
|
||||
_ = t.SetEnvironment(sessionID, "GT_RIG", r.Name)
|
||||
_ = t.SetEnvironment(sessionID, "GT_CREW", name)
|
||||
|
||||
// Start claude
|
||||
// Use SendKeysDelayed to allow shell initialization after NewSession
|
||||
|
||||
@@ -320,7 +320,7 @@ func setRequestingState(role Role, action HandoffAction, townRoot string) error
|
||||
// Read existing state or create new
|
||||
state := make(map[string]interface{})
|
||||
if data, err := os.ReadFile(stateFile); err == nil {
|
||||
json.Unmarshal(data, &state)
|
||||
_ = json.Unmarshal(data, &state)
|
||||
}
|
||||
|
||||
// Set requesting state
|
||||
|
||||
@@ -64,7 +64,7 @@ func runInit(cmd *cobra.Command, args []string) error {
|
||||
// Create .gitkeep to ensure directory is tracked if needed
|
||||
gitkeep := filepath.Join(dirPath, ".gitkeep")
|
||||
if _, err := os.Stat(gitkeep); os.IsNotExist(err) {
|
||||
os.WriteFile(gitkeep, []byte(""), 0644)
|
||||
_ = os.WriteFile(gitkeep, []byte(""), 0644)
|
||||
}
|
||||
|
||||
fmt.Printf(" ✓ Created %s/\n", dir)
|
||||
|
||||
@@ -164,7 +164,7 @@ func init() {
|
||||
mailSendCmd.Flags().StringVar(&mailType, "type", "notification", "Message type (task, scavenge, notification, reply)")
|
||||
mailSendCmd.Flags().StringVar(&mailReplyTo, "reply-to", "", "Message ID this is replying to")
|
||||
mailSendCmd.Flags().BoolVarP(&mailNotify, "notify", "n", false, "Send tmux notification to recipient")
|
||||
mailSendCmd.MarkFlagRequired("subject")
|
||||
_ = mailSendCmd.MarkFlagRequired("subject")
|
||||
|
||||
// Inbox flags
|
||||
mailInboxCmd.Flags().BoolVar(&mailInboxJSON, "json", false, "Output as JSON")
|
||||
@@ -363,7 +363,7 @@ func runMailRead(cmd *cobra.Command, args []string) error {
|
||||
}
|
||||
|
||||
// Mark as read
|
||||
mailbox.MarkRead(msgID)
|
||||
_ = mailbox.MarkRead(msgID)
|
||||
|
||||
// JSON output
|
||||
if mailReadJSON {
|
||||
@@ -722,6 +722,6 @@ func runMailReply(cmd *cobra.Command, args []string) error {
|
||||
// generateThreadID creates a random thread ID for new message threads.
|
||||
func generateThreadID() string {
|
||||
b := make([]byte, 6)
|
||||
rand.Read(b)
|
||||
_, _ = rand.Read(b)
|
||||
return "thread-" + hex.EncodeToString(b)
|
||||
}
|
||||
|
||||
@@ -120,7 +120,7 @@ func startMayorSession(t *tmux.Tmux) error {
|
||||
}
|
||||
|
||||
// Set environment
|
||||
t.SetEnvironment(MayorSessionName, "GT_ROLE", "mayor")
|
||||
_ = t.SetEnvironment(MayorSessionName, "GT_ROLE", "mayor")
|
||||
|
||||
// Launch Claude in a respawn loop - session survives restarts
|
||||
// The startup hook handles 'gt prime' automatically
|
||||
@@ -148,7 +148,7 @@ func runMayorStop(cmd *cobra.Command, args []string) error {
|
||||
fmt.Println("Stopping Mayor session...")
|
||||
|
||||
// Try graceful shutdown first
|
||||
t.SendKeysRaw(MayorSessionName, "C-c")
|
||||
_ = t.SendKeysRaw(MayorSessionName, "C-c")
|
||||
time.Sleep(100 * time.Millisecond)
|
||||
|
||||
// Kill the session
|
||||
@@ -246,7 +246,7 @@ func runMayorRestart(cmd *cobra.Command, args []string) error {
|
||||
if running {
|
||||
// Graceful restart: send Ctrl-C to exit Claude, loop will restart it
|
||||
fmt.Println("Restarting Mayor (sending Ctrl-C to trigger respawn loop)...")
|
||||
t.SendKeysRaw(MayorSessionName, "C-c")
|
||||
_ = t.SendKeysRaw(MayorSessionName, "C-c")
|
||||
fmt.Printf("%s Mayor will restart automatically. Session stays attached.\n", style.Bold.Render("✓"))
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -119,7 +119,7 @@ func init() {
|
||||
swarmCreateCmd.Flags().StringSliceVar(&swarmWorkers, "worker", nil, "Polecat names to assign (repeatable)")
|
||||
swarmCreateCmd.Flags().BoolVar(&swarmStart, "start", false, "Start swarm immediately after creation")
|
||||
swarmCreateCmd.Flags().StringVar(&swarmTarget, "target", "main", "Target branch for landing")
|
||||
swarmCreateCmd.MarkFlagRequired("epic")
|
||||
_ = swarmCreateCmd.MarkFlagRequired("epic")
|
||||
|
||||
// Status flags
|
||||
swarmStatusCmd.Flags().BoolVar(&swarmStatusJSON, "json", false, "Output as JSON")
|
||||
@@ -605,8 +605,8 @@ func runSwarmLand(cmd *cobra.Command, args []string) error {
|
||||
// Create manager and land
|
||||
mgr := swarm.NewManager(foundRig)
|
||||
// Reload swarm into manager
|
||||
mgr.Create(sw.EpicID, sw.Workers, sw.TargetBranch)
|
||||
mgr.UpdateState(sw.ID, sw.State)
|
||||
_, _ = mgr.Create(sw.EpicID, sw.Workers, sw.TargetBranch)
|
||||
_ = mgr.UpdateState(sw.ID, sw.State)
|
||||
|
||||
fmt.Printf("Landing swarm %s to %s...\n", swarmID, sw.TargetBranch)
|
||||
|
||||
|
||||
@@ -81,11 +81,11 @@ func (m *Manager) Add(name string, createBranch bool) (*CrewWorker, error) {
|
||||
if createBranch {
|
||||
branchName = fmt.Sprintf("crew/%s", name)
|
||||
if err := crewGit.CreateBranch(branchName); err != nil {
|
||||
os.RemoveAll(crewPath)
|
||||
_ = os.RemoveAll(crewPath)
|
||||
return nil, fmt.Errorf("creating branch: %w", err)
|
||||
}
|
||||
if err := crewGit.Checkout(branchName); err != nil {
|
||||
os.RemoveAll(crewPath)
|
||||
_ = os.RemoveAll(crewPath)
|
||||
return nil, fmt.Errorf("checking out branch: %w", err)
|
||||
}
|
||||
}
|
||||
@@ -93,13 +93,13 @@ func (m *Manager) Add(name string, createBranch bool) (*CrewWorker, error) {
|
||||
// Create mail directory for mail delivery
|
||||
mailPath := m.mailDir(name)
|
||||
if err := os.MkdirAll(mailPath, 0755); err != nil {
|
||||
os.RemoveAll(crewPath)
|
||||
_ = os.RemoveAll(crewPath)
|
||||
return nil, fmt.Errorf("creating mail dir: %w", err)
|
||||
}
|
||||
|
||||
// Create CLAUDE.md with crew worker prompting
|
||||
if err := m.createClaudeMD(name, crewPath); err != nil {
|
||||
os.RemoveAll(crewPath)
|
||||
_ = os.RemoveAll(crewPath)
|
||||
return nil, fmt.Errorf("creating CLAUDE.md: %w", err)
|
||||
}
|
||||
|
||||
@@ -116,7 +116,7 @@ func (m *Manager) Add(name string, createBranch bool) (*CrewWorker, error) {
|
||||
|
||||
// Save state
|
||||
if err := m.saveState(crew); err != nil {
|
||||
os.RemoveAll(crewPath)
|
||||
_ = os.RemoveAll(crewPath)
|
||||
return nil, fmt.Errorf("saving state: %w", err)
|
||||
}
|
||||
|
||||
@@ -297,7 +297,7 @@ func (m *Manager) Rename(oldName, newName string) error {
|
||||
crew, err := m.loadState(newName)
|
||||
if err != nil {
|
||||
// Rollback on error
|
||||
os.Rename(newPath, oldPath)
|
||||
_ = os.Rename(newPath, oldPath)
|
||||
return fmt.Errorf("loading state: %w", err)
|
||||
}
|
||||
|
||||
@@ -307,7 +307,7 @@ func (m *Manager) Rename(oldName, newName string) error {
|
||||
|
||||
if err := m.saveState(crew); err != nil {
|
||||
// Rollback on error
|
||||
os.Rename(newPath, oldPath)
|
||||
_ = os.Rename(newPath, oldPath)
|
||||
return fmt.Errorf("saving state: %w", err)
|
||||
}
|
||||
|
||||
|
||||
@@ -16,7 +16,7 @@ func TestManagerAddAndGet(t *testing.T) {
|
||||
if err != nil {
|
||||
t.Fatalf("failed to create temp dir: %v", err)
|
||||
}
|
||||
defer os.RemoveAll(tmpDir)
|
||||
defer func() { _ = os.RemoveAll(tmpDir) }()
|
||||
|
||||
// Create a mock rig
|
||||
rigPath := filepath.Join(tmpDir, "test-rig")
|
||||
@@ -107,7 +107,7 @@ func TestManagerAddWithBranch(t *testing.T) {
|
||||
if err != nil {
|
||||
t.Fatalf("failed to create temp dir: %v", err)
|
||||
}
|
||||
defer os.RemoveAll(tmpDir)
|
||||
defer func() { _ = os.RemoveAll(tmpDir) }()
|
||||
|
||||
// Create a mock rig
|
||||
rigPath := filepath.Join(tmpDir, "test-rig")
|
||||
@@ -176,7 +176,7 @@ func TestManagerList(t *testing.T) {
|
||||
if err != nil {
|
||||
t.Fatalf("failed to create temp dir: %v", err)
|
||||
}
|
||||
defer os.RemoveAll(tmpDir)
|
||||
defer func() { _ = os.RemoveAll(tmpDir) }()
|
||||
|
||||
// Create a mock rig
|
||||
rigPath := filepath.Join(tmpDir, "test-rig")
|
||||
@@ -234,7 +234,7 @@ func TestManagerRemove(t *testing.T) {
|
||||
if err != nil {
|
||||
t.Fatalf("failed to create temp dir: %v", err)
|
||||
}
|
||||
defer os.RemoveAll(tmpDir)
|
||||
defer func() { _ = os.RemoveAll(tmpDir) }()
|
||||
|
||||
// Create a mock rig
|
||||
rigPath := filepath.Join(tmpDir, "test-rig")
|
||||
|
||||
@@ -61,7 +61,7 @@ func (d *Daemon) Run() error {
|
||||
if err := os.WriteFile(d.config.PidFile, []byte(strconv.Itoa(os.Getpid())), 0644); err != nil {
|
||||
return fmt.Errorf("writing PID file: %w", err)
|
||||
}
|
||||
defer os.Remove(d.config.PidFile)
|
||||
defer func() { _ = os.Remove(d.config.PidFile) }()
|
||||
|
||||
// Update state
|
||||
state := &State{
|
||||
@@ -312,7 +312,7 @@ func IsRunning(townRoot string) (bool, int, error) {
|
||||
err = process.Signal(syscall.Signal(0))
|
||||
if err != nil {
|
||||
// Process not running, clean up stale PID file
|
||||
os.Remove(pidFile)
|
||||
_ = os.Remove(pidFile)
|
||||
return false, 0, nil
|
||||
}
|
||||
|
||||
@@ -345,12 +345,12 @@ func StopDaemon(townRoot string) error {
|
||||
// Check if still running
|
||||
if err := process.Signal(syscall.Signal(0)); err == nil {
|
||||
// Still running, force kill
|
||||
process.Signal(syscall.SIGKILL)
|
||||
_ = process.Signal(syscall.SIGKILL)
|
||||
}
|
||||
|
||||
// Clean up PID file
|
||||
pidFile := filepath.Join(townRoot, "daemon", "daemon.pid")
|
||||
os.Remove(pidFile)
|
||||
_ = os.Remove(pidFile)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -196,7 +196,7 @@ func (d *Daemon) restartSession(sessionName, identity string) error {
|
||||
}
|
||||
|
||||
// Set environment
|
||||
d.tmux.SetEnvironment(sessionName, "GT_ROLE", identity)
|
||||
_ = d.tmux.SetEnvironment(sessionName, "GT_ROLE", identity)
|
||||
|
||||
// Send startup command
|
||||
if err := d.tmux.SendKeys(sessionName, startCmd); err != nil {
|
||||
|
||||
@@ -141,7 +141,7 @@ func (r *Report) Print(w io.Writer, verbose bool) {
|
||||
}
|
||||
|
||||
// Print summary
|
||||
fmt.Fprintln(w)
|
||||
_, _ = fmt.Fprintln(w)
|
||||
r.printSummary(w)
|
||||
}
|
||||
|
||||
@@ -157,18 +157,18 @@ func (r *Report) printCheck(w io.Writer, check *CheckResult, verbose bool) {
|
||||
prefix = style.ErrorPrefix
|
||||
}
|
||||
|
||||
fmt.Fprintf(w, "%s %s: %s\n", prefix, check.Name, check.Message)
|
||||
_, _ = fmt.Fprintf(w, "%s %s: %s\n", prefix, check.Name, check.Message)
|
||||
|
||||
// Print details in verbose mode or for non-OK results
|
||||
if len(check.Details) > 0 && (verbose || check.Status != StatusOK) {
|
||||
for _, detail := range check.Details {
|
||||
fmt.Fprintf(w, " %s\n", detail)
|
||||
_, _ = fmt.Fprintf(w, " %s\n", detail)
|
||||
}
|
||||
}
|
||||
|
||||
// Print fix hint for errors/warnings
|
||||
if check.FixHint != "" && check.Status != StatusOK {
|
||||
fmt.Fprintf(w, " %s %s\n", style.ArrowPrefix, check.FixHint)
|
||||
_, _ = fmt.Fprintf(w, " %s %s\n", style.ArrowPrefix, check.FixHint)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -188,5 +188,5 @@ func (r *Report) printSummary(w io.Writer) {
|
||||
parts = append(parts, style.Error.Render(fmt.Sprintf("%d errors", r.Summary.Errors)))
|
||||
}
|
||||
|
||||
fmt.Fprintln(w, strings.Join(parts, ", "))
|
||||
_, _ = fmt.Fprintln(w, strings.Join(parts, ", "))
|
||||
}
|
||||
|
||||
@@ -251,24 +251,24 @@ func (g *Git) CheckConflicts(source, target string) ([]string, error) {
|
||||
conflicts, err := g.getConflictingFiles()
|
||||
if err == nil && len(conflicts) > 0 {
|
||||
// Abort the test merge
|
||||
g.AbortMerge()
|
||||
_ = g.AbortMerge()
|
||||
return conflicts, nil
|
||||
}
|
||||
|
||||
// Check if it's a conflict error from wrapper
|
||||
if errors.Is(mergeErr, ErrMergeConflict) {
|
||||
g.AbortMerge()
|
||||
_ = g.AbortMerge()
|
||||
return conflicts, nil
|
||||
}
|
||||
|
||||
// Some other merge error
|
||||
g.AbortMerge()
|
||||
_ = g.AbortMerge()
|
||||
return nil, mergeErr
|
||||
}
|
||||
|
||||
// Merge succeeded (no conflicts) - abort the test merge
|
||||
// Use reset since --abort won't work on successful merge
|
||||
g.run("reset", "--hard", "HEAD")
|
||||
_, _ = g.run("reset", "--hard", "HEAD")
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
|
||||
@@ -21,10 +21,10 @@ func initTestRepo(t *testing.T) string {
|
||||
// Configure user for commits
|
||||
cmd = exec.Command("git", "config", "user.email", "test@test.com")
|
||||
cmd.Dir = dir
|
||||
cmd.Run()
|
||||
_ = cmd.Run()
|
||||
cmd = exec.Command("git", "config", "user.name", "Test User")
|
||||
cmd.Dir = dir
|
||||
cmd.Run()
|
||||
_ = cmd.Run()
|
||||
|
||||
// Create initial commit
|
||||
testFile := filepath.Join(dir, "README.md")
|
||||
@@ -33,10 +33,10 @@ func initTestRepo(t *testing.T) string {
|
||||
}
|
||||
cmd = exec.Command("git", "add", ".")
|
||||
cmd.Dir = dir
|
||||
cmd.Run()
|
||||
_ = cmd.Run()
|
||||
cmd = exec.Command("git", "commit", "-m", "initial")
|
||||
cmd.Dir = dir
|
||||
cmd.Run()
|
||||
_ = cmd.Run()
|
||||
|
||||
return dir
|
||||
}
|
||||
|
||||
@@ -93,7 +93,7 @@ func (m *Mailbox) listBeads() ([]*Message, error) {
|
||||
var beadsMsgs []BeadsMessage
|
||||
if err := json.Unmarshal(stdout.Bytes(), &beadsMsgs); err != nil {
|
||||
// Empty inbox returns empty array or nothing
|
||||
if len(stdout.Bytes()) == 0 || string(stdout.Bytes()) == "null" {
|
||||
if len(stdout.Bytes()) == 0 || stdout.String() == "null" {
|
||||
return nil, nil
|
||||
}
|
||||
return nil, err
|
||||
@@ -116,7 +116,7 @@ func (m *Mailbox) listLegacy() ([]*Message, error) {
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
defer file.Close()
|
||||
defer func() { _ = file.Close() }()
|
||||
|
||||
var messages []*Message
|
||||
scanner := bufio.NewScanner(file)
|
||||
@@ -336,7 +336,7 @@ func (m *Mailbox) appendLegacy(msg *Message) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer file.Close()
|
||||
defer func() { _ = file.Close() }()
|
||||
|
||||
data, err := json.Marshal(msg)
|
||||
if err != nil {
|
||||
@@ -364,15 +364,15 @@ func (m *Mailbox) rewriteLegacy(messages []*Message) error {
|
||||
for _, msg := range messages {
|
||||
data, err := json.Marshal(msg)
|
||||
if err != nil {
|
||||
file.Close()
|
||||
os.Remove(tmpPath)
|
||||
_ = file.Close()
|
||||
_ = os.Remove(tmpPath)
|
||||
return err
|
||||
}
|
||||
file.WriteString(string(data) + "\n")
|
||||
_, _ = file.WriteString(string(data) + "\n")
|
||||
}
|
||||
|
||||
if err := file.Close(); err != nil {
|
||||
os.Remove(tmpPath)
|
||||
_ = os.Remove(tmpPath)
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -408,7 +408,7 @@ func (m *Mailbox) listByThreadBeads(threadID string) ([]*Message, error) {
|
||||
|
||||
var beadsMsgs []BeadsMessage
|
||||
if err := json.Unmarshal(stdout.Bytes(), &beadsMsgs); err != nil {
|
||||
if len(stdout.Bytes()) == 0 || string(stdout.Bytes()) == "null" {
|
||||
if len(stdout.Bytes()) == 0 || stdout.String() == "null" {
|
||||
return nil, nil
|
||||
}
|
||||
return nil, err
|
||||
|
||||
@@ -72,7 +72,7 @@ func (r *Router) Send(msg *Message) error {
|
||||
}
|
||||
|
||||
// Notify recipient if they have an active session
|
||||
r.notifyRecipient(msg)
|
||||
_ = r.notifyRecipient(msg)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -114,14 +114,14 @@ func NewReplyMessage(from, to, subject, body string, original *Message) *Message
|
||||
// generateID creates a random message ID.
|
||||
func generateID() string {
|
||||
b := make([]byte, 8)
|
||||
rand.Read(b)
|
||||
_, _ = rand.Read(b)
|
||||
return "msg-" + hex.EncodeToString(b)
|
||||
}
|
||||
|
||||
// generateThreadID creates a random thread ID.
|
||||
func generateThreadID() string {
|
||||
b := make([]byte, 6)
|
||||
rand.Read(b)
|
||||
_, _ = rand.Read(b)
|
||||
return "thread-" + hex.EncodeToString(b)
|
||||
}
|
||||
|
||||
|
||||
@@ -22,7 +22,7 @@ import (
|
||||
func GenerateMRID(prefix, branch string) string {
|
||||
// Generate 8 random bytes for additional uniqueness
|
||||
randomBytes := make([]byte, 8)
|
||||
rand.Read(randomBytes)
|
||||
_, _ = rand.Read(randomBytes)
|
||||
|
||||
return generateMRIDInternal(prefix, branch, time.Now(), randomBytes)
|
||||
}
|
||||
|
||||
@@ -109,7 +109,7 @@ func (m *Manager) Add(name string) (*Polecat, error) {
|
||||
// Save state
|
||||
if err := m.saveState(polecat); err != nil {
|
||||
// Clean up worktree on failure
|
||||
mayorGit.WorktreeRemove(polecatPath, true)
|
||||
_ = mayorGit.WorktreeRemove(polecatPath, true)
|
||||
return nil, fmt.Errorf("saving state: %w", err)
|
||||
}
|
||||
|
||||
@@ -148,7 +148,7 @@ func (m *Manager) Remove(name string, force bool) error {
|
||||
}
|
||||
|
||||
// Prune any stale worktree entries
|
||||
mayorGit.WorktreePrune()
|
||||
_ = mayorGit.WorktreePrune()
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -36,7 +36,7 @@ func TestEngineer_LoadConfig_NoFile(t *testing.T) {
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer os.RemoveAll(tmpDir)
|
||||
defer func() { _ = os.RemoveAll(tmpDir) }()
|
||||
|
||||
r := &rig.Rig{
|
||||
Name: "test-rig",
|
||||
@@ -62,7 +62,7 @@ func TestEngineer_LoadConfig_WithMergeQueue(t *testing.T) {
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer os.RemoveAll(tmpDir)
|
||||
defer func() { _ = os.RemoveAll(tmpDir) }()
|
||||
|
||||
// Write config file
|
||||
config := map[string]interface{}{
|
||||
@@ -124,7 +124,7 @@ func TestEngineer_LoadConfig_NoMergeQueueSection(t *testing.T) {
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer os.RemoveAll(tmpDir)
|
||||
defer func() { _ = os.RemoveAll(tmpDir) }()
|
||||
|
||||
// Write config file without merge_queue
|
||||
config := map[string]interface{}{
|
||||
@@ -160,7 +160,7 @@ func TestEngineer_LoadConfig_InvalidPollInterval(t *testing.T) {
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer os.RemoveAll(tmpDir)
|
||||
defer func() { _ = os.RemoveAll(tmpDir) }()
|
||||
|
||||
config := map[string]interface{}{
|
||||
"merge_queue": map[string]interface{}{
|
||||
|
||||
@@ -105,7 +105,7 @@ func (m *Manager) Status() (*Refinery, error) {
|
||||
if ref.StartedAt == nil {
|
||||
ref.StartedAt = &now
|
||||
}
|
||||
m.saveState(ref)
|
||||
_ = m.saveState(ref)
|
||||
}
|
||||
return ref, nil
|
||||
}
|
||||
@@ -119,7 +119,7 @@ func (m *Manager) Status() (*Refinery, error) {
|
||||
// Neither session nor process exists - mark as stopped
|
||||
ref.State = StateStopped
|
||||
ref.PID = 0
|
||||
m.saveState(ref)
|
||||
_ = m.saveState(ref)
|
||||
}
|
||||
|
||||
return ref, nil
|
||||
@@ -168,15 +168,15 @@ func (m *Manager) Start(foreground bool) error {
|
||||
}
|
||||
|
||||
// Set environment variables
|
||||
t.SetEnvironment(sessionID, "GT_RIG", m.rig.Name)
|
||||
t.SetEnvironment(sessionID, "GT_REFINERY", "1")
|
||||
_ = t.SetEnvironment(sessionID, "GT_RIG", m.rig.Name)
|
||||
_ = t.SetEnvironment(sessionID, "GT_REFINERY", "1")
|
||||
|
||||
// Send the command to start refinery in foreground mode
|
||||
// The foreground mode handles state updates and the processing loop
|
||||
command := fmt.Sprintf("gt refinery start %s --foreground", m.rig.Name)
|
||||
if err := t.SendKeys(sessionID, command); err != nil {
|
||||
// Clean up the session on failure
|
||||
t.KillSession(sessionID)
|
||||
_ = t.KillSession(sessionID)
|
||||
return fmt.Errorf("starting refinery: %w", err)
|
||||
}
|
||||
|
||||
@@ -202,14 +202,14 @@ func (m *Manager) Stop() error {
|
||||
|
||||
// Kill tmux session if it exists
|
||||
if sessionRunning {
|
||||
t.KillSession(sessionID)
|
||||
_ = t.KillSession(sessionID)
|
||||
}
|
||||
|
||||
// If we have a PID and it's a different process, try to stop it gracefully
|
||||
if ref.PID > 0 && ref.PID != os.Getpid() && processExists(ref.PID) {
|
||||
// Send SIGTERM
|
||||
if proc, err := os.FindProcess(ref.PID); err == nil {
|
||||
proc.Signal(os.Interrupt)
|
||||
_ = proc.Signal(os.Interrupt)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -321,15 +321,13 @@ func (m *Manager) run(ref *Refinery) error {
|
||||
ticker := time.NewTicker(10 * time.Second)
|
||||
defer ticker.Stop()
|
||||
|
||||
for {
|
||||
select {
|
||||
case <-ticker.C:
|
||||
// Process queue
|
||||
if err := m.ProcessQueue(); err != nil {
|
||||
fmt.Printf("Queue processing error: %v\n", err)
|
||||
}
|
||||
for range ticker.C {
|
||||
// Process queue
|
||||
if err := m.ProcessQueue(); err != nil {
|
||||
fmt.Printf("Queue processing error: %v\n", err)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// ProcessQueue processes all pending merge requests.
|
||||
@@ -376,7 +374,7 @@ func (m *Manager) ProcessMR(mr *MergeRequest) MergeResult {
|
||||
return MergeResult{Error: fmt.Sprintf("cannot claim MR: %v", err)}
|
||||
}
|
||||
ref.CurrentMR = mr
|
||||
m.saveState(ref)
|
||||
_ = m.saveState(ref)
|
||||
|
||||
result := MergeResult{}
|
||||
|
||||
@@ -395,7 +393,7 @@ func (m *Manager) ProcessMR(mr *MergeRequest) MergeResult {
|
||||
}
|
||||
|
||||
// Pull latest
|
||||
m.gitRun("pull", "origin", mr.TargetBranch) // Ignore errors
|
||||
_ = m.gitRun("pull", "origin", mr.TargetBranch) // Ignore errors
|
||||
|
||||
// 3. Merge
|
||||
err := m.gitRun("merge", "--no-ff", "-m",
|
||||
@@ -408,7 +406,7 @@ func (m *Manager) ProcessMR(mr *MergeRequest) MergeResult {
|
||||
result.Conflict = true
|
||||
result.Error = "merge conflict"
|
||||
// Abort the merge
|
||||
m.gitRun("merge", "--abort")
|
||||
_ = m.gitRun("merge", "--abort")
|
||||
m.completeMR(mr, "", "merge conflict - polecat must rebase") // Reopen for rebase
|
||||
// Notify worker about conflict
|
||||
m.notifyWorkerConflict(mr)
|
||||
@@ -425,7 +423,7 @@ func (m *Manager) ProcessMR(mr *MergeRequest) MergeResult {
|
||||
result.TestsFailed = true
|
||||
result.Error = fmt.Sprintf("tests failed: %v", err)
|
||||
// Reset to before merge
|
||||
m.gitRun("reset", "--hard", "HEAD~1")
|
||||
_ = m.gitRun("reset", "--hard", "HEAD~1")
|
||||
m.completeMR(mr, "", result.Error) // Reopen for fixes
|
||||
return result
|
||||
}
|
||||
@@ -435,7 +433,7 @@ func (m *Manager) ProcessMR(mr *MergeRequest) MergeResult {
|
||||
if err := m.pushWithRetry(mr.TargetBranch, config); err != nil {
|
||||
result.Error = fmt.Sprintf("push failed: %v", err)
|
||||
// Reset to before merge
|
||||
m.gitRun("reset", "--hard", "HEAD~1")
|
||||
_ = m.gitRun("reset", "--hard", "HEAD~1")
|
||||
m.completeMR(mr, "", result.Error) // Reopen for retry
|
||||
return result
|
||||
}
|
||||
@@ -456,7 +454,7 @@ func (m *Manager) ProcessMR(mr *MergeRequest) MergeResult {
|
||||
|
||||
// Optionally delete the merged branch
|
||||
if config.DeleteMergedBranches {
|
||||
m.gitRun("push", "origin", "--delete", mr.Branch)
|
||||
_ = m.gitRun("push", "origin", "--delete", mr.Branch)
|
||||
}
|
||||
|
||||
return result
|
||||
@@ -500,7 +498,7 @@ func (m *Manager) completeMR(mr *MergeRequest, closeReason CloseReason, errMsg s
|
||||
ref.Stats.TodayFailed++
|
||||
}
|
||||
|
||||
m.saveState(ref)
|
||||
_ = m.saveState(ref)
|
||||
}
|
||||
|
||||
// getTestCommand returns the test command if configured.
|
||||
@@ -689,7 +687,7 @@ Then the Refinery will retry the merge.`,
|
||||
mr.Branch, mr.TargetBranch, mr.TargetBranch),
|
||||
Priority: mail.PriorityHigh,
|
||||
}
|
||||
router.Send(msg)
|
||||
_ = router.Send(msg)
|
||||
}
|
||||
|
||||
// notifyWorkerMerged sends a success notification to a polecat.
|
||||
@@ -705,7 +703,7 @@ Issue: %s
|
||||
Thank you for your contribution!`,
|
||||
mr.Branch, mr.TargetBranch, mr.IssueID),
|
||||
}
|
||||
router.Send(msg)
|
||||
_ = router.Send(msg)
|
||||
}
|
||||
|
||||
// Common errors for MR operations
|
||||
@@ -865,7 +863,7 @@ Please review the feedback and address the issues before resubmitting.`,
|
||||
mr.Branch, mr.IssueID, reason),
|
||||
Priority: mail.PriorityNormal,
|
||||
}
|
||||
router.Send(msg)
|
||||
_ = router.Send(msg)
|
||||
}
|
||||
|
||||
// findTownRoot walks up directories to find the town root.
|
||||
|
||||
@@ -194,7 +194,7 @@ func (m *Manager) AddRig(opts AddRigOptions) (*Rig, error) {
|
||||
}
|
||||
|
||||
// Track cleanup on failure
|
||||
cleanup := func() { os.RemoveAll(rigPath) }
|
||||
cleanup := func() { _ = os.RemoveAll(rigPath) }
|
||||
success := false
|
||||
defer func() {
|
||||
if !success {
|
||||
|
||||
@@ -120,8 +120,8 @@ func (m *Manager) Start(polecat string, opts StartOptions) error {
|
||||
}
|
||||
|
||||
// Set environment
|
||||
m.tmux.SetEnvironment(sessionID, "GT_RIG", m.rig.Name)
|
||||
m.tmux.SetEnvironment(sessionID, "GT_POLECAT", polecat)
|
||||
_ = m.tmux.SetEnvironment(sessionID, "GT_RIG", m.rig.Name)
|
||||
_ = m.tmux.SetEnvironment(sessionID, "GT_POLECAT", polecat)
|
||||
|
||||
// Send initial command
|
||||
command := opts.Command
|
||||
@@ -137,9 +137,7 @@ func (m *Manager) Start(polecat string, opts StartOptions) error {
|
||||
if opts.Issue != "" {
|
||||
time.Sleep(500 * time.Millisecond)
|
||||
prompt := fmt.Sprintf("Work on issue: %s", opts.Issue)
|
||||
if err := m.Inject(polecat, prompt); err != nil {
|
||||
// Non-fatal, just log
|
||||
}
|
||||
_ = m.Inject(polecat, prompt) // Non-fatal error
|
||||
}
|
||||
|
||||
return nil
|
||||
@@ -161,7 +159,7 @@ func (m *Manager) Stop(polecat string, force bool) error {
|
||||
|
||||
// Try graceful shutdown first (unless forced)
|
||||
if !force {
|
||||
m.tmux.SendKeysRaw(sessionID, "C-c") // Ctrl+C
|
||||
_ = m.tmux.SendKeysRaw(sessionID, "C-c") // Ctrl+C
|
||||
time.Sleep(100 * time.Millisecond)
|
||||
}
|
||||
|
||||
|
||||
@@ -37,9 +37,7 @@ func (m *Manager) CreateIntegrationBranch(swarmID string) error {
|
||||
}
|
||||
|
||||
// Push to origin
|
||||
if err := m.gitRun("push", "-u", "origin", branchName); err != nil {
|
||||
// Non-fatal - may not have remote
|
||||
}
|
||||
_ = m.gitRun("push", "-u", "origin", branchName) // Non-fatal - may not have remote
|
||||
|
||||
return nil
|
||||
}
|
||||
@@ -64,9 +62,7 @@ func (m *Manager) MergeToIntegration(swarmID, workerBranch string) error {
|
||||
}
|
||||
|
||||
// Fetch the worker branch
|
||||
if err := m.gitRun("fetch", "origin", workerBranch); err != nil {
|
||||
// May not exist on remote, try local
|
||||
}
|
||||
_ = m.gitRun("fetch", "origin", workerBranch) // May not exist on remote, try local
|
||||
|
||||
// Attempt merge
|
||||
err = m.gitRun("merge", "--no-ff", "-m",
|
||||
@@ -102,7 +98,7 @@ func (m *Manager) LandToMain(swarmID string) error {
|
||||
}
|
||||
|
||||
// Pull latest
|
||||
m.gitRun("pull", "origin", swarm.TargetBranch) // Ignore errors
|
||||
_ = m.gitRun("pull", "origin", swarm.TargetBranch) // Ignore errors
|
||||
|
||||
// Merge integration branch
|
||||
err := m.gitRun("merge", "--no-ff", "-m",
|
||||
@@ -138,15 +134,15 @@ func (m *Manager) CleanupBranches(swarmID string) error {
|
||||
}
|
||||
|
||||
// Delete integration branch remotely
|
||||
m.gitRun("push", "origin", "--delete", swarm.Integration) // Ignore errors
|
||||
_ = m.gitRun("push", "origin", "--delete", swarm.Integration) // Ignore errors
|
||||
|
||||
// Delete worker branches
|
||||
for _, task := range swarm.Tasks {
|
||||
if task.Branch != "" {
|
||||
// Local delete
|
||||
m.gitRun("branch", "-D", task.Branch)
|
||||
_ = m.gitRun("branch", "-D", task.Branch)
|
||||
// Remote delete
|
||||
m.gitRun("push", "origin", "--delete", task.Branch)
|
||||
_ = m.gitRun("push", "origin", "--delete", task.Branch)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -210,7 +210,7 @@ Manual intervention required.`,
|
||||
swarmID, strings.Join(workers, "\n- ")),
|
||||
Priority: mail.PriorityHigh,
|
||||
}
|
||||
router.Send(msg)
|
||||
_ = router.Send(msg)
|
||||
}
|
||||
|
||||
// notifyMayorLanded sends a landing report to Mayor.
|
||||
@@ -233,5 +233,5 @@ Tasks merged: %d`,
|
||||
result.BranchesCleaned,
|
||||
len(swarm.Tasks)),
|
||||
}
|
||||
router.Send(msg)
|
||||
_ = router.Send(msg)
|
||||
}
|
||||
|
||||
@@ -94,7 +94,7 @@ func TestManagerCancel(t *testing.T) {
|
||||
m := NewManager(r)
|
||||
|
||||
swarm, _ := m.Create("epic-1", []string{"Toast"}, "main")
|
||||
m.Start(swarm.ID)
|
||||
_ = m.Start(swarm.ID)
|
||||
|
||||
if err := m.Cancel(swarm.ID, "user requested"); err != nil {
|
||||
t.Errorf("Cancel failed: %v", err)
|
||||
@@ -179,7 +179,7 @@ func TestManagerIsComplete(t *testing.T) {
|
||||
}
|
||||
|
||||
// Complete the pending task
|
||||
m.UpdateTaskState(swarm.ID, "task-1", TaskMerged)
|
||||
_ = m.UpdateTaskState(swarm.ID, "task-1", TaskMerged)
|
||||
complete, _ = m.IsComplete(swarm.ID)
|
||||
if !complete {
|
||||
t.Error("IsComplete should be true when all tasks merged")
|
||||
|
||||
@@ -260,7 +260,7 @@ func (t *Tmux) GetSessionInfo(name string) (*SessionInfo, error) {
|
||||
}
|
||||
|
||||
windows := 0
|
||||
fmt.Sscanf(parts[1], "%d", &windows)
|
||||
_, _ = fmt.Sscanf(parts[1], "%d", &windows)
|
||||
|
||||
return &SessionInfo{
|
||||
Name: parts[0],
|
||||
|
||||
@@ -50,13 +50,13 @@ func TestSessionLifecycle(t *testing.T) {
|
||||
sessionName := "gt-test-session-" + t.Name()
|
||||
|
||||
// Clean up any existing session
|
||||
tm.KillSession(sessionName)
|
||||
_ = tm.KillSession(sessionName)
|
||||
|
||||
// Create session
|
||||
if err := tm.NewSession(sessionName, ""); err != nil {
|
||||
t.Fatalf("NewSession: %v", err)
|
||||
}
|
||||
defer tm.KillSession(sessionName)
|
||||
defer func() { _ = tm.KillSession(sessionName) }()
|
||||
|
||||
// Verify exists
|
||||
has, err := tm.HasSession(sessionName)
|
||||
@@ -107,13 +107,13 @@ func TestDuplicateSession(t *testing.T) {
|
||||
sessionName := "gt-test-dup-" + t.Name()
|
||||
|
||||
// Clean up any existing session
|
||||
tm.KillSession(sessionName)
|
||||
_ = tm.KillSession(sessionName)
|
||||
|
||||
// Create session
|
||||
if err := tm.NewSession(sessionName, ""); err != nil {
|
||||
t.Fatalf("NewSession: %v", err)
|
||||
}
|
||||
defer tm.KillSession(sessionName)
|
||||
defer func() { _ = tm.KillSession(sessionName) }()
|
||||
|
||||
// Try to create duplicate
|
||||
err := tm.NewSession(sessionName, "")
|
||||
@@ -131,13 +131,13 @@ func TestSendKeysAndCapture(t *testing.T) {
|
||||
sessionName := "gt-test-keys-" + t.Name()
|
||||
|
||||
// Clean up any existing session
|
||||
tm.KillSession(sessionName)
|
||||
_ = tm.KillSession(sessionName)
|
||||
|
||||
// Create session
|
||||
if err := tm.NewSession(sessionName, ""); err != nil {
|
||||
t.Fatalf("NewSession: %v", err)
|
||||
}
|
||||
defer tm.KillSession(sessionName)
|
||||
defer func() { _ = tm.KillSession(sessionName) }()
|
||||
|
||||
// Send echo command
|
||||
if err := tm.SendKeys(sessionName, "echo HELLO_TEST_MARKER"); err != nil {
|
||||
@@ -167,13 +167,13 @@ func TestGetSessionInfo(t *testing.T) {
|
||||
sessionName := "gt-test-info-" + t.Name()
|
||||
|
||||
// Clean up any existing session
|
||||
tm.KillSession(sessionName)
|
||||
_ = tm.KillSession(sessionName)
|
||||
|
||||
// Create session
|
||||
if err := tm.NewSession(sessionName, ""); err != nil {
|
||||
t.Fatalf("NewSession: %v", err)
|
||||
}
|
||||
defer tm.KillSession(sessionName)
|
||||
defer func() { _ = tm.KillSession(sessionName) }()
|
||||
|
||||
info, err := tm.GetSessionInfo(sessionName)
|
||||
if err != nil {
|
||||
|
||||
@@ -92,7 +92,7 @@ func (m *Manager) Status() (*Witness, error) {
|
||||
if !processExists(w.PID) {
|
||||
w.State = StateStopped
|
||||
w.PID = 0
|
||||
m.saveState(w)
|
||||
_ = m.saveState(w)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -150,7 +150,7 @@ func (m *Manager) Stop() error {
|
||||
if w.PID > 0 && w.PID != os.Getpid() {
|
||||
// Send SIGTERM
|
||||
if proc, err := os.FindProcess(w.PID); err == nil {
|
||||
proc.Signal(os.Interrupt)
|
||||
_ = proc.Signal(os.Interrupt)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -171,12 +171,10 @@ func (m *Manager) run(w *Witness) error {
|
||||
ticker := time.NewTicker(30 * time.Second)
|
||||
defer ticker.Stop()
|
||||
|
||||
for {
|
||||
select {
|
||||
case <-ticker.C:
|
||||
m.checkAndProcess(w)
|
||||
}
|
||||
for range ticker.C {
|
||||
m.checkAndProcess(w)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// checkAndProcess performs health check and processes shutdown requests.
|
||||
@@ -289,7 +287,7 @@ func (m *Manager) getWitnessMessages() ([]WitnessMessage, error) {
|
||||
func (m *Manager) ackMessage(id string) {
|
||||
cmd := exec.Command("bd", "mail", "ack", id)
|
||||
cmd.Dir = m.workDir
|
||||
cmd.Run() // Ignore errors
|
||||
_ = cmd.Run() // Ignore errors
|
||||
}
|
||||
|
||||
// extractPolecatName extracts the polecat name from a lifecycle request body.
|
||||
|
||||
Reference in New Issue
Block a user