feat: resolve old inline comments when superseding review
CI / test (pull_request) Successful in 14s
CI / review (gpt-4.1, gpt, GPT_REVIEW_TOKEN) (pull_request) Successful in 21s
CI / review (gpt-5, security, SECURITY_REVIEW.md, SECURITY_REVIEW_TOKEN) (pull_request) Successful in 42s
CI / review (gpt-5, sonnet, SONNET_REVIEW_TOKEN) (pull_request) Successful in 1m1s
CI / test (pull_request) Successful in 14s
CI / review (gpt-4.1, gpt, GPT_REVIEW_TOKEN) (pull_request) Successful in 21s
CI / review (gpt-5, security, SECURITY_REVIEW.md, SECURITY_REVIEW_TOKEN) (pull_request) Successful in 42s
CI / review (gpt-5, sonnet, SONNET_REVIEW_TOKEN) (pull_request) Successful in 1m1s
Closes #27 After superseding an old review, resolves all its inline comments via POST /pulls/comments/{id}/resolve. This clears unresolved conversation markers from the PR timeline/diff view. New API methods: - ListReviewComments: GET /repos/.../pulls/{n}/reviews/{id}/comments - ResolveComment: POST /repos/.../pulls/comments/{id}/resolve Failures are non-fatal (debug log) — the review still posts and supersedes even if resolution fails.
This commit is contained in:
@@ -362,6 +362,27 @@ func main() {
|
||||
} else {
|
||||
slog.Info("marked old review as superseded", "old_state", existingReview.State, "new_review_id", posted.ID, "pr", prNumber)
|
||||
}
|
||||
|
||||
// Resolve old review's inline comments (clears unresolved conversations in PR timeline)
|
||||
oldComments, err := giteaClient.ListReviewComments(ctx, owner, repoName, prNumber, existingReview.ID)
|
||||
if err != nil {
|
||||
slog.Warn("could not list old review comments for resolution", "review_id", existingReview.ID, "error", err)
|
||||
} else {
|
||||
resolved := 0
|
||||
for _, c := range oldComments {
|
||||
if c.ID == 0 {
|
||||
continue
|
||||
}
|
||||
if err := giteaClient.ResolveComment(ctx, owner, repoName, c.ID); err != nil {
|
||||
slog.Debug("could not resolve inline comment", "comment_id", c.ID, "error", err)
|
||||
} else {
|
||||
resolved++
|
||||
}
|
||||
}
|
||||
if resolved > 0 {
|
||||
slog.Info("resolved old inline comments", "count", resolved, "pr", prNumber)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -82,6 +82,7 @@ type ChangedFile struct {
|
||||
|
||||
// ReviewComment represents an inline comment to attach to a review.
|
||||
type ReviewComment struct {
|
||||
ID int64 `json:"id,omitempty"`
|
||||
Path string `json:"path"`
|
||||
NewPosition int64 `json:"new_position"`
|
||||
Body string `json:"body"`
|
||||
@@ -460,3 +461,49 @@ func (c *Client) EditComment(ctx context.Context, owner, repo string, commentID
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// ListReviewComments returns the inline comments attached to a specific review.
|
||||
func (c *Client) ListReviewComments(ctx context.Context, owner, repo string, prNumber int, reviewID int64) ([]ReviewComment, error) {
|
||||
reqURL := fmt.Sprintf("%s/api/v1/repos/%s/%s/pulls/%d/reviews/%d/comments",
|
||||
c.baseURL,
|
||||
url.PathEscape(owner),
|
||||
url.PathEscape(repo),
|
||||
prNumber,
|
||||
reviewID)
|
||||
body, err := c.doGet(ctx, reqURL)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("list review comments: %w", err)
|
||||
}
|
||||
var comments []ReviewComment
|
||||
if err := json.Unmarshal(body, &comments); err != nil {
|
||||
return nil, fmt.Errorf("parse review comments: %w", err)
|
||||
}
|
||||
return comments, nil
|
||||
}
|
||||
|
||||
// ResolveComment marks an inline review comment as resolved.
|
||||
func (c *Client) ResolveComment(ctx context.Context, owner, repo string, commentID int64) error {
|
||||
reqURL := fmt.Sprintf("%s/api/v1/repos/%s/%s/pulls/comments/%d/resolve",
|
||||
c.baseURL,
|
||||
url.PathEscape(owner),
|
||||
url.PathEscape(repo),
|
||||
commentID)
|
||||
|
||||
req, err := http.NewRequestWithContext(ctx, http.MethodPost, reqURL, nil)
|
||||
if err != nil {
|
||||
return fmt.Errorf("create resolve request: %w", err)
|
||||
}
|
||||
req.Header.Set("Authorization", "token "+c.token)
|
||||
|
||||
resp, err := c.http.Do(req)
|
||||
if err != nil {
|
||||
return fmt.Errorf("resolve comment: %w", err)
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
if resp.StatusCode != http.StatusOK && resp.StatusCode != http.StatusCreated && resp.StatusCode != http.StatusNoContent {
|
||||
body, _ := io.ReadAll(resp.Body)
|
||||
return fmt.Errorf("resolve comment failed (status %d): %s", resp.StatusCode, body)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user