Files
review-bot/integration_test.go
T
Rodin 5f7ffab487 feat(#125): rename GITEA_URL to VCS_URL with deprecated fallback
- Add --vcs-url flag as primary (reads VCS_URL env var)
- Keep --gitea-url and GITEA_URL as deprecated fallbacks with warnings
- Update action.yml: rename gitea-url input to vcs-url, pass VCS_URL to binary
- Update ci.yml: use VCS_URL env var in Run review step
- Update integration tests: INTEGRATION_GITEA_URL -> INTEGRATION_VCS_URL
- Update README: --vcs-url / VCS_URL with fallback note in env var table

Backward compat: existing GITEA_URL users get a deprecation warning and
continue to work unchanged until they migrate to VCS_URL.
2026-05-13 23:00:35 -07:00

106 lines
3.0 KiB
Go

//go:build integration
package main
import (
"context"
"os"
"strconv"
"strings"
"testing"
"gitea.weiker.me/rodin/review-bot/gitea"
"gitea.weiker.me/rodin/review-bot/llm"
"gitea.weiker.me/rodin/review-bot/review"
)
// Integration test requires a running Gitea instance and LLM endpoint.
// Set environment variables:
//
// INTEGRATION_VCS_URL - VCS base URL
// INTEGRATION_GITEA_TOKEN - Gitea API token with repo access
// INTEGRATION_GITEA_REPO - owner/repo with an open PR
// INTEGRATION_PR_NUMBER - PR number to test against
// INTEGRATION_LLM_BASE_URL - LLM API base URL
// INTEGRATION_LLM_API_KEY - LLM API key
// INTEGRATION_LLM_MODEL - Model name
func TestIntegration_FullReviewFlow(t *testing.T) {
giteaURL := os.Getenv("INTEGRATION_VCS_URL")
giteaToken := os.Getenv("INTEGRATION_GITEA_TOKEN")
giteaRepo := os.Getenv("INTEGRATION_GITEA_REPO")
prNumStr := os.Getenv("INTEGRATION_PR_NUMBER")
llmBaseURL := os.Getenv("INTEGRATION_LLM_BASE_URL")
llmAPIKey := os.Getenv("INTEGRATION_LLM_API_KEY")
llmModel := os.Getenv("INTEGRATION_LLM_MODEL")
if giteaURL == "" || giteaToken == "" || giteaRepo == "" || prNumStr == "" ||
llmBaseURL == "" || llmAPIKey == "" || llmModel == "" {
t.Skip("Integration test env vars not set, skipping")
}
prNumber, err := strconv.Atoi(prNumStr)
if err != nil {
t.Fatalf("Invalid PR number %q: %v", prNumStr, err)
}
// Parse owner/repo
parts := strings.SplitN(giteaRepo, "/", 2)
if len(parts) != 2 {
t.Fatalf("Invalid repo format %q", giteaRepo)
}
owner, repoName := parts[0], parts[1]
if owner == "" || repoName == "" {
t.Fatalf("Invalid repo format %q", giteaRepo)
}
ctx := context.Background()
// Step 1: Fetch PR
giteaClient := gitea.NewClient(giteaURL, giteaToken)
pr, err := giteaClient.GetPullRequest(ctx, owner, repoName, prNumber)
if err != nil {
t.Fatalf("GetPullRequest: %v", err)
}
t.Logf("PR: %s (sha: %s)", pr.Title, pr.Head.Sha)
// Step 2: Fetch diff
diff, err := giteaClient.GetPullRequestDiff(ctx, owner, repoName, prNumber)
if err != nil {
t.Fatalf("GetPullRequestDiff: %v", err)
}
if diff == "" {
t.Fatal("diff is empty")
}
t.Logf("Diff size: %d bytes", len(diff))
// Step 3: Build prompts
systemPrompt := review.BuildSystemPrompt("", "")
userPrompt := review.BuildUserPrompt(pr.Title, pr.Body, diff, "", true, "")
// Step 4: Call LLM
llmClient := llm.NewClient(llmBaseURL, llmAPIKey, llmModel)
response, err := llmClient.Complete(ctx, []llm.Message{
{Role: "system", Content: systemPrompt},
{Role: "user", Content: userPrompt},
})
if err != nil {
t.Fatalf("LLM Complete: %v", err)
}
t.Logf("LLM response: %d bytes", len(response))
// Step 5: Parse response
result, err := review.ParseResponse(response)
if err != nil {
t.Fatalf("ParseResponse: %v", err)
}
t.Logf("Verdict: %s, Findings: %d", result.Verdict, len(result.Findings))
// Step 6: Format (dry-run validation)
body := review.FormatMarkdown(result, "integration-test")
if body == "" {
t.Fatal("formatted review body is empty")
}
t.Logf("Review body:\n%s", body)
}