// Package config loads yaju-keisatsu's YAML configuration file. package config import ( "fmt" "os" "path/filepath" "gopkg.in/yaml.v3" ) type Config struct { ListenAddr string `yaml:"listen_addr"` WebhookSecret string `yaml:"webhook_secret"` Forgejo Forgejo `yaml:"forgejo"` Bot Bot `yaml:"bot"` // PhrasesFile, if set, is loaded and merged with Phrases. It lets a // deployment point at the repo's community-maintained phrases.yaml while // still keeping any private additions inline below. PhrasesFile string `yaml:"phrases_file"` Phrases []string `yaml:"phrases"` } type phrasesFile struct { Phrases []string `yaml:"phrases"` } type Forgejo struct { BaseURL string `yaml:"base_url"` Token string `yaml:"token"` } type Bot struct { // Username is the Forgejo account the API token belongs to. Comments // authored by this account are ignored so the bot never replies to itself. Username string `yaml:"username"` // BranchPrefix is prepended to the auto-generated correction branch name. BranchPrefix string `yaml:"branch_prefix"` // TargetExtensions limits which pushed files are scanned for corrections. // An empty list scans every file. TargetExtensions []string `yaml:"target_extensions"` } func Load(path string) (*Config, error) { data, err := os.ReadFile(path) if err != nil { return nil, fmt.Errorf("read config: %w", err) } cfg := &Config{ ListenAddr: ":8080", Bot: Bot{ BranchPrefix: "bot/goroku-fix/", }, } if err := yaml.Unmarshal(data, cfg); err != nil { return nil, fmt.Errorf("parse config: %w", err) } if cfg.PhrasesFile != "" { fp := cfg.PhrasesFile if !filepath.IsAbs(fp) { fp = filepath.Join(filepath.Dir(path), fp) } data, err := os.ReadFile(fp) if err != nil { return nil, fmt.Errorf("read phrases_file: %w", err) } var pf phrasesFile if err := yaml.Unmarshal(data, &pf); err != nil { return nil, fmt.Errorf("parse phrases_file: %w", err) } cfg.Phrases = append(pf.Phrases, cfg.Phrases...) } if cfg.Forgejo.BaseURL == "" { return nil, fmt.Errorf("forgejo.base_url is required") } if cfg.Forgejo.Token == "" { return nil, fmt.Errorf("forgejo.token is required") } if cfg.WebhookSecret == "" { return nil, fmt.Errorf("webhook_secret is required") } if len(cfg.Phrases) == 0 { return nil, fmt.Errorf("phrases list is empty (set phrases and/or phrases_file)") } return cfg, nil }