Files
pierre-bot/cmd/pierre/main.go

132 lines
4.3 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
package main
import (
"context"
"log"
"os"
"path/filepath"
"git.schreifuchs.ch/schreifuchs/pierre-bot/internal/chatter"
"git.schreifuchs.ch/schreifuchs/pierre-bot/internal/gitadapters/bitbucket"
"git.schreifuchs.ch/schreifuchs/pierre-bot/internal/gitadapters/gitea"
"git.schreifuchs.ch/schreifuchs/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"`
BaseURL string `help:"Endpoint for provider (only for ollama)" env:"LLM_BASE_URL"`
APIKey string `help:"APIKey for provider" env:"LLM_API_KEY"`
Model string `help:"Model to use" env:"LLM_MODEL"`
}
type ReviewConfig struct {
MaxChunkChars int `help:"Maximum diff chunk size in characters (default 60000)" default:"60000"`
Guidelines []string `help:"Project-specific review guidelines"`
DisableComments bool `help:"Do not post comments to the Git provider (dryrun mode)"`
}
type Config struct {
Review ReviewConfig `embed:"" prefix:"review-"`
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
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 git pierre.GitAdapter
switch provider {
case "bitbucket":
if cfg.Bitbucket.BaseURL == "" {
log.Fatal("Bitbucket Base URL is required when using bitbucket provider.")
}
git = bitbucket.NewBitbucket(cfg.Bitbucket.BaseURL, cfg.Bitbucket.Token)
case "gitea":
if cfg.Gitea.BaseURL == "" {
log.Fatal("Gitea Base URL is required when using gitea provider.")
}
var err error
git, 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)
}
// Initialize AI Adapter
var ai pierre.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.BaseURL, cfg.LLM.Model)
case "openai":
ai = chatter.NewOpenAIAdapter(cfg.LLM.APIKey, cfg.LLM.Model, cfg.LLM.BaseURL)
default:
log.Fatalf("%s is not a valid llm provider", cfg.LLM.Provider)
}
if err != nil {
log.Fatalf("Error initializing AI: %v", err)
}
pierreService := pierre.New(ai, git, cfg.Review.MaxChunkChars, cfg.Review.Guidelines, cfg.Review.DisableComments)
if err := pierreService.MakeReview(context.Background(), cfg.Repo.Owner, cfg.Repo.Repo, cfg.Repo.PRID); err != nil {
log.Fatalf("Error during review: %v", err)
}
}