diff --git a/cmd/goose/main.go b/cmd/goose/main.go index 0323238..5ea060b 100644 --- a/cmd/goose/main.go +++ b/cmd/goose/main.go @@ -39,7 +39,7 @@ const ( maxPRsToProcess = 200 minUpdateInterval = 10 * time.Second defaultUpdateInterval = 1 * time.Minute - blockedPRIconDuration = 5 * time.Minute + blockedPRIconDuration = 15 * time.Minute maxRetryDelay = 2 * time.Minute maxRetries = 10 minorFailureThreshold = 3 diff --git a/cmd/goose/main_test.go b/cmd/goose/main_test.go index 3016b90..8615c32 100644 --- a/cmd/goose/main_test.go +++ b/cmd/goose/main_test.go @@ -9,6 +9,8 @@ import ( "sync" "testing" "time" + + "github.com/codeGROOVE-dev/turnclient/pkg/turn" ) func TestMain(m *testing.M) { @@ -198,7 +200,7 @@ func TestMenuItemTitleTransition(t *testing.T) { _ = ctx // Unused in this test but would be used for real menu operations } -// TestWorkflowStateNewlyPublished tests that PRs with NEWLY_PUBLISHED workflow state get "- NEW!" suffix. +// TestWorkflowStateNewlyPublished tests that PRs with NEWLY_PUBLISHED workflow state get a 💎 bullet. func TestWorkflowStateNewlyPublished(t *testing.T) { tests := []struct { name string @@ -211,21 +213,21 @@ func TestWorkflowStateNewlyPublished(t *testing.T) { Repository: "test/repo", Number: 123, ActionKind: "review", - WorkflowState: "NEWLY_PUBLISHED", + WorkflowState: string(turn.StateNewlyPublished), NeedsReview: true, UpdatedAt: time.Now(), }, - expectedTitle: "■ test/repo #123 — review - NEW!", + expectedTitle: "💎 test/repo #123 — review", }, { name: "newly_published_without_action", pr: PR{ Repository: "test/repo", Number: 456, - WorkflowState: "NEWLY_PUBLISHED", + WorkflowState: string(turn.StateNewlyPublished), UpdatedAt: time.Now(), }, - expectedTitle: "test/repo #456 - NEW!", + expectedTitle: "💎 test/repo #456", }, { name: "newly_published_with_running_tests", @@ -233,10 +235,10 @@ func TestWorkflowStateNewlyPublished(t *testing.T) { Repository: "test/repo", Number: 789, TestState: "running", - WorkflowState: "NEWLY_PUBLISHED", + WorkflowState: string(turn.StateNewlyPublished), UpdatedAt: time.Now(), }, - expectedTitle: "test/repo #789 — tests running... - NEW!", + expectedTitle: "💎 test/repo #789 — tests running...", }, { name: "not_newly_published_with_action", @@ -266,13 +268,11 @@ func TestWorkflowStateNewlyPublished(t *testing.T) { title = fmt.Sprintf("%s — tests running...", title) } - // Add "- NEW!" suffix if workflow state is NEWLY_PUBLISHED - if pr.WorkflowState == "NEWLY_PUBLISHED" { - title = fmt.Sprintf("%s - NEW!", title) - } - - // Add prefix based on blocked status - if pr.NeedsReview || pr.IsBlocked { + // Add prefix based on workflow state or blocked status + switch { + case pr.WorkflowState == string(turn.StateNewlyPublished): + title = fmt.Sprintf("💎 %s", title) + case pr.NeedsReview || pr.IsBlocked: title = fmt.Sprintf("■ %s", title) } diff --git a/cmd/goose/ui.go b/cmd/goose/ui.go index e3d464a..916d1bd 100644 --- a/cmd/goose/ui.go +++ b/cmd/goose/ui.go @@ -13,6 +13,7 @@ import ( "strings" "time" + "github.com/codeGROOVE-dev/turnclient/pkg/turn" "github.com/energye/systray" // needed for MenuItem type ) @@ -342,13 +343,12 @@ func (app *App) addPRSection(ctx context.Context, prs []PR, sectionTitle string, title = fmt.Sprintf("%s — tests running...", title) } - // Add "- NEW!" suffix if workflow state is NEWLY_PUBLISHED - if sortedPRs[prIndex].WorkflowState == "NEWLY_PUBLISHED" { - title = fmt.Sprintf("%s - NEW!", title) - } - // Add bullet point or emoji based on PR status - if sortedPRs[prIndex].NeedsReview || sortedPRs[prIndex].IsBlocked { + switch { + case sortedPRs[prIndex].WorkflowState == string(turn.StateNewlyPublished): + // Use gem emoji for newly published PRs + title = fmt.Sprintf("💎 %s", title) + case sortedPRs[prIndex].NeedsReview || sortedPRs[prIndex].IsBlocked: // Get the blocked time from state manager prState, hasState := app.stateManager.PRState(sortedPRs[prIndex].URL) @@ -358,16 +358,27 @@ func (app *App) addPRSection(ctx context.Context, prs []PR, sectionTitle string, time.Since(prState.FirstBlockedAt) < blockedPRIconDuration && !prState.IsInitialDiscovery { timeSinceBlocked := time.Since(prState.FirstBlockedAt) - // Use party popper for outgoing PRs, goose for incoming PRs + // Use cockroach for fix_tests, party popper for other outgoing PRs, goose for incoming PRs if sectionTitle == "Outgoing" { - title = fmt.Sprintf("🎉 %s", title) - slog.Info("[MENU] Adding party popper to outgoing PR", - "repo", sortedPRs[prIndex].Repository, - "number", sortedPRs[prIndex].Number, - "url", sortedPRs[prIndex].URL, - "firstBlockedAt", prState.FirstBlockedAt.Format(time.RFC3339), - "blocked_ago", timeSinceBlocked.Round(time.Second), - "remaining", (blockedPRIconDuration - timeSinceBlocked).Round(time.Second)) + if sortedPRs[prIndex].ActionKind == "fix_tests" { + title = fmt.Sprintf("🪳 %s", title) + slog.Info("[MENU] Adding cockroach to outgoing PR with broken tests", + "repo", sortedPRs[prIndex].Repository, + "number", sortedPRs[prIndex].Number, + "url", sortedPRs[prIndex].URL, + "firstBlockedAt", prState.FirstBlockedAt.Format(time.RFC3339), + "blocked_ago", timeSinceBlocked.Round(time.Second), + "remaining", (blockedPRIconDuration - timeSinceBlocked).Round(time.Second)) + } else { + title = fmt.Sprintf("🎉 %s", title) + slog.Info("[MENU] Adding party popper to outgoing PR", + "repo", sortedPRs[prIndex].Repository, + "number", sortedPRs[prIndex].Number, + "url", sortedPRs[prIndex].URL, + "firstBlockedAt", prState.FirstBlockedAt.Format(time.RFC3339), + "blocked_ago", timeSinceBlocked.Round(time.Second), + "remaining", (blockedPRIconDuration - timeSinceBlocked).Round(time.Second)) + } } else { title = fmt.Sprintf("🪿 %s", title) slog.Debug("[MENU] Adding goose to incoming PR", @@ -394,9 +405,11 @@ func (app *App) addPRSection(ctx context.Context, prs []PR, sectionTitle string, } } } - } else if sortedPRs[prIndex].ActionKind != "" { + case sortedPRs[prIndex].ActionKind != "": // PR has an action but isn't blocked - add bullet to indicate it could use input title = fmt.Sprintf("• %s", title) + default: + // No special prefix needed } // Format age inline for tooltip duration := time.Since(sortedPRs[prIndex].UpdatedAt) @@ -538,13 +551,12 @@ func (app *App) generatePRSectionTitles(prs []PR, sectionTitle string, hiddenOrg title = fmt.Sprintf("%s — tests running...", title) } - // Add "- NEW!" suffix if workflow state is NEWLY_PUBLISHED - if sortedPRs[prIndex].WorkflowState == "NEWLY_PUBLISHED" { - title = fmt.Sprintf("%s - NEW!", title) - } - // Add bullet point or emoji for blocked PRs (same logic as in addPRSection) - if sortedPRs[prIndex].NeedsReview || sortedPRs[prIndex].IsBlocked { + switch { + case sortedPRs[prIndex].WorkflowState == string(turn.StateNewlyPublished): + // Use gem emoji for newly published PRs + title = fmt.Sprintf("💎 %s", title) + case sortedPRs[prIndex].NeedsReview || sortedPRs[prIndex].IsBlocked: prState, hasState := app.stateManager.PRState(sortedPRs[prIndex].URL) if hasState && !prState.FirstBlockedAt.IsZero() && @@ -552,14 +564,25 @@ func (app *App) generatePRSectionTitles(prs []PR, sectionTitle string, hiddenOrg !prState.IsInitialDiscovery { timeSinceBlocked := time.Since(prState.FirstBlockedAt) if sectionTitle == "Outgoing" { - title = fmt.Sprintf("🎉 %s", title) - slog.Info("[MENU] Adding party popper to outgoing PR in generateMenuTitles", - "repo", sortedPRs[prIndex].Repository, - "number", sortedPRs[prIndex].Number, - "url", sortedPRs[prIndex].URL, - "firstBlockedAt", prState.FirstBlockedAt.Format(time.RFC3339), - "blocked_ago", timeSinceBlocked.Round(time.Second), - "remaining", (blockedPRIconDuration - timeSinceBlocked).Round(time.Second)) + if sortedPRs[prIndex].ActionKind == "fix_tests" { + title = fmt.Sprintf("🪳 %s", title) + slog.Info("[MENU] Adding cockroach to outgoing PR with broken tests in generateMenuTitles", + "repo", sortedPRs[prIndex].Repository, + "number", sortedPRs[prIndex].Number, + "url", sortedPRs[prIndex].URL, + "firstBlockedAt", prState.FirstBlockedAt.Format(time.RFC3339), + "blocked_ago", timeSinceBlocked.Round(time.Second), + "remaining", (blockedPRIconDuration - timeSinceBlocked).Round(time.Second)) + } else { + title = fmt.Sprintf("🎉 %s", title) + slog.Info("[MENU] Adding party popper to outgoing PR in generateMenuTitles", + "repo", sortedPRs[prIndex].Repository, + "number", sortedPRs[prIndex].Number, + "url", sortedPRs[prIndex].URL, + "firstBlockedAt", prState.FirstBlockedAt.Format(time.RFC3339), + "blocked_ago", timeSinceBlocked.Round(time.Second), + "remaining", (blockedPRIconDuration - timeSinceBlocked).Round(time.Second)) + } } else { title = fmt.Sprintf("🪿 %s", title) slog.Debug("[MENU] Adding goose to incoming PR in generateMenuTitles", @@ -586,9 +609,11 @@ func (app *App) generatePRSectionTitles(prs []PR, sectionTitle string, hiddenOrg "number", sortedPRs[prIndex].Number) } } - } else if sortedPRs[prIndex].ActionKind != "" { + case sortedPRs[prIndex].ActionKind != "": // PR has an action but isn't blocked - add bullet to indicate it could use input title = fmt.Sprintf("• %s", title) + default: + // No special prefix needed } titles = append(titles, title) diff --git a/go.mod b/go.mod index 03b5a97..0c24efd 100644 --- a/go.mod +++ b/go.mod @@ -3,9 +3,9 @@ module github.com/codeGROOVE-dev/goose go 1.24.0 require ( - github.com/codeGROOVE-dev/retry v1.2.0 - github.com/codeGROOVE-dev/sprinkler v0.0.0-20251027122631-1d61827b70ca - github.com/codeGROOVE-dev/turnclient v0.0.0-20251022064427-5a712e1e10e6 + github.com/codeGROOVE-dev/retry v1.3.0 + github.com/codeGROOVE-dev/sprinkler v0.0.0-20251027213037-05bb80a9db89 + github.com/codeGROOVE-dev/turnclient v0.0.0-20251028130307-1f85c9aa43c4 github.com/energye/systray v1.0.2 github.com/gen2brain/beeep v0.11.1 github.com/google/go-github/v57 v57.0.0 @@ -14,7 +14,7 @@ require ( require ( git.sr.ht/~jackmordaunt/go-toast v1.1.2 // indirect - github.com/codeGROOVE-dev/prx v0.0.0-20251027012315-7b273aabfc7d // indirect + github.com/codeGROOVE-dev/prx v0.0.0-20251027204543-4e6165f046e5 // indirect github.com/esiqveland/notify v0.13.3 // indirect github.com/go-ole/go-ole v1.3.0 // indirect github.com/godbus/dbus/v5 v5.1.0 // indirect diff --git a/go.sum b/go.sum index 3300e13..628cb97 100644 --- a/go.sum +++ b/go.sum @@ -2,12 +2,20 @@ git.sr.ht/~jackmordaunt/go-toast v1.1.2 h1:/yrfI55LRt1M7H1vkaw+NaH1+L1CDxrqDltwm git.sr.ht/~jackmordaunt/go-toast v1.1.2/go.mod h1:jA4OqHKTQ4AFBdwrSnwnskUIIS3HYzlJSgdzCKqfavo= github.com/codeGROOVE-dev/prx v0.0.0-20251027012315-7b273aabfc7d h1:kUaCKFRxWFrWEyl4fVHi+eY/D5tKhBU29a8YbQyihEk= github.com/codeGROOVE-dev/prx v0.0.0-20251027012315-7b273aabfc7d/go.mod h1:7qLbi18baOyS8yO/6/64SBIqtyzSzLFdsDST15NPH3w= +github.com/codeGROOVE-dev/prx v0.0.0-20251027204543-4e6165f046e5 h1:tjxTLJ5NXx1xhReL4M+J4LTl/JGNSZjPrznAoci06OA= +github.com/codeGROOVE-dev/prx v0.0.0-20251027204543-4e6165f046e5/go.mod h1:FEy3gz9IYDXWnKWkoDSL+pWu6rujxbBSrF4w5A8QSK0= github.com/codeGROOVE-dev/retry v1.2.0 h1:xYpYPX2PQZmdHwuiQAGGzsBm392xIMl4nfMEFApQnu8= github.com/codeGROOVE-dev/retry v1.2.0/go.mod h1:8OgefgV1XP7lzX2PdKlCXILsYKuz6b4ZpHa/20iLi8E= +github.com/codeGROOVE-dev/retry v1.3.0 h1:/+ipAWRJLL6y1R1vprYo0FSjSBvH6fE5j9LKXjpD54g= +github.com/codeGROOVE-dev/retry v1.3.0/go.mod h1:8OgefgV1XP7lzX2PdKlCXILsYKuz6b4ZpHa/20iLi8E= github.com/codeGROOVE-dev/sprinkler v0.0.0-20251027122631-1d61827b70ca h1:NDBJTf69PxMsZkZLUjvnfiMQHWL6Y2T4jQT5YNzXTXA= github.com/codeGROOVE-dev/sprinkler v0.0.0-20251027122631-1d61827b70ca/go.mod h1:/kd3ncsRNldD0MUpbtp5ojIzfCkyeXB7JdOrpuqG7Gg= +github.com/codeGROOVE-dev/sprinkler v0.0.0-20251027213037-05bb80a9db89 h1:8Z3SM90hy1nuK2r2yhtv4HwitnO9si4GzVRktRDQ68g= +github.com/codeGROOVE-dev/sprinkler v0.0.0-20251027213037-05bb80a9db89/go.mod h1:/kd3ncsRNldD0MUpbtp5ojIzfCkyeXB7JdOrpuqG7Gg= github.com/codeGROOVE-dev/turnclient v0.0.0-20251022064427-5a712e1e10e6 h1:7FCmaftkl362oTZHVJyUg+xhxqfQFx+JisBf7RgklL8= github.com/codeGROOVE-dev/turnclient v0.0.0-20251022064427-5a712e1e10e6/go.mod h1:fYwtN9Ql6lY8t2WvCfENx+mP5FUwjlqwXCLx9CVLY20= +github.com/codeGROOVE-dev/turnclient v0.0.0-20251028130307-1f85c9aa43c4 h1:si9tMEo5SXpDuDXGkJ1zNnnpP8TbmakrkNujAbpKlqA= +github.com/codeGROOVE-dev/turnclient v0.0.0-20251028130307-1f85c9aa43c4/go.mod h1:bFWMd0JeaJY0kSIO5AcRQdJLXF3Fo3eKclE49vmIZes= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=