store

package
v0.44.1 Latest Latest
Warning

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

Go to latest
Published: Sep 23, 2026 License: Apache-2.0 Imports: 11 Imported by: 0

Documentation

Overview

Package store is the server's SQLite persistence layer: executions, their stack/edge subgraph, and per-(class,target) approval gate state. Pure-Go SQLite (modernc.org/sqlite, no cgo); schema migrated by goose at Open.

Index

Constants

This section is empty.

Variables

View Source
var ErrConcurrencyConflict = errors.New("eventstore: concurrency conflict")

ErrConcurrencyConflict is returned by Append when the stream's current version is not the expected version — i.e. another writer advanced the stream since the caller last read it. The caller should reload and retry.

Functions

func AppendPhaseHistory added in v0.43.0

func AppendPhaseHistory(tx *sql.Tx, execID, phase, label string, pct *int) error

AppendPhaseHistory appends an immutable execution_phases row (lifecycle read model).

func AssociateClaimExecution added in v0.15.0

func AssociateClaimExecution(db *sql.DB, env string, pr int, execID string) error

AssociateClaimExecution links a PR's claims to the apply execution that now owns them (so heartbeats/finalize can target by pr+env).

func BumpRev

func BumpRev(db *sql.DB, id string) error

BumpRev increments the cache-bust revision (used by the rendered SVG URL so GitHub's image proxy re-fetches on each state change).

func DeleteTarget added in v0.9.9

func DeleteTarget(tx *sql.Tx, pr int, environment, class, target string) error

DeleteTarget removes a single gate target row.

func EnvironmentsForPR added in v0.15.0

func EnvironmentsForPR(db *sql.DB, pr int) ([]string, error)

EnvironmentsForPR returns the distinct environments that have at least one execution for the given PR. Order is unspecified.

func FindExecutionBySHA added in v0.24.0

func FindExecutionBySHA(db *sql.DB, environment, statusContext, sha string) (string, bool, error)

FindExecutionBySHA returns the most recent non-superseded execution for (environment, status_context, sha) with pr > 0. The inbound-build correlation and the pr==0 runner-Init recovery both key on it: a plan head SHA is PR-unique, so this recovers the owning PR when a rerun lost its _PR_NUMBER.

func FindNonSupersededExecution added in v0.18.2

func FindNonSupersededExecution(db *sql.DB, pr int, environment, sha, statusContext, incomingID string) (string, bool, error)

FindNonSupersededExecution looks up the most recent non-superseded execution for the given (pr, environment, sha, status_context) where pr > 0 and id != incoming id.

func GetStackOutput added in v0.6.0

func GetStackOutput(db *sql.DB, execID, stack, kind string) (pointer, excerpt string, ok bool, err error)

GetStackOutput returns the stored pointer + excerpt for a stack's output kind. ok is false when none is recorded.

func LatestExecutionID added in v0.6.0

func LatestExecutionID(db *sql.DB, pr int, environment string) (string, bool)

LatestExecutionID returns the most recent execution id for (pr, environment). ok is false when none exists.

func LatestPRForSHA added in v0.22.0

func LatestPRForSHA(db *sql.DB, sha, environment, statusContext string) (int, bool)

LatestPRForSHA recovers the PR of the newest execution for (sha, env, context) — the check_run rerequested path for apply checks, whose webhook payload carries no pull_requests on merge commits.

func LatestReportedExecutionID added in v0.22.0

func LatestReportedExecutionID(db *sql.DB, pr int, environment string) (string, bool)

LatestReportedExecutionID is LatestExecutionID restricted to executions the runner actually reported on (a phase tick or registered stacks) — a serve-queued row awaiting its build has neither and must not shadow the last real plan (the apply-lock evaluation reads the graph through this).

func LatestVerifyExecutionID added in v0.6.0

func LatestVerifyExecutionID(db *sql.DB, pr int, environment string) (string, bool)

LatestVerifyExecutionID returns the most recent verify-context execution id for (pr, environment) — i.e. a run whose status_context begins with "verify". ok is false when none exists.

func LoadGraph

func LoadGraph(db *sql.DB, id string) (events.Graph, error)

LoadGraph loads the stacks (ordered by path) and edges of an execution.

func Open

func Open(dsn string) (*sql.DB, error)

Open opens the SQLite database at dsn, enables WAL, and applies all migrations. dsn is a modernc.org/sqlite DSN, e.g. a file path or "file:/data/server.db".

func ProjectEdge added in v0.43.0

func ProjectEdge(tx *sql.Tx, execID, from, to string) error

ProjectEdge inserts a dependency edge, ignoring duplicates.

func ProjectExecutionRow added in v0.43.0

func ProjectExecutionRow(tx *sql.Tx, e ProjectedExecution) error

ProjectExecutionRow UPSERTs the execution-aggregate-owned columns of an executions row, preserving non-owned columns (report_markdown, change_reasons, check_run_id, rev) on conflict. superseded_by and created_at ARE owned: superseded_by is written verbatim from the folded execution.State (Evolve's Superseded/Started cases are the sole authority — see execution.Evolve), and created_at is revived to CURRENT_TIMESTAMP whenever a fresh in_progress Init arrives for a row that was terminal and/or superseded, mirroring what ReviveExecution used to do as a separate statement.

func ProjectStack added in v0.43.0

func ProjectStack(tx *sql.Tx, execID string, s ProjectedStack) error

ProjectStack UPSERTs the execution-aggregate-owned columns of a stacks row.

func ReplaceClaims added in v0.17.0

func ReplaceClaims(db *sql.DB, env string, rows map[string]Claim) error

ReplaceClaims rewrites the apply_claims projection for env to exactly match `rows` (stack_path → {owner_pr, expires_at}). Upserts each row and deletes any existing rows for env not present in the new set. This is the projector seam: the env:<env> event stream is the source of truth, apply_claims a derived cross-env index for the sweep + the live-UI list. Atomic in one tx.

func SetChangeReasons added in v0.31.0

func SetChangeReasons(db *sql.DB, id string, reasons []events.ChangeReason) error

SetChangeReasons stores the JSON serialized change reasons for an execution.

func SetCheckRunID

func SetCheckRunID(db *sql.DB, id string, checkRunID int64) error

SetCheckRunID records the GitHub check-run id created for an execution.

func SetReport

func SetReport(db *sql.DB, id, markdown string) error

SetReport stores the rendered plan report markdown for an execution.

func SweepExpiredClaims added in v0.15.0

func SweepExpiredClaims(db *sql.DB, now time.Time) ([]string, error)

SweepExpiredClaims deletes all claims expired at `now` and returns the distinct environments that lost a claim (so the caller can re-evaluate their held checks).

func Transact added in v0.36.0

func Transact(db *sql.DB, fn func(*sql.Tx) error) error

Transact runs fn inside a serialized database transaction. This completely serializes all database writes on the Go side, making SQLITE_BUSY write contention mathematically impossible, while letting Go's connection pool utilize unlimited concurrent reader connections!

func UpsertApplyLockCheck added in v0.15.0

func UpsertApplyLockCheck(db *sql.DB, c ApplyLockCheck) error

func UpsertPRMeta added in v0.27.0

func UpsertPRMeta(db *sql.DB, m PRMeta) error

UpsertPRMeta records the PR's current metadata, overwriting any previous row for (repo, pr). Safe to call repeatedly as the webhook re-delivers or the PR is edited.

func UpsertStackOutput added in v0.6.0

func UpsertStackOutput(db *sql.DB, execID, stack, kind, pointer, excerpt string) error

UpsertStackOutput records (or updates) the pointer + tail excerpt for one stack's output of a given kind ("log", later "plan"/"verify").

Types

type ApplyLockCheck added in v0.15.0

type ApplyLockCheck struct {
	Environment string
	HeadSHA     string
	CheckRunID  int64
	PR          int
	Repo        string
	Stacks      []string
	State       string // clear | held | unverifiable
	Kind        string // merge_group | pr_head
	ExecutionID string // plan execution whose check run carries the consolidated render; "" for legacy/merge-group records
}

ApplyLockCheck is a persisted apply-lock check run (so serve can PATCH it later when an overlapping apply releases). Keyed by (environment, head_sha).

func GetApplyLockCheck added in v0.15.0

func GetApplyLockCheck(db *sql.DB, env, headSHA string) (ApplyLockCheck, bool, error)

func HeldApplyLockChecks added in v0.15.0

func HeldApplyLockChecks(db *sql.DB, env string) ([]ApplyLockCheck, error)

type Claim added in v0.15.0

type Claim = events.Claim

Claim is one apply-lock claim row. It is a type alias of events.Claim (the wire type) so the ledger, the wire protocol, and persistence share one definition — following the domain-alias discipline (see events.Counts = domain.Counts).

func ListClaims added in v0.15.0

func ListClaims(db *sql.DB, env string) ([]Claim, error)

ListClaims returns all claims for env (any expiry) ordered by stack_path.

type EventStore added in v0.17.0

type EventStore struct {
	// contains filtered or unexported fields
}

EventStore is the append-only event log + snapshot cache over SQLite. It is domain-agnostic: it deals only in StoredEvent and []byte snapshot blobs.

func NewEventStore added in v0.17.0

func NewEventStore(db *sql.DB) *EventStore

NewEventStore wraps db as an EventStore.

func (*EventStore) Append added in v0.17.0

func (s *EventStore) Append(streamID string, expectedVersion int, evs []StoredEvent) error

Append writes evs as the next contiguous versions after expectedVersion (the caller's last-seen stream version; 0 for a new/empty stream). It is all-or-nothing. Returns ErrConcurrencyConflict if the stream's current version is not expectedVersion.

func (*EventStore) Load added in v0.17.0

func (s *EventStore) Load(streamID string) ([]StoredEvent, int, error)

Load returns the stream's events in version order plus its current version (0 and an empty slice for an unknown/empty stream).

func (*EventStore) LoadSnapshot added in v0.17.0

func (s *EventStore) LoadSnapshot(streamID string) (state []byte, version int, ok bool, err error)

LoadSnapshot returns the latest snapshot for the stream (ok=false if none).

func (*EventStore) SaveSnapshot added in v0.17.0

func (s *EventStore) SaveSnapshot(streamID string, version int, state []byte) error

SaveSnapshot upserts the latest snapshot for the stream (last-write-wins). No concurrency check: the events table is authoritative, so a stale snapshot only means replaying a longer event tail. version is the event version the snapshot reflects.

type Execution

type Execution struct {
	ID             string
	Repo           string
	SHA            string
	PR             int
	Environment    string
	CheckRunID     sql.NullInt64
	Rev            int
	ReportMarkdown string
	LogURL         string
	Status         string // execution-level commit status (e.g. "in_progress"/"success"/"failure"); written by the serve handler, distinct from per-stack events.Status
	StatusContext  string
	Phase          string
	ProgressLabel  sql.NullString `json:"-"`
	ProgressPct    sql.NullInt64  `json:"-"`
	CreatedAt      time.Time
	SupersededBy   string
	ChangeReasons  string `json:"-"`
}

Execution is a row of the executions table.

func GetExecution

func GetExecution(db *sql.DB, id string) (Execution, error)

GetExecution loads one execution row.

func ListExecutions added in v0.6.0

func ListExecutions(db *sql.DB, limit int) ([]Execution, error)

ListExecutions returns the most recent executions, newest first.

func ListExecutionsForPR added in v0.6.0

func ListExecutionsForPR(db *sql.DB, pr int) ([]Execution, error)

ListExecutionsForPR returns all executions for a PR, newest first.

func StuckPendingExecutions added in v0.22.0

func StuckPendingExecutions(db *sql.DB, environment string, cutoff time.Time) ([]Execution, error)

StuckPendingExecutions returns this environment's serve-initiated executions (id prefix per reconcile.RunExecutionIDPrefix) still in_progress with no runner activity at all (empty phase) created before cutoff — the start-watchdog's candidates. Runner-created executions and other tiers' rows are excluded in SQL so the watchdog never replays streams it cannot act on.

type Gate

type Gate struct {
	PR          int
	Environment string
}

Gate identifies the unit an approval verdict is posted for.

func PendingGates

func PendingGates(db *sql.DB) ([]Gate, error)

PendingGates returns the (pr, environment) gates that still have at least one target not yet ACTIVE — i.e. gates whose verdict may still need posting. The reconcile loop walks these to self-heal the gap where an approval event is processed while the grant is still activating (some providers fire no further event for the activating→active transition) and dropped events / restarts.

type GateTarget

type GateTarget struct {
	Class     string
	Target    string
	GrantName string
	State     string
	Requester string
}

GateTarget holds the per-(class,target) grant state recorded for a (pr, environment).

func TargetsFor

func TargetsFor(db *sql.DB, pr int, environment string) ([]GateTarget, error)

TargetsFor returns every GateTarget recorded for (pr, environment). Returns a non-nil empty slice when none match.

type OpenGrantPR added in v0.10.0

type OpenGrantPR struct {
	PR   int
	Repo string
}

OpenGrantPR is a PR that still holds at least one open (non-terminal) grant, paired with the repo of its latest execution (for the orphan sweep's GitHub closed-state check). Repo is "" when no execution row exists.

func OpenGrantPRs added in v0.10.0

func OpenGrantPRs(db *sql.DB) ([]OpenGrantPR, error)

OpenGrantPRs returns every PR with at least one gate target in an open state (AWAITING/ACTIVATING/ACTIVE), each paired with its latest execution's repo. Unlike PendingGates it INCLUDES fully-ACTIVE (Satisfied) gates — the merged-PR orphan whose grants were never revoked — which is exactly what the sweep must re-examine. Terminal states (DENIED/REVOKED/EXPIRED) are deliberately excluded: those grants are no longer live, so the sweep has nothing to revoke for them (an EXPIRED grant the reconciler may later re-arm becomes AWAITING again — open — and is caught on the next sweep). A PR is one row regardless of how many environments hold open grants (GROUP BY pr); revokeOrphans handles every env.

type PRMeta added in v0.27.0

type PRMeta struct {
	Repo        string
	PR          int
	Title       string
	Body        string
	AuthorLogin string
	HeadRef     string
	URL         string
	AutoMerge   bool
	UpdatedAt   time.Time
}

PRMeta is a row of the pr_meta table: PR-level identity (title, author, branch, automerge) as reported by the GitHub webhook, keyed by (repo, pr).

func GetPRMeta added in v0.27.0

func GetPRMeta(db *sql.DB, repo string, pr int) (PRMeta, bool, error)

GetPRMeta loads the metadata row for (repo, pr). ok is false when no row exists (absent is not an error).

func GetPRMetaByPR added in v0.27.0

func GetPRMetaByPR(db *sql.DB, pr int) (PRMeta, bool, error)

GetPRMetaByPR loads the metadata row for pr without requiring the caller to know repo up front. The webhook writes pr_meta on PR open/sync, before any execution exists (executions appear only once the runner calls /api/init) — so a repo-keyed lookup derived from "latest execution's repo" misses real rows in that window. A serve is effectively single-repo, but this queries by pr alone so the meta lookup never depends on an execution existing. When multiple rows exist for pr (should not happen in practice), the most recently updated one wins. ok is false when no row exists (absent is not an error).

type PRTarget added in v0.9.5

type PRTarget struct {
	Environment string
	Class       string
	Target      string
}

PRTarget is a (environment, class, target) tuple recorded for a PR, used by the PR-closed webhook to revoke orphaned grants across all environments.

func PRTargets added in v0.9.5

func PRTargets(db *sql.DB, pr int) ([]PRTarget, error)

PRTargets returns every (environment, class, target) recorded for pr across all environments. Returns a non-nil empty slice when none match.

type PendingApproval added in v0.25.0

type PendingApproval struct {
	PR          int
	Environment string
	Repo        string
	Class       string
	Target      string
	GrantName   string
	State       string
	Requester   string
}

PendingApproval is one gate target awaiting human action, joined with the PR context a reviewer needs: the repo comes from the (pr, environment)'s latest execution ("" when none exists yet).

func PendingApprovals added in v0.25.0

func PendingApprovals(db *sql.DB) ([]PendingApproval, error)

PendingApprovals returns every gate target not yet ACTIVE, across all PRs and environments — the cross-PR approvals to-do list (same non-ACTIVE predicate as PendingGates, so DENIED/REVOKED targets surface too: they need attention, not approval). Returns a non-nil empty slice when none match.

type PhaseRow added in v0.37.0

type PhaseRow struct {
	Phase string
	Label string
	At    time.Time
}

PhaseRow is one recorded lifecycle phase transition of an execution.

func PhasesFor added in v0.37.0

func PhasesFor(db *sql.DB, executionID string) ([]PhaseRow, error)

PhasesFor returns an execution's recorded phase transitions, oldest first (by insert time, rowid as a stable tiebreaker for same-second inserts).

type ProjectedExecution added in v0.43.0

type ProjectedExecution struct {
	ID            string
	Repo          string
	SHA           string
	PR            int
	Environment   string
	Context       string
	LogURL        string
	Phase         string
	Status        string
	ProgressLabel string
	ProgressPct   *int
	SupersededBy  string
}

ProjectedExecution is the execution-aggregate-owned projection of an executions row, written by the (forthcoming) event-sourced projector.

type ProjectedStack added in v0.43.0

type ProjectedStack struct {
	Path       string
	Project    string
	Status     events.Status
	Detail     string
	Categories []events.Category
	Counts     *events.Counts
}

ProjectedStack is the execution-aggregate-owned projection of a stacks row.

type StoredEvent added in v0.17.0

type StoredEvent struct {
	Type string
	Data []byte
}

StoredEvent is one opaque appended fact. Type is an event-type tag and Data is the opaque payload (JSON bytes in practice). The store never interprets either.

Directories

Path Synopsis
Package migrations embeds the goose SQL migrations for the server store.
Package migrations embeds the goose SQL migrations for the server store.

Jump to

Keyboard shortcuts

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