Documentation
¶
Overview ¶
Package github implements GitHub issue management for the orchestrator. It handles cobbler issue creation, listing, labeling, DAG promotion, and lifecycle management via the gh CLI.
Index ¶
- Constants
- func ExtractDescriptionFiles(description string) []string
- func ExtractParentIssueNumber(generation string) int
- func FormatIssueFrontMatter(generation string, index, dependsOn int) string
- func GenLabel(generation string) string
- func GoModModulePath(repoRoot string) string
- func HasLabel(issue CobblerIssue, label string) bool
- func IssuesContextJSON(issues []CobblerIssue) (string, error)
- func NormalizeIssueTitle(title string) string
- func ParseIssueURL(raw string) (int, error)
- type BranchChecker
- type CobblerFrontMatter
- type CobblerIssue
- type ContextIssue
- type Deps
- type GitHubTracker
- func (t *GitHubTracker) AddIssueLabel(repo string, number int, label string) error
- func (t *GitHubTracker) CloseCobblerIssue(repo string, number int, generation string) error
- func (t *GitHubTracker) CloseGenerationIssues(repo, generation string) error
- func (t *GitHubTracker) CloseMeasuringPlaceholder(repo string, number int)
- func (t *GitHubTracker) CloseMeasuringPlaceholderWithComment(repo string, number int, comment string)
- func (t *GitHubTracker) CommentCobblerIssue(repo string, number int, body string)
- func (t *GitHubTracker) CreateCobblerIssue(repo, generation string, issue ProposedIssue) (int, error)
- func (t *GitHubTracker) CreateMeasuringPlaceholder(repo, generation string, iteration int) (int, error)
- func (t *GitHubTracker) DetectGitHubRepo(repoRoot string) (string, error)
- func (t *GitHubTracker) EditIssueTitle(repo string, number int, title string) error
- func (t *GitHubTracker) EnsureCobblerGenLabel(repo, generation string) error
- func (t *GitHubTracker) EnsureCobblerLabels(repo string) error
- func (t *GitHubTracker) FetchIssueComments(repo string, number int) ([]string, error)
- func (t *GitHubTracker) FileTargetRepoDefects(repo string, defects []string)
- func (t *GitHubTracker) FinalizeMeasurePlaceholder(repo string, number int, generation, comment string, childIssues []int)
- func (t *GitHubTracker) GcStaleGenerationIssues(repo, generationPrefix string)
- func (t *GitHubTracker) GhExec(repoRoot string, args ...string) (string, error)
- func (t *GitHubTracker) LinkSubIssue(repo string, parentNumber, childNumber int) error
- func (t *GitHubTracker) ListActiveIssuesContext(repo, generation string) (string, error)
- func (t *GitHubTracker) ListAllCobblerIssues(repo, generation string) ([]CobblerIssue, error)
- func (t *GitHubTracker) ListOpenCobblerIssues(repo, generation string) ([]CobblerIssue, error)
- func (t *GitHubTracker) ListRepoLabels(repo string) []string
- func (t *GitHubTracker) PickReadyIssue(repo, generation string) (CobblerIssue, error)
- func (t *GitHubTracker) PromoteReadyIssues(repo, generation string) error
- func (t *GitHubTracker) RemoveIssueLabel(repo string, number int, label string) error
- func (t *GitHubTracker) ResolveTargetRepo() string
- func (t *GitHubTracker) WaitForIssuesVisible(repo, generation string, expected int)
- type Logger
- type ProposedIssue
- type RepoConfig
- type WorkTracker
Constants ¶
const ( LabelReady = "cobbler-ready" LabelInProgress = "cobbler-in-progress" )
LabelReady and LabelInProgress are the two status labels applied to orchestrator issues during their lifecycle.
const GenLabelPrefix = "cobbler-gen-"
GenLabelPrefix is the prefix for generation-scoped labels.
Variables ¶
This section is empty.
Functions ¶
func ExtractDescriptionFiles ¶ added in v0.20260309.1
ExtractDescriptionFiles parses the files section from a YAML task description and returns the set of file paths. Returns nil if parsing fails or no files are found. Works with both CobblerIssue.Description and ProposedIssue.Description.
func ExtractParentIssueNumber ¶
ExtractParentIssueNumber parses a GitHub issue number from a generation name that follows the pattern "...-gh-<N>-..." (e.g., "generation-gh-206-slug" → 206). Returns 0 if the pattern is not found.
func FormatIssueFrontMatter ¶
FormatIssueFrontMatter formats the YAML front-matter block for an issue body.
func GenLabel ¶
GenLabel returns the generation label for a given generation name. GitHub enforces a 50-character maximum on label names. When the full label would exceed 50 chars, we keep the prefix (12 chars) plus the first 29 chars of the generation name, a hyphen, and an 8-char FNV-32 hex digest of the full generation name — yielding exactly 50 chars and remaining deterministic.
func GoModModulePath ¶
GoModModulePath reads the module path from the go.mod in repoRoot.
func HasLabel ¶
func HasLabel(issue CobblerIssue, label string) bool
HasLabel returns true if the issue has the given label.
func IssuesContextJSON ¶
func IssuesContextJSON(issues []CobblerIssue) (string, error)
IssuesContextJSON converts a slice of CobblerIssue into the JSON string expected by parseIssuesJSON. Exported for testing.
func NormalizeIssueTitle ¶
NormalizeIssueTitle strips [measure]/[stitch] prefixes and trims whitespace so that proposed titles can be compared against existing issues (GH-1026).
func ParseIssueURL ¶
ParseIssueURL extracts a GitHub issue number from a URL string like "https://github.com/owner/repo/issues/123\n". Returns an error for malformed or empty output.
Types ¶
type BranchChecker ¶
BranchChecker returns true if a git branch exists in the given directory.
type CobblerFrontMatter ¶
type CobblerFrontMatter struct {
Generation string `yaml:"cobbler_generation"`
Index int `yaml:"cobbler_index"`
DependsOn int `yaml:"cobbler_depends_on"`
}
CobblerFrontMatter is the YAML front-matter embedded at the top of every GitHub issue created by the orchestrator.
func ParseIssueFrontMatter ¶
func ParseIssueFrontMatter(body string) (CobblerFrontMatter, string)
ParseIssueFrontMatter splits a GitHub issue body into its YAML front-matter and description parts. Returns zero-value front-matter on parse failure.
type CobblerIssue ¶
type CobblerIssue struct {
Number int // GitHub issue number
Title string // Issue title
State string // "open" or "closed"
Index int // cobbler_index from front-matter
DependsOn int // cobbler_depends_on (-1 = no dependency)
Generation string // cobbler_generation label value
Description string // Body text below the front-matter block
Labels []string
}
CobblerIssue holds the parsed representation of a GitHub issue created by the orchestrator. Fields are populated from the issue's YAML front-matter.
func ParseCobblerIssuesJSON ¶
func ParseCobblerIssuesJSON(data []byte) ([]CobblerIssue, error)
ParseCobblerIssuesJSON parses the JSON output from the GitHub REST API issues endpoint into a slice of CobblerIssue structs.
type ContextIssue ¶
type ContextIssue struct {
ID string `yaml:"id" json:"id"`
Title string `yaml:"title" json:"title"`
Status string `yaml:"status" json:"status"`
Type string `yaml:"type" json:"type"`
}
ContextIssue represents an issue tracker entry in the project context. It captures the fields needed for Claude to avoid creating duplicate issues during measure.
type Deps ¶
type Deps struct {
Log Logger
GhBin string
BranchExists BranchChecker
}
Deps holds external dependencies injected by the parent package. Retained for backward compatibility; new code should use GitHubTracker.
type GitHubTracker ¶ added in v0.20260308.2
type GitHubTracker struct {
Log Logger
GhBin string
BranchExists BranchChecker
Cfg RepoConfig
}
GitHubTracker implements WorkTracker by wrapping the gh CLI and configuration needed for GitHub issue operations.
func NewGitHubTracker ¶ added in v0.20260308.2
func NewGitHubTracker(deps Deps, cfg RepoConfig) *GitHubTracker
NewGitHubTracker creates a GitHubTracker from Deps and RepoConfig.
func (*GitHubTracker) AddIssueLabel ¶ added in v0.20260308.2
func (t *GitHubTracker) AddIssueLabel(repo string, number int, label string) error
AddIssueLabel adds a label to a GitHub issue via the API.
func (*GitHubTracker) CloseCobblerIssue ¶ added in v0.20260308.2
func (t *GitHubTracker) CloseCobblerIssue(repo string, number int, generation string) error
CloseCobblerIssue closes a GitHub issue and re-runs PromoteReadyIssues so any unblocked issues become ready.
func (*GitHubTracker) CloseGenerationIssues ¶ added in v0.20260308.2
func (t *GitHubTracker) CloseGenerationIssues(repo, generation string) error
CloseGenerationIssues closes all open issues scoped to a generation. Used during reset or cleanup of a failed generation.
func (*GitHubTracker) CloseMeasuringPlaceholder ¶ added in v0.20260308.2
func (t *GitHubTracker) CloseMeasuringPlaceholder(repo string, number int)
CloseMeasuringPlaceholder closes the placeholder issue created by CreateMeasuringPlaceholder. Best-effort: logs and ignores errors.
func (*GitHubTracker) CloseMeasuringPlaceholderWithComment ¶ added in v0.20260308.2
func (t *GitHubTracker) CloseMeasuringPlaceholderWithComment(repo string, number int, comment string)
CloseMeasuringPlaceholderWithComment closes the placeholder issue and adds a comment explaining why it was closed. Used on error paths to avoid orphans (GH-747). Best-effort: logs and ignores errors.
func (*GitHubTracker) CommentCobblerIssue ¶ added in v0.20260308.2
func (t *GitHubTracker) CommentCobblerIssue(repo string, number int, body string)
CommentCobblerIssue posts a comment on a GitHub issue. Errors are logged but do not fail the caller — commenting is best-effort.
func (*GitHubTracker) CreateCobblerIssue ¶ added in v0.20260308.2
func (t *GitHubTracker) CreateCobblerIssue(repo, generation string, issue ProposedIssue) (int, error)
CreateCobblerIssue creates a GitHub issue on repo for the given generation and ProposedIssue. Returns the GitHub issue number.
Note: gh issue create (v2.87.3) does not support --json; it outputs the issue URL (https://github.com/owner/repo/issues/123) on success.
func (*GitHubTracker) CreateMeasuringPlaceholder ¶ added in v0.20260308.2
func (t *GitHubTracker) CreateMeasuringPlaceholder(repo, generation string, iteration int) (int, error)
CreateMeasuringPlaceholder creates a transient GitHub issue that signals the measure agent is actively calling Claude for iteration i (1-based). The issue carries no cobbler-ready label so stitch won't pick it up. Callers must call CloseMeasuringPlaceholder after the iteration completes.
func (*GitHubTracker) DetectGitHubRepo ¶ added in v0.20260308.2
func (t *GitHubTracker) DetectGitHubRepo(repoRoot string) (string, error)
DetectGitHubRepo resolves the GitHub owner/repo string for the target project. Resolution order:
- t.Cfg.IssuesRepo if set (explicit override, used for testing)
- `gh repo view --json nameWithOwner` run in repoRoot (reads git remote)
- Strip "github.com/" from t.Cfg.ModulePath
func (*GitHubTracker) EditIssueTitle ¶ added in v0.20260308.2
func (t *GitHubTracker) EditIssueTitle(repo string, number int, title string) error
EditIssueTitle updates the title of a GitHub issue.
func (*GitHubTracker) EnsureCobblerGenLabel ¶ added in v0.20260308.2
func (t *GitHubTracker) EnsureCobblerGenLabel(repo, generation string) error
EnsureCobblerGenLabel creates the generation-scoped label on the repo if it does not already exist.
func (*GitHubTracker) EnsureCobblerLabels ¶ added in v0.20260308.2
func (t *GitHubTracker) EnsureCobblerLabels(repo string) error
EnsureCobblerLabels creates the cobbler-ready and cobbler-in-progress labels on the target repo if they do not already exist. Idempotent.
func (*GitHubTracker) FetchIssueComments ¶ added in v0.20260308.2
func (t *GitHubTracker) FetchIssueComments(repo string, number int) ([]string, error)
FetchIssueComments returns the body text of all comments on the given issue.
func (*GitHubTracker) FileTargetRepoDefects ¶ added in v0.20260308.2
func (t *GitHubTracker) FileTargetRepoDefects(repo string, defects []string)
FileTargetRepoDefects files each defect as a GitHub bug issue in repo. Errors are logged but do not fail the caller — filing is best-effort (prd003 R11.5, R11.6). If repo is empty the call is a no-op with a warning log (prd003 R11.7).
func (*GitHubTracker) FinalizeMeasurePlaceholder ¶ added in v0.20260308.8
func (t *GitHubTracker) FinalizeMeasurePlaceholder(repo string, number int, generation, comment string, childIssues []int)
FinalizeMeasurePlaceholder converts the measuring placeholder into a permanent [measure] issue, adds a summary comment, links created stitch issues as sub-issues, adds the generation label, and closes it (GH-1360).
func (*GitHubTracker) GcStaleGenerationIssues ¶ added in v0.20260308.2
func (t *GitHubTracker) GcStaleGenerationIssues(repo, generationPrefix string)
GcStaleGenerationIssues closes open issues whose generation branch no longer exists locally. This catches leaked issues from crashed tests, killed processes, or GeneratorStop runs that predated the cleanup fix. It fetches all open issues in a single API call, filters locally for cobbler-gen-* labels, groups by generation, and closes issues for missing branches. Cost: 1 API call for discovery + 1 per stale issue.
func (*GitHubTracker) GhExec ¶ added in v0.20260308.2
func (t *GitHubTracker) GhExec(repoRoot string, args ...string) (string, error)
GhExec runs a gh subcommand with dir set to repoRoot and returns stdout.
func (*GitHubTracker) LinkSubIssue ¶ added in v0.20260308.2
func (t *GitHubTracker) LinkSubIssue(repo string, parentNumber, childNumber int) error
LinkSubIssue attaches childNumber as a GitHub sub-issue of parentNumber. It first fetches the child's database ID, then POSTs to the sub_issues API. Errors are returned so the caller can log them as warnings.
func (*GitHubTracker) ListActiveIssuesContext ¶ added in v0.20260308.2
func (t *GitHubTracker) ListActiveIssuesContext(repo, generation string) (string, error)
ListActiveIssuesContext returns a JSON array of ContextIssue objects for all open issues in the generation, suitable for injection into the measure prompt. The JSON format matches what parseIssuesJSON expects.
func (*GitHubTracker) ListAllCobblerIssues ¶ added in v0.20260308.2
func (t *GitHubTracker) ListAllCobblerIssues(repo, generation string) ([]CobblerIssue, error)
ListAllCobblerIssues returns all GitHub issues (open and closed) for a generation. Used by GeneratorStats to report completed tasks.
func (*GitHubTracker) ListOpenCobblerIssues ¶ added in v0.20260308.2
func (t *GitHubTracker) ListOpenCobblerIssues(repo, generation string) ([]CobblerIssue, error)
ListOpenCobblerIssues returns all open GitHub issues for a generation. It uses the REST API endpoint (gh api repos/.../issues) rather than gh issue list, because gh issue list uses GitHub's search API which is eventually consistent and can return stale results immediately after label changes. The REST endpoint reads directly from the database.
func (*GitHubTracker) ListRepoLabels ¶ added in v0.20260308.2
func (t *GitHubTracker) ListRepoLabels(repo string) []string
ListRepoLabels returns the names of all labels on the repo.
func (*GitHubTracker) PickReadyIssue ¶ added in v0.20260308.2
func (t *GitHubTracker) PickReadyIssue(repo, generation string) (CobblerIssue, error)
PickReadyIssue promotes ready issues then picks the lowest-numbered cobbler-ready issue, adds cobbler-in-progress, and returns it.
func (*GitHubTracker) PromoteReadyIssues ¶ added in v0.20260308.2
func (t *GitHubTracker) PromoteReadyIssues(repo, generation string) error
PromoteReadyIssues builds the DAG from open issues and applies cobbler-ready to unblocked issues. Issues whose dependency is still open have cobbler-ready removed.
func (*GitHubTracker) RemoveIssueLabel ¶ added in v0.20260308.2
func (t *GitHubTracker) RemoveIssueLabel(repo string, number int, label string) error
RemoveIssueLabel removes a label from a GitHub issue via the API.
func (*GitHubTracker) ResolveTargetRepo ¶ added in v0.20260308.2
func (t *GitHubTracker) ResolveTargetRepo() string
ResolveTargetRepo returns the GitHub owner/repo string for the project being developed. It checks t.Cfg.TargetRepo first; if empty it strips "github.com/" from t.Cfg.ModulePath. Returns "" if neither yields a non-empty value. Intentionally separate from DetectGitHubRepo to avoid cobbler.issues_repo contaminating target resolution (prd003 R11.4, D2).
func (*GitHubTracker) WaitForIssuesVisible ¶ added in v0.20260308.2
func (t *GitHubTracker) WaitForIssuesVisible(repo, generation string, expected int)
WaitForIssuesVisible polls ListOpenCobblerIssues until at least expected issues appear or the timeout expires. The REST API label index may lag briefly after issue creation, so this function ensures all issues are visible before promotion or DAG resolution.
type ProposedIssue ¶
type ProposedIssue struct {
Index int `yaml:"index"`
Title string `yaml:"title"`
Description string `yaml:"description"`
Dependency int `yaml:"dependency"`
}
ProposedIssue represents an issue proposed by measure for creation on GitHub.
type RepoConfig ¶
type RepoConfig struct {
IssuesRepo string // cobbler.issues_repo override
ModulePath string // project.module_path for fallback detection
TargetRepo string // project.target_repo for defect filing
}
RepoConfig holds the minimal configuration fields needed by this package.
type WorkTracker ¶ added in v0.20260308.2
type WorkTracker interface {
// Repo detection
DetectGitHubRepo(repoRoot string) (string, error)
// Label management
EnsureCobblerLabels(repo string) error
EnsureCobblerGenLabel(repo, generation string) error
ListRepoLabels(repo string) []string
AddIssueLabel(repo string, number int, label string) error
RemoveIssueLabel(repo string, number int, label string) error
// Issue CRUD
CreateCobblerIssue(repo, generation string, issue ProposedIssue) (int, error)
CreateMeasuringPlaceholder(repo, generation string, iteration int) (int, error)
CloseCobblerIssue(repo string, number int, generation string) error
CloseMeasuringPlaceholder(repo string, number int)
CloseMeasuringPlaceholderWithComment(repo string, number int, comment string)
FinalizeMeasurePlaceholder(repo string, number int, generation, comment string, childIssues []int)
EditIssueTitle(repo string, number int, title string) error
CommentCobblerIssue(repo string, number int, body string)
CloseGenerationIssues(repo, generation string) error
// Issue queries
ListOpenCobblerIssues(repo, generation string) ([]CobblerIssue, error)
ListAllCobblerIssues(repo, generation string) ([]CobblerIssue, error)
FetchIssueComments(repo string, number int) ([]string, error)
ListActiveIssuesContext(repo, generation string) (string, error)
WaitForIssuesVisible(repo, generation string, expected int)
// Sub-issues
LinkSubIssue(repo string, parentNumber, childNumber int) error
// DAG
PromoteReadyIssues(repo, generation string) error
PickReadyIssue(repo, generation string) (CobblerIssue, error)
// GC
GcStaleGenerationIssues(repo, generationPrefix string)
// Defects
FileTargetRepoDefects(repo string, defects []string)
ResolveTargetRepo() string
// Generic
GhExec(repoRoot string, args ...string) (string, error)
}
WorkTracker defines the interface for all issue-tracking operations that have external dependencies (gh CLI calls, branch checks). Pure functions that operate only on in-memory data remain as package-level functions. Designed so a future crumbs/trails implementation can satisfy it.