add tool to gitea
Build and Deploy / build-and-deploy (push) Failing after 20s

This commit is contained in:
2026-06-05 02:34:00 +10:00
commit 532b912ffb
25 changed files with 4981 additions and 0 deletions
+107
View File
@@ -0,0 +1,107 @@
package config
import (
"fmt"
"os"
"gopkg.in/yaml.v3"
)
// Load reads a kforge.yml file from disk, applies all defaults,
// and returns the parsed config ready for environment resolution.
func Load(path string) (*KforgeConfig, error) {
data, err := os.ReadFile(path)
if err != nil {
return nil, fmt.Errorf("reading %s: %w", path, err)
}
return LoadBytes(data)
}
// LoadBytes parses kforge.yml from a byte slice. Useful in tests.
func LoadBytes(data []byte) (*KforgeConfig, error) {
cfg := &KforgeConfig{}
if err := yaml.Unmarshal(data, cfg); err != nil {
return nil, fmt.Errorf("parsing kforge.yml: %w", err)
}
if err := validate(cfg); err != nil {
return nil, err
}
ApplyDefaults(cfg)
return cfg, nil
}
// validate performs structural validation before defaults are
// applied. Returns the first error found.
func validate(cfg *KforgeConfig) error {
if cfg.Meta.Name == "" {
return fmt.Errorf("meta.name is required")
}
if cfg.Meta.Tenant == "" {
return fmt.Errorf("meta.tenant is required")
}
if len(cfg.Environments) == 0 {
return fmt.Errorf("at least one environment must be defined")
}
for envKey, env := range cfg.Environments {
if len(env.Ingress.Hosts) == 0 {
return fmt.Errorf("environments.%s: at least one ingress host is required", envKey)
}
for _, host := range env.Ingress.Hosts {
if host.Hostname == "" {
return fmt.Errorf("environments.%s: ingress host hostname cannot be empty", envKey)
}
}
for _, job := range env.CronJobs {
if job.Name == "" {
return fmt.Errorf("environments.%s: cron job is missing a name", envKey)
}
if job.Schedule == "" {
return fmt.Errorf("environments.%s.cron_jobs.%s: schedule is required", envKey, job.Name)
}
if len(job.Command) == 0 {
return fmt.Errorf("environments.%s.cron_jobs.%s: command is required", envKey, job.Name)
}
}
for _, v := range env.EnvVars {
if err := validateEnvVar(envKey, v); err != nil {
return err
}
}
}
for _, v := range cfg.Defaults.EnvVars {
if err := validateEnvVar("defaults", v); err != nil {
return err
}
}
return nil
}
func validateEnvVar(context string, v EnvVarConfig) error {
if v.Name == "" {
return fmt.Errorf("%s: env var is missing a name", context)
}
switch v.Type {
case EnvVarTypePlain, "":
// value can technically be empty (empty string env var is valid)
case EnvVarTypeSecretRef:
if v.SecretName == "" || v.SecretKey == "" {
return fmt.Errorf("%s: env var %q (secret_ref) requires secret_name and secret_key", context, v.Name)
}
case EnvVarTypeConfigMapRef:
if v.ConfigMapName == "" || v.ConfigMapKey == "" {
return fmt.Errorf("%s: env var %q (configmap_ref) requires configmap_name and configmap_key", context, v.Name)
}
default:
return fmt.Errorf("%s: env var %q has unknown type %q (valid: plain, secret_ref, configmap_ref)", context, v.Name, v.Type)
}
return nil
}
// EnvironmentKeys returns the sorted list of environment names.
func EnvironmentKeys(cfg *KforgeConfig) []string {
keys := make([]string, 0, len(cfg.Environments))
for k := range cfg.Environments {
keys = append(keys, k)
}
return keys
}