feat: add context.Context + unexport client fields
CI / test (pull_request) Successful in 13s
CI / review (gpt-5, sonnet, SONNET_REVIEW_TOKEN) (pull_request) Successful in 54s
CI / review (gpt-5-mini, gpt, GPT_REVIEW_TOKEN) (pull_request) Successful in 1m22s

REVIEW.md findings 1-4, 14:
- All Gitea client methods now accept context.Context as first param
- All LLM client methods now accept context.Context as first param
- Use http.NewRequestWithContext for cancellation/timeout support
- Main uses 3-minute timeout context for all operations
- Unexport Client struct fields (baseURL, token, apiKey, etc.)
- Use bytes.NewReader instead of strings.NewReader(string(...))
This commit is contained in:
Rodin
2026-05-01 12:31:41 -07:00
parent f77ea171c3
commit 27e0056f29
6 changed files with 112 additions and 99 deletions
+19 -13
View File
@@ -1,12 +1,14 @@
package main
import (
"context"
"flag"
"fmt"
"log"
"os"
"strconv"
"strings"
"time"
"gitea.weiker.me/rodin/review-bot/gitea"
"gitea.weiker.me/rodin/review-bot/llm"
@@ -64,17 +66,21 @@ func main() {
llmClient.WithTemperature(*llmTemp)
}
// Create a top-level context with a 3-minute timeout for all operations
ctx, cancel := context.WithTimeout(context.Background(), 3*time.Minute)
defer cancel()
log.Printf("Reviewing PR #%d on %s/%s", prNumber, owner, repoName)
// Step 1: Fetch PR metadata
pr, err := giteaClient.GetPullRequest(owner, repoName, prNumber)
pr, err := giteaClient.GetPullRequest(ctx, owner, repoName, prNumber)
if err != nil {
log.Fatalf("Failed to fetch PR: %v", err)
}
log.Printf("PR: %s", pr.Title)
// Step 2: Fetch diff
diff, err := giteaClient.GetPullRequestDiff(owner, repoName, prNumber)
diff, err := giteaClient.GetPullRequestDiff(ctx, owner, repoName, prNumber)
if err != nil {
log.Fatalf("Failed to fetch diff: %v", err)
}
@@ -82,11 +88,11 @@ func main() {
// Step 3: Fetch full file content for modified files
fileContext := ""
files, err := giteaClient.GetPullRequestFiles(owner, repoName, prNumber)
files, err := giteaClient.GetPullRequestFiles(ctx, owner, repoName, prNumber)
if err != nil {
log.Printf("Warning: could not fetch PR files list: %v", err)
} else {
fileContext = fetchFileContext(giteaClient, owner, repoName, pr.Head.Ref, files)
fileContext = fetchFileContext(ctx, giteaClient, owner, repoName, pr.Head.Ref, files)
log.Printf("Fetched full context for %d files", len(files))
}
@@ -94,7 +100,7 @@ func main() {
ciPassed := true
ciDetails := ""
if pr.Head.Sha != "" {
statuses, err := giteaClient.GetCommitStatuses(owner, repoName, pr.Head.Sha)
statuses, err := giteaClient.GetCommitStatuses(ctx, owner, repoName, pr.Head.Sha)
if err != nil {
log.Printf("Warning: could not fetch CI status: %v", err)
} else {
@@ -106,7 +112,7 @@ func main() {
// Step 5: Load conventions file if specified
conventions := ""
if *conventionsFile != "" {
content, err := giteaClient.GetFileContent(owner, repoName, *conventionsFile)
content, err := giteaClient.GetFileContent(ctx, owner, repoName, *conventionsFile)
if err != nil {
log.Printf("Warning: could not load conventions file %q: %v", *conventionsFile, err)
} else {
@@ -118,7 +124,7 @@ func main() {
// Step 6: Load patterns from external repo if specified
patterns := ""
if *patternsRepo != "" {
patterns = fetchPatterns(giteaClient, *patternsRepo, *patternsFiles)
patterns = fetchPatterns(ctx, giteaClient, *patternsRepo, *patternsFiles)
log.Printf("Loaded patterns from %s (%d bytes)", *patternsRepo, len(patterns))
}
@@ -133,7 +139,7 @@ func main() {
{Role: "user", Content: userPrompt},
}
response, err := llmClient.Complete(messages)
response, err := llmClient.Complete(ctx, messages)
if err != nil {
log.Fatalf("LLM request failed: %v", err)
}
@@ -158,20 +164,20 @@ func main() {
}
log.Printf("Posting review (event=%s)...", event)
if err := giteaClient.PostReview(owner, repoName, prNumber, event, reviewBody); err != nil {
if err := giteaClient.PostReview(ctx, owner, repoName, prNumber, event, reviewBody); err != nil {
log.Fatalf("Failed to post review: %v", err)
}
log.Printf("Review posted successfully!")
}
// fetchFileContext fetches the full content of modified files from the PR branch.
func fetchFileContext(client *gitea.Client, owner, repo, ref string, files []gitea.ChangedFile) string {
func fetchFileContext(ctx context.Context, client *gitea.Client, owner, repo, ref string, files []gitea.ChangedFile) string {
var sb strings.Builder
for _, f := range files {
if f.Status == "removed" {
continue // Skip deleted files
}
content, err := client.GetFileContentRef(owner, repo, f.Filename, ref)
content, err := client.GetFileContentRef(ctx, owner, repo, f.Filename, ref)
if err != nil {
log.Printf("Warning: could not fetch %s: %v", f.Filename, err)
continue
@@ -188,7 +194,7 @@ func fetchFileContext(client *gitea.Client, owner, repo, ref string, files []git
// patternsRepo is comma-separated list of owner/name repos.
// patternsFiles is comma-separated list of file paths or directories.
// If a path ends with / or is a directory, all files within it are fetched recursively.
func fetchPatterns(client *gitea.Client, patternsRepo, patternsFiles string) string {
func fetchPatterns(ctx context.Context, client *gitea.Client, patternsRepo, patternsFiles string) string {
var sb strings.Builder
repos := strings.Split(patternsRepo, ",")
@@ -212,7 +218,7 @@ func fetchPatterns(client *gitea.Client, patternsRepo, patternsFiles string) str
continue
}
files, err := client.GetAllFilesInPath(owner, repo, path)
files, err := client.GetAllFilesInPath(ctx, owner, repo, path)
if err != nil {
log.Printf("Warning: could not fetch %s from %s: %v", path, repoRef, err)
continue