Help us shape the future of Go! Take the 2026 Go Developer Survey

review

package
v0.1.0 Latest Latest
Warning

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

Go to latest
Published: May 10, 2026 License: AGPL-3.0 Imports: 16 Imported by: 0

Documentation

Overview

Package review owns PR-review orchestration: inline comments, review submission with attached pending comments, dismissal, reviewer requests, thread resolution, and the required-reviews gate consulted by the merge handler.

Diff-position anchoring model (matches GitHub's contract): each comment captures (file_path, side, original_commit_sha, original_line, original_position). The PR synchronize pipeline re-walks the diff against the new head and updates each comment's current_position; comments whose anchor line no longer exists go to current_position=NULL ("outdated"). The position mapping helper here is invoked from `pulls.Synchronize`.

Index

Constants

View Source
const MaxReviewersPerPR = 20

MaxReviewersPerPR caps active review requests per PR. Matches the spec pitfall section.

Variables

View Source
var (
	ErrEmptyBody              = errors.New("review: comment body is required")
	ErrBodyTooLong            = errors.New("review: body too long")
	ErrAuthorCannotApprove    = errors.New("review: author cannot approve their own PR")
	ErrInvalidState           = errors.New("review: state must be comment, approve, or request_changes")
	ErrCommentNotOnPR         = errors.New("review: comment does not belong to this PR")
	ErrAlreadyResolved        = errors.New("review: thread already resolved")
	ErrNotResolved            = errors.New("review: thread is not resolved")
	ErrReviewerLimitReached   = errors.New("review: 20 reviewers max per PR")
	ErrReviewerAlreadyPending = errors.New("review: reviewer already requested")
	ErrReviewNotFound         = errors.New("review: review not found")
)

Errors surfaced to handlers.

Functions

func AddComment

func AddComment(ctx context.Context, deps Deps, p CommentParams) (pullsdb.PrReviewComment, error)

AddComment inserts a single inline comment. When InReplyToID is set the new comment threads under that one (validated to belong to the same PR). Markdown is rendered to body_html_cached at insert time.

func Dismiss

func Dismiss(ctx context.Context, deps Deps, actorUserID, reviewID int64, reason string) error

Dismiss flips a review's dismissed_at + reason. Caller has already gated on policy (typically repo admin only).

func EditComment

func EditComment(ctx context.Context, deps Deps, commentID int64, body string) error

EditComment updates the body of an existing comment. Caller is expected to have already enforced "actor == comment.author OR repo admin" via policy.

func RemapAllForPR

func RemapAllForPR(ctx context.Context, deps Deps, gitDir string, prID int64, newBaseOID, newHeadOID string) error

RemapAllForPR re-anchors every non-draft review comment on a PR against the new (base, head) snapshot. For each comment we do a content-aware check:

  1. Read the line text at (original_commit_sha, file_path, original_line). This is what the comment was written against.
  2. Read the same line number in the new blob (newHeadOID for side=right; newBaseOID for side=left).
  3. If the bytes are identical → keep current_position = original_line. If not → current_position = NULL (outdated). The comment still renders in the conversation timeline; the Files tab hides it until the user clicks "Show outdated."

This is the conservative v1 mapper. Lines that have been re-indented, shifted by an insertion above, or merely had a comma added all outdate — that's the right default. The spec calls out `git blame --porcelain` as a richer mapper for rebase-heavy PRs; add that when the simple presence check proves too aggressive.

Idempotent: re-running converges on the same answer.

func Reopen

func Reopen(ctx context.Context, deps Deps, commentID int64) error

Reopen clears the resolved-at marker on a thread.

func Request

Request creates a pr_review_requests row. Bounded by MaxReviewersPerPR per the spec pitfalls section.

func Resolve

func Resolve(ctx context.Context, deps Deps, actorUserID, commentID int64) error

Resolve marks the thread (root + replies) resolved. The "thread" is keyed off the comment id; UI walks `in_reply_to_id` to render replies, so resolving the root collapses the whole conversation. Default-collapsed in the Files tab; "Show resolved" toggle reopens.

func Submit

func Submit(ctx context.Context, deps Deps, p SubmitParams) (pullsdb.PrReview, error)

Submit records the review row, attaches every pending draft comment the author has on this PR to the new review (one tx), and emits a `reviewed` timeline event with the state. Pending review-request rows owned by the author are satisfied when state is approve or request_changes.

Types

type CommentParams

type CommentParams struct {
	PRIssueID         int64
	AuthorUserID      int64
	FilePath          string
	Side              string // "left" | "right"
	OriginalCommitSHA string
	OriginalLine      int32
	OriginalPosition  int32
	CurrentPosition   int32 // -1 means already outdated (rare on insert)
	Body              string
	InReplyToID       int64 // 0 means top-level
	Pending           bool
}

CommentParams describes a single inline comment on a PR. When `Pending` is true the comment is filed as a draft attached to the author's pending review (review_id stays NULL); SubmitReview later flips pending=false and sets review_id.

type Deps

type Deps struct {
	Pool   *pgxpool.Pool
	Logger *slog.Logger
}

Deps wires this package into the runtime.

type GateInputs

type GateInputs struct {
	RepoID    int64
	BaseRef   string
	PRIssueID int64
}

GateInputs is the small struct the merge gate cares about.

type GateResult

type GateResult struct {
	// Satisfied — the PR meets the review requirements (or none apply).
	Satisfied bool
	// Reason — short human-readable cause when not satisfied. Used by
	// the UI banner ("Approval required (1/1 reviews missing)").
	Reason string
	// RequiredCount — the rule's required_review_count.
	RequiredCount int
	// CurrentApprovals — count of "latest review per author" with state
	// approve. Always excludes the PR author.
	CurrentApprovals int
	// HasRequestChanges — at least one undismissed `request_changes`
	// review whose author hasn't superseded it with a later approve.
	HasRequestChanges bool
}

GateResult mirrors the spec's mergeable_state vocabulary for review-side blocks.

func Evaluate

func Evaluate(ctx context.Context, pool *pgxpool.Pool, in GateInputs, prAuthorUserID int64) (GateResult, error)

Evaluate computes the gate against the matching branch-protection rule. Returns Satisfied=true when no rule matches the base ref or when the rule's required_review_count == 0 and no unresolved request_changes reviews exist.

"Latest review per author" semantics: when an author submits a request_changes and later submits an approve, only the approve counts. When two distinct authors approve and one of them later submits a comment, both still count for the approval tally — only approve and request_changes shift the per-author state.

type RequestParams

type RequestParams struct {
	PRIssueID         int64
	RequestedUserID   int64
	RequestedByUserID int64
}

RequestParams describes a review-request action.

type SubmitParams

type SubmitParams struct {
	PRIssueID    int64
	AuthorUserID int64
	State        string // "comment" | "approve" | "request_changes"
	Body         string
	// PRAuthorUserID is the issues.author_user_id of the PR — used to
	// reject self-approval. Caller passes it in to keep this package
	// from cross-importing the pulls orchestrator.
	PRAuthorUserID int64
}

SubmitParams describes the submit-a-review action.

Jump to

Keyboard shortcuts

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