| 1 | // SPDX-License-Identifier: AGPL-3.0-or-later |
| 2 | |
| 3 | // Package checks owns CI check-suite + check-run orchestration. The |
| 4 | // API layer (internal/web/handlers/api/checks.go) calls into Create |
| 5 | // and Update; the merge gate at internal/pulls/pulls.go calls |
| 6 | // EvaluateRequiredChecks. |
| 7 | // |
| 8 | // No work in this package executes user code — shithub is a |
| 9 | // receiver of check status from external systems (and, post-MVP, |
| 10 | // shithub Actions). The API surface is GitHub-shaped so existing CI |
| 11 | // adapters port cleanly. |
| 12 | package checks |
| 13 | |
| 14 | import ( |
| 15 | "errors" |
| 16 | "log/slog" |
| 17 | |
| 18 | "github.com/jackc/pgx/v5/pgxpool" |
| 19 | ) |
| 20 | |
| 21 | // Deps wires the package against the runtime. |
| 22 | type Deps struct { |
| 23 | Pool *pgxpool.Pool |
| 24 | Logger *slog.Logger |
| 25 | } |
| 26 | |
| 27 | // Output is the JSON shape stored in `check_runs.output`. Matches |
| 28 | // GitHub's `output` shape: title + summary + text. Bodies are bounded |
| 29 | // at the orchestrator (256 KiB on text, 64 KiB on summary) per spec. |
| 30 | type Output struct { |
| 31 | Title string `json:"title,omitempty"` |
| 32 | Summary string `json:"summary,omitempty"` |
| 33 | Text string `json:"text,omitempty"` |
| 34 | } |
| 35 | |
| 36 | // MaxOutputTextBytes / MaxOutputSummaryBytes cap the output payload |
| 37 | // per spec section "Open questions". |
| 38 | const ( |
| 39 | MaxOutputTextBytes = 256 * 1024 |
| 40 | MaxOutputSummaryBytes = 64 * 1024 |
| 41 | ) |
| 42 | |
| 43 | // Errors surfaced to API + handlers. |
| 44 | var ( |
| 45 | ErrEmptyName = errors.New("checks: name is required") |
| 46 | ErrNameTooLong = errors.New("checks: name too long (max 200)") |
| 47 | ErrInvalidStatus = errors.New("checks: status must be queued, in_progress, completed, or pending") |
| 48 | ErrInvalidConclusion = errors.New("checks: invalid conclusion") |
| 49 | ErrCompletedNeedsConclusion = errors.New("checks: completed status requires conclusion") |
| 50 | ErrOutputTextTooLarge = errors.New("checks: output.text exceeds 256 KiB cap") |
| 51 | ErrOutputSummaryTooLarge = errors.New("checks: output.summary exceeds 64 KiB cap") |
| 52 | ErrShortHeadSHA = errors.New("checks: head_sha must be at least 7 hex chars") |
| 53 | ErrCheckRunNotFound = errors.New("checks: run not found") |
| 54 | ErrSuiteNotFound = errors.New("checks: suite not found") |
| 55 | ) |
| 56 | |
| 57 | // validStatus / validConclusion mirror the Postgres enums. |
| 58 | func validStatus(s string) bool { |
| 59 | switch s { |
| 60 | case "queued", "in_progress", "completed", "pending": |
| 61 | return true |
| 62 | } |
| 63 | return false |
| 64 | } |
| 65 | |
| 66 | func validConclusion(s string) bool { |
| 67 | switch s { |
| 68 | case "success", "failure", "neutral", "cancelled", |
| 69 | "skipped", "timed_out", "action_required", "stale": |
| 70 | return true |
| 71 | } |
| 72 | return false |
| 73 | } |
| 74 |