137 lines
4.2 KiB
Go
137 lines
4.2 KiB
Go
package main
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"log"
|
|
"os"
|
|
"path/filepath"
|
|
|
|
"bitbucket.bit.admin.ch/scm/~u80859501/pierre-bot/internal/chatter"
|
|
"bitbucket.bit.admin.ch/scm/~u80859501/pierre-bot/internal/gitadapters"
|
|
"bitbucket.bit.admin.ch/scm/~u80859501/pierre-bot/internal/gitadapters/gitea"
|
|
"bitbucket.bit.admin.ch/scm/~u80859501/pierre-bot/internal/pierre"
|
|
"github.com/alecthomas/kong"
|
|
kongyaml "github.com/alecthomas/kong-yaml"
|
|
)
|
|
|
|
type BitbucketConfig struct {
|
|
BaseURL string `help:"Bitbucket Base URL (e.g. https://bitbucket.example.com)" env:"BITBUCKET_URL"`
|
|
Token string `help:"Bearer Token" env:"BITBUCKET_TOKEN"`
|
|
}
|
|
|
|
type GiteaConfig struct {
|
|
BaseURL string `help:"Gitea Base URL (e.g. https://gitea.com)" env:"GITEA_URL"`
|
|
Token string `help:"API Token" env:"GITEA_TOKEN"`
|
|
}
|
|
|
|
type RepoArgs struct {
|
|
Owner string `arg:"" help:"Project Key or Owner" env:"PIERRE_OWNER"`
|
|
Repo string `arg:"" help:"Repository Slug" env:"PIERRE_REPO"`
|
|
PRID int `arg:"" help:"Pull Request ID" name:"pr"`
|
|
}
|
|
|
|
type LLMConfig struct {
|
|
Provider string `help:"Provider for llm (ollama or gemini)" required:"" env:"LLM_PROVIDER"`
|
|
Endpoint string `help:"Endpoint for provider (only for ollama)" env:"LLM_ENDPOINT"`
|
|
APIKey string `help:"APIKey for provider" env:"LLM_API_KEY"`
|
|
Model string `help:"Model to use" env:"LLM_MODEL"`
|
|
}
|
|
|
|
type Config struct {
|
|
GitProvider string `help:"Git provider (bitbucket or gitea)" env:"GIT_PROVIDER"`
|
|
Bitbucket BitbucketConfig `embed:"" prefix:"bitbucket-"`
|
|
Gitea GiteaConfig `embed:"" prefix:"gitea-"`
|
|
Repo RepoArgs `embed:""`
|
|
LLM LLMConfig `embed:"" prefix:"llm-"`
|
|
Config kong.ConfigFlag `help:"Path to a YAML config file"`
|
|
}
|
|
|
|
func main() {
|
|
cfg := &Config{}
|
|
home, err := os.UserHomeDir()
|
|
if err != nil {
|
|
log.Fatalf("could not find home directory: %v", err)
|
|
}
|
|
|
|
defaultConfig := filepath.Join(home, ".config", "pierre", "config.yaml")
|
|
|
|
// Parse flags, env vars, and config files
|
|
ctx := kong.Parse(cfg,
|
|
kong.Name("pierre"),
|
|
kong.Description("AI-powered Pull Request reviewer"),
|
|
kong.UsageOnError(),
|
|
kong.Configuration(kongyaml.Loader, "config.yaml", defaultConfig),
|
|
)
|
|
|
|
// Auto-detect provider
|
|
provider := cfg.GitProvider
|
|
if provider == "" {
|
|
if cfg.Bitbucket.BaseURL != "" && cfg.Gitea.BaseURL == "" {
|
|
provider = "bitbucket"
|
|
} else if cfg.Gitea.BaseURL != "" && cfg.Bitbucket.BaseURL == "" {
|
|
provider = "gitea"
|
|
} else if cfg.Bitbucket.BaseURL != "" && cfg.Gitea.BaseURL != "" {
|
|
log.Fatal("Multiple git providers configured. Please specify one using --git-provider.")
|
|
} else {
|
|
log.Fatal("No git provider configured. Please provide Bitbucket or Gitea configuration.")
|
|
}
|
|
}
|
|
|
|
var adapter gitadapters.Adapter
|
|
switch provider {
|
|
case "bitbucket":
|
|
if cfg.Bitbucket.BaseURL == "" {
|
|
log.Fatal("Bitbucket Base URL is required when using bitbucket provider.")
|
|
}
|
|
adapter = gitadapters.NewBitbucket(cfg.Bitbucket.BaseURL, cfg.Bitbucket.Token)
|
|
case "gitea":
|
|
if cfg.Gitea.BaseURL == "" {
|
|
log.Fatal("Gitea Base URL is required when using gitea provider.")
|
|
}
|
|
adapter, err = gitea.New(cfg.Gitea.BaseURL, cfg.Gitea.Token)
|
|
if err != nil {
|
|
log.Fatalf("Error initializing Gitea adapter: %v", err)
|
|
}
|
|
default:
|
|
log.Fatalf("Unknown git provider: %s", provider)
|
|
}
|
|
|
|
// Fetch Diff using positional args from shared RepoArgs
|
|
diff, err := adapter.GetDiff(cfg.Repo.Owner, cfg.Repo.Repo, cfg.Repo.PRID)
|
|
if err != nil {
|
|
log.Fatalf("Error fetching diff: %v", err)
|
|
}
|
|
|
|
// Initialize AI Adapter
|
|
var ai chatter.ChatAdapter
|
|
|
|
switch cfg.LLM.Provider {
|
|
case "gemini":
|
|
ai, err = chatter.NewGeminiAdapter(context.Background(), cfg.LLM.APIKey, cfg.LLM.Model)
|
|
case "ollama":
|
|
ai, err = chatter.NewOllamaAdapter(cfg.LLM.Endpoint, cfg.LLM.Model)
|
|
default:
|
|
log.Fatalf("%s is not a valid llm provider", cfg.LLM.Provider)
|
|
}
|
|
|
|
if err != nil {
|
|
log.Fatalf("Error initializing AI: %v", err)
|
|
}
|
|
|
|
// Run Logic
|
|
comments, err := pierre.JudgePR(context.Background(), ai, diff)
|
|
if err != nil {
|
|
log.Fatalf("Error judging PR: %v", err)
|
|
}
|
|
|
|
fmt.Printf("Analysis complete. Found %d issues.\n---\n", len(comments))
|
|
|
|
for _, c := range comments {
|
|
fmt.Printf("File: %s\nLine: %d\nMessage: %s\n%s\n",
|
|
c.File, c.Line, c.Message, "---")
|
|
}
|
|
|
|
_ = ctx
|
|
}
|