// Package config loads and validates the server configuration from the // environment. All settings are required and validated at startup so the // process fails fast with a clear message instead of at first request. package config import ( "errors" "fmt" "net/url" "os" "strings" ) // Config holds the validated runtime configuration. type Config struct { // WoodpeckerURL is the base URL of the Woodpecker CI server // (e.g. "https://woodpecker.example.com"). WoodpeckerURL string // WoodpeckerToken is the personal access token used for API authentication. WoodpeckerToken string } // Load reads configuration from the environment and validates it. func Load() (*Config, error) { cfg := &Config{ WoodpeckerURL: os.Getenv("WOODPECKER_URL"), WoodpeckerToken: os.Getenv("WOODPECKER_TOKEN"), } if cfg.WoodpeckerURL == "" { return nil, errors.New("WOODPECKER_URL is required (e.g. https://woodpecker.example.com)") } u, err := url.Parse(cfg.WoodpeckerURL) if err != nil { return nil, fmt.Errorf("WOODPECKER_URL is not a valid URL: %w", err) } if u.Scheme != "http" && u.Scheme != "https" { return nil, fmt.Errorf("WOODPECKER_URL must use http or https scheme, got %q", u.Scheme) } if u.Host == "" { return nil, errors.New("WOODPECKER_URL must include a host (e.g. https://woodpecker.example.com)") } if cfg.WoodpeckerToken == "" { return nil, errors.New("WOODPECKER_TOKEN is required") } return cfg, nil } // APIBaseURL returns the Woodpecker REST API base URL: the server URL with a // single trailing slash stripped and "/api" appended. func (c *Config) APIBaseURL() string { return strings.TrimSuffix(c.WoodpeckerURL, "/") + "/api" }