yaju-is-always-watching-you/internal/config/config.go
awayatan f411886d88
Some checks are pending
CI / test (push) Waiting to run
Split phrase list out into community-editable phrases.yaml
config.yaml previously mixed secrets with the phrase list, forcing
private-only edits. Now config supports phrases_file, which is loaded and
merged with any private phrases: entries, so the repo-tracked phrases.yaml
can be extended via PR while per-deployment additions stay private.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-26 23:27:27 +09:00

90 lines
2.4 KiB
Go

// 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
}