Go · 2492 bytes Raw Blame History
1 // SPDX-License-Identifier: AGPL-3.0-or-later
2
3 // Package review owns PR-review orchestration: inline comments,
4 // review submission with attached pending comments, dismissal,
5 // reviewer requests, thread resolution, and the required-reviews
6 // gate consulted by the merge handler.
7 //
8 // Diff-position anchoring model (matches GitHub's contract): each
9 // comment captures (file_path, side, original_commit_sha,
10 // original_line, original_position). The PR synchronize pipeline
11 // re-walks the diff against the new head and updates each comment's
12 // current_position; comments whose anchor line no longer exists go
13 // to current_position=NULL ("outdated"). The position mapping
14 // helper here is invoked from `pulls.Synchronize`.
15 package review
16
17 import (
18 "context"
19 "errors"
20 "log/slog"
21
22 "github.com/jackc/pgx/v5/pgxpool"
23
24 mdrender "github.com/tenseleyFlow/shithub/internal/markdown"
25 )
26
27 // Deps wires this package into the runtime.
28 type Deps struct {
29 Pool *pgxpool.Pool
30 Logger *slog.Logger
31 }
32
33 // Errors surfaced to handlers.
34 var (
35 ErrEmptyBody = errors.New("review: comment body is required")
36 ErrBodyTooLong = errors.New("review: body too long")
37 ErrAuthorCannotApprove = errors.New("review: author cannot approve their own PR")
38 ErrInvalidState = errors.New("review: state must be comment, approve, or request_changes")
39 ErrCommentNotOnPR = errors.New("review: comment does not belong to this PR")
40 ErrAlreadyResolved = errors.New("review: thread already resolved")
41 ErrNotResolved = errors.New("review: thread is not resolved")
42 ErrReviewerLimitReached = errors.New("review: 20 reviewers max per PR")
43 ErrReviewerAlreadyPending = errors.New("review: reviewer already requested")
44 ErrReviewNotFound = errors.New("review: review not found")
45 )
46
47 // MaxReviewersPerPR caps active review requests per PR. Matches the
48 // spec pitfall section.
49 const MaxReviewersPerPR = 20
50
51 // renderBodyHTML wraps markdown.RenderHTML with a logger-aware error
52 // path. Review/comment body length is bounded upstream at 65535 chars
53 // by the orchestrator. ErrInputTooLarge here means a precondition
54 // regressed — log loudly. (S00-S25 audit, M.)
55 func renderBodyHTML(ctx context.Context, deps Deps, body string) string {
56 html, err := mdrender.RenderHTML([]byte(body))
57 if err != nil && deps.Logger != nil {
58 deps.Logger.WarnContext(ctx, "review: markdown render failed",
59 "error", err, "body_bytes", len(body))
60 }
61 return html
62 }
63