Files
nate.lubitz 532b912ffb
Build and Deploy / build-and-deploy (push) Failing after 20s
add tool to gitea
2026-06-05 02:34:00 +10:00

171 lines
4.4 KiB
Go

package cmd
import (
"fmt"
"os"
"kforge/internal/config"
dnsProvider "kforge/internal/dns"
"kforge/internal/generator"
"github.com/spf13/cobra"
)
// ------------------------------------------------------------
// kforge dns ensure
// ------------------------------------------------------------
var dnsCmd = &cobra.Command{
Use: "dns",
Short: "Manage DNS records for kforge environments",
}
var dnsEnsureEnvs []string
var dnsEnsureCmd = &cobra.Command{
Use: "ensure",
Short: "Create or update DNS A records for ingress hosts",
Long: `For each ingress host with dns_record: true, creates or updates
an A record pointing to KFORGE_NODE_IP.
Idempotent — safe to run on every deploy. Skips hosts where the
record already points to the correct IP.
Examples:
kforge dns ensure --env staging
kforge dns ensure --env staging --env production`,
RunE: runDNSEnsure,
}
func init() {
dnsEnsureCmd.Flags().StringArrayVarP(&dnsEnsureEnvs, "env", "e", nil,
"Environment(s) to ensure DNS records for (default: all)")
dnsCmd.AddCommand(dnsEnsureCmd)
rootCmd.AddCommand(dnsCmd)
}
func runDNSEnsure(cmd *cobra.Command, args []string) error {
cfg, err := loadConfig()
if err != nil {
return err
}
if cfg.DNS.SkipDNS {
fmt.Println("dns.skip_dns is true — skipping DNS management")
return nil
}
nodeIP := cfg.DNS.NodeIP
if nodeIP == "" {
nodeIP = os.Getenv("KFORGE_NODE_IP")
}
if nodeIP == "" {
return fmt.Errorf("node IP not set: add dns.node_ip to kforge.yml or set KFORGE_NODE_IP")
}
provider, err := dnsProvider.NewProvider(cfg.DNS)
if err != nil {
return fmt.Errorf("initialising DNS provider: %w", err)
}
envKeys := dnsEnsureEnvs
if len(envKeys) == 0 {
envKeys = config.EnvironmentKeys(cfg)
}
for _, envKey := range envKeys {
fmt.Printf("\nEnsuring DNS records for: %s\n", envKey)
env, err := config.ResolveEnvironment(cfg, envKey)
if err != nil {
return err
}
if err := dnsProvider.EnsureRecordsForEnvironment(provider, &env, nodeIP); err != nil {
return fmt.Errorf("env %q: %w", envKey, err)
}
}
return nil
}
// ------------------------------------------------------------
// kforge gitea-actions
// ------------------------------------------------------------
var (
giteaActionsOutput string
giteaActionsBranch string
giteaActionsEnvs []string
)
var giteaActionsCmd = &cobra.Command{
Use: "gitea-actions",
Short: "Generate a Gitea Actions workflow for this app",
Long: `Generates a complete .gitea/workflows/deploy.yml that:
- Builds and pushes the Docker image on every push to main
- Runs kforge validate
- Applies cluster secrets (idempotent)
- Ensures DNS records
- Generates manifests and applies them with kubectl
- Rolls out the deployment
The generated workflow replaces your hand-written deploy.yml.
Re-run whenever you add environments or change deploy options.
Examples:
kforge gitea-actions
kforge gitea-actions --output .gitea/workflows/deploy.yml
kforge gitea-actions --env staging --env production`,
RunE: runGiteaActions,
}
func init() {
giteaActionsCmd.Flags().StringVarP(&giteaActionsOutput, "output", "o",
".gitea/workflows/deploy.yml",
"Output path for the generated workflow file")
giteaActionsCmd.Flags().StringVar(&giteaActionsBranch, "branch", "main",
"Branch that triggers the workflow")
giteaActionsCmd.Flags().StringArrayVarP(&giteaActionsEnvs, "env", "e", nil,
"Environments to deploy (default: all, staging before production)")
rootCmd.AddCommand(giteaActionsCmd)
}
func runGiteaActions(cmd *cobra.Command, args []string) error {
cfg, err := loadConfig()
if err != nil {
return err
}
workflow, err := generator.GenerateGiteaActions(cfg, generator.GiteaActionsOptions{
Branch: giteaActionsBranch,
Environments: giteaActionsEnvs,
})
if err != nil {
return fmt.Errorf("generating workflow: %w", err)
}
if giteaActionsOutput == "-" {
fmt.Print(workflow)
return nil
}
// Ensure parent directory exists.
dir := giteaActionsOutput
for i := len(dir) - 1; i >= 0; i-- {
if dir[i] == '/' {
dir = dir[:i]
break
}
}
if dir != giteaActionsOutput {
if err := os.MkdirAll(dir, 0o755); err != nil {
return fmt.Errorf("creating output directory: %w", err)
}
}
if err := os.WriteFile(giteaActionsOutput, []byte(workflow), 0o644); err != nil {
return fmt.Errorf("writing workflow: %w", err)
}
fmt.Printf("✓ Gitea Actions workflow written to %s\n", giteaActionsOutput)
return nil
}