github

package
v0.20260309.3 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Mar 9, 2026 License: MIT Imports: 10 Imported by: 0

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

View Source
const (
	LabelReady      = "cobbler-ready"
	LabelInProgress = "cobbler-in-progress"
)

LabelReady and LabelInProgress are the two status labels applied to orchestrator issues during their lifecycle.

View Source
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

func ExtractDescriptionFiles(description string) []string

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

func ExtractParentIssueNumber(generation string) int

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

func FormatIssueFrontMatter(generation string, index, dependsOn int) string

FormatIssueFrontMatter formats the YAML front-matter block for an issue body.

func GenLabel

func GenLabel(generation string) string

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

func GoModModulePath(repoRoot string) string

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

func NormalizeIssueTitle(title string) string

NormalizeIssueTitle strips [measure]/[stitch] prefixes and trims whitespace so that proposed titles can be compared against existing issues (GH-1026).

func ParseIssueURL

func ParseIssueURL(raw string) (int, error)

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

type BranchChecker func(branch, dir string) bool

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:

  1. t.Cfg.IssuesRepo if set (explicit override, used for testing)
  2. `gh repo view --json nameWithOwner` run in repoRoot (reads git remote)
  3. 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 Logger

type Logger func(format string, args ...any)

Logger is a function that formats and emits log messages.

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.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL