fix(dashboard): use registered rigs for merge queue instead of hardcoded repos (#863)

The FetchMergeQueue function was hardcoded to query PRs from
michaellady/roxas and michaellady/gastown, causing the dashboard
to show unrelated PRs regardless of which rigs are actually registered.

This fix:
- Adds townRoot to LiveConvoyFetcher to access workspace config
- Loads registered rigs from mayor/rigs.json dynamically
- Adds gitURLToRepoPath helper to convert git URLs (HTTPS/SSH) to
  owner/repo format for the gh CLI
- Updates comments to reflect the new behavior

Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
The App Agency
2026-01-21 22:11:29 -05:00
committed by GitHub
parent d67aa0212c
commit 3931d10af3

View File

@@ -10,11 +10,13 @@ import (
"time"
"github.com/steveyegge/gastown/internal/activity"
"github.com/steveyegge/gastown/internal/config"
"github.com/steveyegge/gastown/internal/workspace"
)
// LiveConvoyFetcher fetches convoy data from beads.
type LiveConvoyFetcher struct {
townRoot string
townBeads string
}
@@ -26,6 +28,7 @@ func NewLiveConvoyFetcher() (*LiveConvoyFetcher, error) {
}
return &LiveConvoyFetcher{
townRoot: townRoot,
townBeads: filepath.Join(townRoot, ".beads"),
}, nil
}
@@ -439,21 +442,25 @@ func calculateWorkStatus(completed, total int, activityColor string) string {
}
}
// FetchMergeQueue fetches open PRs from configured repos.
// FetchMergeQueue fetches open PRs from registered rigs.
func (f *LiveConvoyFetcher) FetchMergeQueue() ([]MergeQueueRow, error) {
// Repos to query for PRs
repos := []struct {
Full string // Full repo path for gh CLI
Short string // Short name for display
}{
{"michaellady/roxas", "roxas"},
{"michaellady/gastown", "gastown"},
// Load registered rigs from config
rigsConfigPath := filepath.Join(f.townRoot, "mayor", "rigs.json")
rigsConfig, err := config.LoadRigsConfig(rigsConfigPath)
if err != nil {
return nil, fmt.Errorf("loading rigs config: %w", err)
}
var result []MergeQueueRow
for _, repo := range repos {
prs, err := f.fetchPRsForRepo(repo.Full, repo.Short)
for rigName, entry := range rigsConfig.Rigs {
// Convert git URL to owner/repo format for gh CLI
repoPath := gitURLToRepoPath(entry.GitURL)
if repoPath == "" {
continue
}
prs, err := f.fetchPRsForRepo(repoPath, rigName)
if err != nil {
// Non-fatal: continue with other repos
continue
@@ -464,6 +471,28 @@ func (f *LiveConvoyFetcher) FetchMergeQueue() ([]MergeQueueRow, error) {
return result, nil
}
// gitURLToRepoPath converts a git URL to owner/repo format.
// Supports HTTPS (https://github.com/owner/repo.git) and
// SSH (git@github.com:owner/repo.git) formats.
func gitURLToRepoPath(gitURL string) string {
// Handle HTTPS format: https://github.com/owner/repo.git
if strings.HasPrefix(gitURL, "https://github.com/") {
path := strings.TrimPrefix(gitURL, "https://github.com/")
path = strings.TrimSuffix(path, ".git")
return path
}
// Handle SSH format: git@github.com:owner/repo.git
if strings.HasPrefix(gitURL, "git@github.com:") {
path := strings.TrimPrefix(gitURL, "git@github.com:")
path = strings.TrimSuffix(path, ".git")
return path
}
// Unsupported format
return ""
}
// prResponse represents the JSON response from gh pr list.
type prResponse struct {
Number int `json:"number"`
@@ -479,7 +508,7 @@ type prResponse struct {
// fetchPRsForRepo fetches open PRs for a single repo.
func (f *LiveConvoyFetcher) fetchPRsForRepo(repoFull, repoShort string) ([]MergeQueueRow, error) {
// #nosec G204 -- gh is a trusted CLI, repo is from hardcoded list
// #nosec G204 -- gh is a trusted CLI, repo is from registered rigs config
cmd := exec.Command("gh", "pr", "list",
"--repo", repoFull,
"--state", "open",