Documentation
¶
Overview ¶
Package store owns the database schema, GORM models, repositories, and the goose-driven migration runner. Callers depend on small interfaces declared where they consume the store (handler packages); only this package needs to know about GORM.
Index ¶
- Variables
- func MigrateDown(ctx context.Context, db *gorm.DB) error
- func MigrateStatus(ctx context.Context, db *gorm.DB) (string, error)
- func MigrateUp(ctx context.Context, db *gorm.DB) error
- func NewTestDB(t *testing.T) *gorm.DB
- func Open(url string) (*gorm.DB, error)
- func RawCreateForTest(db *gorm.DB, pr PullRequest) error
- func SQLDB(db *gorm.DB) (*sql.DB, error)
- type CodeReview
- type CodeReviews
- func (r *CodeReviews) ActiveForUser(ctx context.Context, repository string, prNumber int, slackUserID string) (CodeReview, error)
- func (r *CodeReviews) Finish(ctx context.Context, repository string, prNumber int) error
- func (r *CodeReviews) GetActive(ctx context.Context, repository string, prNumber int) (CodeReview, error)
- func (r *CodeReviews) Reviewers(ctx context.Context, repository string, prNumber int) ([]CodeReview, error)
- func (r *CodeReviews) Start(ctx context.Context, repository string, prNumber int, ...) error
- type Message
- type PullRequest
- type PullRequests
- func (r *PullRequests) AddMessage(ctx context.Context, repository string, prNumber int, ...) error
- func (r *PullRequests) Delete(ctx context.Context, repository string, prNumber int) error
- func (r *PullRequests) DeleteStaleBefore(ctx context.Context, cutoff time.Time) (int64, error)
- func (r *PullRequests) FindStuck(ctx context.Context, cutoff time.Time) ([]PullRequest, error)
- func (r *PullRequests) ListOpen(ctx context.Context) ([]PullRequest, error)
- func (r *PullRequests) MarkClosed(ctx context.Context, repository string, prNumber int) error
- func (r *PullRequests) Messages(ctx context.Context, repository string, prNumber int) ([]Message, error)
- func (r *PullRequests) Touch(ctx context.Context, repository string, prNumber int) error
- type Reactions
- type RepoMapping
- type Target
Constants ¶
This section is empty.
Variables ¶
var ErrActiveReviewExists = errors.New("store: active code review exists")
ErrActiveReviewExists is returned by Start when the same user already has an active review on the PR — the partial unique index rejected the insert. Callers surface the conflict UX ("already reviewing") instead of a 500.
var ErrNotFound = errors.New("store: not found")
ErrNotFound is returned when a lookup matches no row.
Functions ¶
func MigrateDown ¶
MigrateDown rolls back the most recent migration.
func MigrateStatus ¶
MigrateStatus returns a human-readable list of each migration and whether it has been applied.
func NewTestDB ¶
NewTestDB returns a *gorm.DB backed by a fresh on-disk SQLite database inside t.TempDir, with all migrations applied. The database is closed and removed automatically when the test completes.
We use an on-disk file rather than `:memory:` because the goose-sqlite driver expects a stable database name to record migration state, and multiple in-memory connections in the same process are not always shared.
func Open ¶
Open opens a SQLite database for production use. The url accepts either a raw file path or the "file:..." DSN form used in our config defaults.
GORM's logger is silenced for "record not found" because we treat ErrNotFound as a normal return value, not a warning condition.
func RawCreateForTest ¶
func RawCreateForTest(db *gorm.DB, pr PullRequest) error
RawCreateForTest inserts a pull_requests row preserving the caller's CreatedAt/UpdatedAt/ClosedAt, bypassing GORM's autoCreate/UpdateTime. Used by tests that need to seed PRs with a controlled age and open/closed state. A zero CreatedAt defaults to UpdatedAt.
Types ¶
type CodeReview ¶ added in v0.21.0
type CodeReview struct {
ID uint `gorm:"primaryKey"`
PullRequestID uint `gorm:"column:pull_request_id;not null"`
SlackUserID string `gorm:"column:slack_user_id;not null"`
SlackUserName string `gorm:"column:slack_user_name"`
StartedAt time.Time `gorm:"column:started_at;not null"`
FinishedAt *time.Time `gorm:"column:finished_at"`
}
CodeReview is one review "session" for a PR: who started reviewing it and when, with FinishedAt nil while the review is in progress and set once the reviewer's GitHub review lands. It hangs off a PullRequest (cascade-deleted with it) and a partial unique index enforces at most one active (FinishedAt IS NULL) review per PR — finished rows accumulate as history.
func (CodeReview) TableName ¶ added in v0.21.0
func (CodeReview) TableName() string
TableName pins the table name.
type CodeReviews ¶ added in v0.21.0
type CodeReviews struct {
// contains filtered or unexported fields
}
CodeReviews persists per-PR review sessions and enforces at most one active review per (PR, user); multiple distinct users may review a PR concurrently. A review is identified to callers by its PR's natural key (repository, prNumber); the surrogate pull_request_id is resolved internally.
func NewCodeReviews ¶ added in v0.21.0
func NewCodeReviews(db *gorm.DB) *CodeReviews
NewCodeReviews constructs a CodeReviews repository bound to db.
func (*CodeReviews) ActiveForUser ¶ added in v0.21.0
func (r *CodeReviews) ActiveForUser(ctx context.Context, repository string, prNumber int, slackUserID string) (CodeReview, error)
ActiveForUser returns the user's active (unfinished) review on the PR, or ErrNotFound when that user has no review in progress here. It is the app-level guard the click handler checks before Start; the DB's partial unique index on (pull_request_id, slack_user_id) is the race-safe backstop.
func (*CodeReviews) Finish ¶ added in v0.21.0
Finish marks the PR's active review finished. It is idempotent: no active review (or an untracked PR) is a no-op, mirroring MarkClosed.
func (*CodeReviews) GetActive ¶ added in v0.21.0
func (r *CodeReviews) GetActive(ctx context.Context, repository string, prNumber int) (CodeReview, error)
GetActive returns the PR's active (unfinished) review, or ErrNotFound when the PR is untracked or has no review in progress.
func (*CodeReviews) Reviewers ¶ added in v0.21.0
func (r *CodeReviews) Reviewers(ctx context.Context, repository string, prNumber int) ([]CodeReview, error)
Reviewers returns all code-review sessions for the PR ordered by started_at ascending (earliest first). An untracked PR or a PR with no reviews returns an empty slice and nil error.
func (*CodeReviews) Start ¶ added in v0.21.0
func (r *CodeReviews) Start(ctx context.Context, repository string, prNumber int, slackUserID, slackUserName string) error
Start opens a review on the PR for the given Slack user. It returns ErrNotFound when the PR is not tracked, and ErrActiveReviewExists when the PR already has an active review — the DB's partial unique index is the source of truth, so two near-simultaneous Starts can't both win.
type Message ¶ added in v0.20.0
type Message struct {
ID uint `gorm:"primaryKey"`
PullRequestID uint `gorm:"column:pull_request_id;not null"`
Channel string `gorm:"column:channel;not null"`
MessageID string `gorm:"column:message_id;not null"`
}
Message is one posted messenger message for a PR. (PullRequestID, Channel) is unique — at most one message per channel per PR. Channel is a room in the messenger; MessageID is the messenger's id for the post (Slack's ts).
type PullRequest ¶ added in v0.20.0
type PullRequest struct {
ID uint `gorm:"primaryKey"`
Repository string `gorm:"column:gh_repository;not null"`
PRNumber int `gorm:"column:pr_number;not null"`
CreatedAt time.Time `gorm:"column:created_at;not null"`
UpdatedAt time.Time `gorm:"column:updated_at;not null"`
ClosedAt *time.Time `gorm:"column:closed_at"`
Messages []Message `gorm:"foreignKey:PullRequestID;constraint:OnDelete:CASCADE"`
}
PullRequest is one tracked PR. (Repository, PRNumber) is the natural key; CreatedAt is kept for later statistics, UpdatedAt is the activity clock (bumped on open and every review/comment) driving digest idle-detection and cleanup, and ClosedAt (nil = open) marks merged/closed so the digest skips it.
func (PullRequest) TableName ¶ added in v0.20.0
func (PullRequest) TableName() string
TableName pins the table name; do not rely on GORM pluralization.
type PullRequests ¶ added in v0.20.0
type PullRequests struct {
// contains filtered or unexported fields
}
PullRequests persists tracked PRs and their per-channel messenger messages.
func NewPullRequests ¶ added in v0.20.0
func NewPullRequests(db *gorm.DB) *PullRequests
NewPullRequests constructs a PullRequests repository bound to db.
func (*PullRequests) AddMessage ¶ added in v0.20.0
func (r *PullRequests) AddMessage(ctx context.Context, repository string, prNumber int, channel, messageID string) error
AddMessage records one posted message, creating the PR row on first sight. Insertion is idempotent on (pull_request_id, channel): re-adding the same channel for the same PR is a no-op, which makes the open fan-out safe to replay after a partial failure or GitHub redelivery.
func (*PullRequests) Delete ¶ added in v0.20.0
Delete removes the PR and (by cascade) its messages. Missing PR is a no-op.
func (*PullRequests) DeleteStaleBefore ¶ added in v0.20.0
DeleteStaleBefore removes PRs idle since before cutoff (messages cascade).
func (*PullRequests) FindStuck ¶ added in v0.20.0
func (r *PullRequests) FindStuck(ctx context.Context, cutoff time.Time) ([]PullRequest, error)
FindStuck returns open PRs idle since before cutoff, messages preloaded, oldest first.
func (*PullRequests) ListOpen ¶ added in v0.20.0
func (r *PullRequests) ListOpen(ctx context.Context) ([]PullRequest, error)
ListOpen returns every not-yet-closed PR, ordered for stable output.
func (*PullRequests) MarkClosed ¶ added in v0.20.0
MarkClosed sets closed_at. Missing PR is a no-op.
type Reactions ¶ added in v0.18.0
type Reactions struct {
Enabled bool
NewPR string
MergedPR string
ClosedPR string
Approved string
Commented string
RequestChange string
BotReview string
}
Reactions is the resolved per-repo reaction-emoji set (Slack emoji names without colons). Enabled gates whether close/review reactions are added at all. Empty BotReview disables the bot-reviewer marker.
type RepoMapping ¶
type RepoMapping struct {
Repository string
SlackChannel string
Mentions []string
// Resolved per-repo behavioral config (global config.yaml defaults merged
// with org/* and org/repo overrides). Formatting-only — not part of
// validation or the lock.
Reactions Reactions
IgnoreAIReviews bool
DependabotFormat bool
}
RepoMapping is the value object handlers and validators consume — a GitHub repository routed to a Slack channel with an optional mentions list, and resolved behavioral config (global defaults merged with org/* and org/repo overrides). The source of truth for routing lives in config.yaml's mappings: section (loaded by internal/config / internal/mappings); the type stays here so consumers don't have to know who produced it.