feat: delete previous review before posting new one (#6) #22
@@ -205,6 +205,14 @@ On the next run, it finds and deletes any review containing its own sentinel (ex
|
|||||||
|
|
||||||
If `reviewer-name` is empty, cleanup is skipped (reviews stack like before).
|
If `reviewer-name` is empty, cleanup is skipped (reviews stack like before).
|
||||||
|
|
||||||
|
### Shared Token: Worst-Wins Behavior
|
||||||
|
|
||||||
|
When multiple review types share the same Gitea bot account (e.g. code-quality and security), Gitea determines the user's approval state from their **most recent review**. This creates a race condition: if security finds issues (REQUEST_CHANGES) but code-quality finishes last (APPROVE), the PR appears approved.
|
||||||
|
|
||||||
|
review-bot handles this automatically with **worst-wins reconciliation**: before posting, each job checks whether any sibling review from the same user already has REQUEST_CHANGES. If so and this job would post APPROVE, it posts as REQUEST_CHANGES instead — maintaining the block. This ensures the PR stays blocked until all checks pass, regardless of execution order.
|
||||||
|
|
||||||
|
**If you need independent approval/block per review type**, use separate Gitea bot accounts with their own tokens.
|
||||||
|
|
||||||
## Custom Review Prompts
|
## Custom Review Prompts
|
||||||
|
|
||||||
Use `system-prompt-file` to specialize the review focus. The file contents are appended to the base system prompt as "Additional Review Instructions."
|
Use `system-prompt-file` to specialize the review focus. The file contents are appended to the base system prompt as "Additional Review Instructions."
|
||||||
|
|||||||
@@ -226,6 +226,26 @@ func main() {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Worst-wins: if we're about to APPROVE but a sibling review from the same
|
||||||
|
// user already has REQUEST_CHANGES, post as REQUEST_CHANGES too so we don't
|
||||||
|
// override the blocking state.
|
||||||
|
if event == "APPROVED" && *reviewerName != "" {
|
||||||
|
existing, err := giteaClient.ListReviews(ctx, owner, repoName, prNumber)
|
||||||
|
if err == nil {
|
||||||
|
for _, r := range existing {
|
||||||
|
if !r.Stale && r.State == "REQUEST_CHANGES" {
|
||||||
|
// Check it's from the same user (same token) but a different role
|
||||||
|
sentinelCheck := fmt.Sprintf("<!-- review-bot:%s -->", *reviewerName)
|
||||||
|
if !strings.Contains(r.Body, sentinelCheck) {
|
||||||
|
log.Printf("Sibling review %d has REQUEST_CHANGES; escalating to REQUEST_CHANGES", r.ID)
|
||||||
|
event = "REQUEST_CHANGES"
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
log.Printf("Posting review (event=%s)...", event)
|
log.Printf("Posting review (event=%s)...", event)
|
||||||
posted, err := giteaClient.PostReview(ctx, owner, repoName, prNumber, event, reviewBody)
|
posted, err := giteaClient.PostReview(ctx, owner, repoName, prNumber, event, reviewBody)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -249,6 +269,7 @@ func main() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user