Documentation
¶
Overview ¶
Package pkg provides the core domain types and logic for the github-dark-factory-watcher service: GitHub API integration, pull-request filtering, cursor persistence, and Kafka command publishing.
Index ¶
- Constants
- func BuildCreateCommand(pr PullRequest, details PRDetails, taskIDStr string, cfg TaskConfig, ...) task.CreateCommand
- func DeriveTaskID(owner, repo string, number int, sha string) uuid.UUID
- func SaveCursor(ctx context.Context, path string, state Cursor) error
- type Cursor
- type GitHubClient
- type Metrics
- type PRDetails
- type PullRequest
- type SearchResult
- type TaskConfig
- type Watcher
Constants ¶
const DefaultCursorPath = "/data/cursor.json"
DefaultCursorPath is the default path for cursor state persistence.
const DefaultMaxSlugLen = 80
DefaultMaxSlugLen is the default cap for the slugified PR-title segment alone. Override via MAX_SLUG_LEN.
const DefaultMaxTitleLen = 200
DefaultMaxTitleLen is the default safety cap for the whole vault filename, including segments and separators. Crosses Windows MAX_PATH=260 and ext4 NAME_MAX=255 with margin. Override via MAX_TITLE_LEN.
Variables ¶
This section is empty.
Functions ¶
func BuildCreateCommand ¶
func BuildCreateCommand( pr PullRequest, details PRDetails, taskIDStr string, cfg TaskConfig, matchedSpecs []string, ) task.CreateCommand
BuildCreateCommand builds the dark-factory-implement CreateTaskCommand for a candidate PR. Exposed for direct testing of the emitted contract.
func DeriveTaskID ¶
DeriveTaskID returns a deterministic task identifier for a (PR, SHA) pair. Input: "<owner>/<repo>#<number>@<sha>", e.g. "bborbe/maintainer#42@abc123...". The full SHA is used (not truncated) to keep the dedup keyspace collision-free. Same inputs → same UUID, so a re-emit of the same (PR, SHA) is a controller no-op.
Types ¶
type Cursor ¶
type Cursor struct {
LastUpdatedAt libtime.DateTime `json:"last_updated_at"`
HeadSHAs map[string]string `json:"head_shas"`
}
Cursor holds the watcher's persisted poll state, including the last-seen update time and a map of task-identifier to head SHA for force-push detection.
type GitHubClient ¶
type GitHubClient interface {
// SearchPRs issues a GitHub Search query for open PRs updated since cursor.
// page=1 for the first call; use SearchResult.NextPage for subsequent calls.
SearchPRs(
ctx context.Context,
scope string,
since libtime.DateTime,
page int,
) (SearchResult, error)
// GetPRDetails fetches head SHA, clone URL, branch, state and draft flag for
// a single PR via pulls/N (re-confirming draft/state against search-index lag).
GetPRDetails(ctx context.Context, owner, repo string, number int) (PRDetails, error)
// ListPRFiles returns the paths of every file touched by the PR diff
// (paginated pulls/N/files).
ListPRFiles(ctx context.Context, owner, repo string, number int) ([]string, error)
// GetContent returns the decoded bytes of a repo file at the given ref.
// A missing file surfaces as an error for which IsNotFound reports true.
GetContent(ctx context.Context, owner, repo, filePath, ref string) ([]byte, error)
// ListDir returns the entry paths (files and subdirs) directly under the
// given directory path at ref. A missing directory surfaces as an error for
// which IsNotFound reports true.
ListDir(ctx context.Context, owner, repo, dirPath, ref string) ([]string, error)
// IsNotFound reports whether err is a GitHub 404 (missing file/dir/ref).
IsNotFound(err error) bool
}
GitHubClient abstracts the GitHub API calls the watcher and the darkfactory candidate evaluator need.
func NewGitHubClient ¶
func NewGitHubClient(httpClient *http.Client) GitHubClient
NewGitHubClient returns a GitHubClient backed by the real GitHub API. The httpClient must already carry authentication (App auth via lib/githubapp.NewClient).
type Metrics ¶
type Metrics interface {
// IncPollCycle increments the poll cycle counter with the given result label.
// result: "success", "rate_limited", "github_error"
IncPollCycle(result string)
// IncPublished increments the published counter with the given status label.
// status: "create", "skipped", "error"
IncPublished(status string)
// IncReposScanned increments the scanned-PR counter (sanity check on the scope filter).
IncReposScanned()
// IncFilterSkipped increments the filter-skipped counter with the given reason.
// reason: "out_of_scope", "details_error", "empty_sha", "not_draft", "not_open",
// "no_dark_factory_yaml", "no_spec_in_diff", "prompts_in_flight", "evaluate_error"
IncFilterSkipped(reason string)
}
Metrics exposes counters for observable watcher behaviour.
func NewMetrics ¶
func NewMetrics(registerer prometheus.Registerer) Metrics
NewMetrics returns a Metrics implementation backed by Prometheus counters registered against the given registerer. Passing nil resolves to prometheus.DefaultRegisterer (production); tests pass prometheus.NewRegistry() so repeated construction in the same process does not panic with a duplicate registration.
type PRDetails ¶
type PRDetails struct {
// HeadSHA is the commit hash of the PR's head branch. Used as the `ref`
// the agent checks out and as the per-task dedup key.
HeadSHA string
// CloneURL is the HTTPS clone URL of the head repo (e.g.
// `https://github.com/owner/repo.git`). Emitted as `clone_url`.
CloneURL string
// Branch is the head branch name (e.g. `dark-factory/foo`). Emitted as `branch`.
Branch string
// State is the PR state ("open" / "closed"), re-confirmed via pulls/N.
State string
// IsDraft indicates whether the PR is a draft, re-confirmed via pulls/N.
IsDraft bool
// Title is the PR title.
Title string
// UpdatedAt is the PR last-updated timestamp; drives the cursor watermark.
UpdatedAt libtime.DateTime
}
PRDetails holds the per-PR fields the watcher needs to re-confirm state and materialize a task the agent can act on. The Search API does not expose most of these; they require a follow-up PullRequests.Get call (which also dodges search-index lag on the draft/state flags).
type PullRequest ¶
type PullRequest struct {
GlobalID int64
Number int
Owner string
Repo string
Title string
HTMLURL string
IsDraft bool
UpdatedAt libtime.DateTime
}
PullRequest holds the fields the watcher needs from a GitHub PR search result.
type SearchResult ¶
type SearchResult struct {
PullRequests []PullRequest
HasNextPage bool
NextPage int
RateRemaining int
RateResetAt libtime.DateTime
}
SearchResult is the result of a single paginated search call.
type TaskConfig ¶
type TaskConfig struct {
Stage string
MaxSlugLen int
MaxTitleLen int
TaskSuffix string
// TargetVault routes the CreateTaskCommand to a specific vault controller
// (matched verbatim against the controller's VAULT_NAME). Empty leaves it
// unset so the controller's legacy default-vault fallback applies.
TargetVault string
}
TaskConfig groups the per-task publishing configuration.
type Watcher ¶
Watcher polls GitHub and publishes dark-factory-implement task commands to Kafka.
func NewWatcher ¶
func NewWatcher( ghClient GitHubClient, createSender task.CreateCommandSender, metrics Metrics, cursorPath string, startTime libtime.DateTime, scope string, scopeFilter filter.TaskCreationFilter, cfg TaskConfig, ) Watcher
NewWatcher returns a Watcher that polls GitHub and publishes commands.
Source Files
¶
Directories
¶
| Path | Synopsis |
|---|---|
|
Package darkfactory holds the network-backed candidate evaluator that decides whether an open draft PR carries an approved-not-completed dark-factory spec in its diff and therefore warrants a dark-factory-implement task.
|
Package darkfactory holds the network-backed candidate evaluator that decides whether an open draft PR carries an approved-not-completed dark-factory spec in its diff and therefore warrants a dark-factory-implement task. |
|
Package factory wires concrete dependencies for the github-dark-factory-watcher binary.
|
Package factory wires concrete dependencies for the github-dark-factory-watcher binary. |
|
Package filter implements the scope filter chain — the mandatory defense-in-depth predicate that refuses to act on any repo outside the configured REPO_ALLOWLIST, even if the upstream GitHub search returns more.
|
Package filter implements the scope filter chain — the mandatory defense-in-depth predicate that refuses to act on any repo outside the configured REPO_ALLOWLIST, even if the upstream GitHub search returns more. |