fix: cleaned up and mended logic

This commit is contained in:
eding 2025-08-21 23:45:20 +02:00
parent 47d3c6df2e
commit 145c81b05b

121
main.go
View file

@ -9,7 +9,6 @@ import (
"github.com/spf13/cobra" "github.com/spf13/cobra"
) )
// Global variables for flags
var orgName, manifestsRepoName string var orgName, manifestsRepoName string
func main() { func main() {
@ -33,7 +32,6 @@ func main() {
initCmd.Flags().StringVar(&orgName, "org", "", "The GitHub organization (e.g., Pingu-Studio)") initCmd.Flags().StringVar(&orgName, "org", "", "The GitHub organization (e.g., Pingu-Studio)")
initCmd.Flags().StringVar(&manifestsRepoName, "manifests-repo", "cicd-deployment-manifests", "The name of the manifests repository") initCmd.Flags().StringVar(&manifestsRepoName, "manifests-repo", "cicd-deployment-manifests", "The name of the manifests repository")
initCmd.MarkFlagRequired("org") initCmd.MarkFlagRequired("org")
initCmd.MarkFlagRequired("manifests-repo")
repoCmd.AddCommand(initCmd) repoCmd.AddCommand(initCmd)
rootCmd.AddCommand(repoCmd) rootCmd.AddCommand(repoCmd)
@ -43,7 +41,7 @@ func main() {
} }
} }
func runInit(cmd *cobra.Command, args []string) { func runInitRepo(cmd *cobra.Command, args []string) {
fmt.Println("[INFO] Checking dependencies (git and gh)...") fmt.Println("[INFO] Checking dependencies (git and gh)...")
if !commandExists("git") || !commandExists("gh") { if !commandExists("git") || !commandExists("gh") {
fmt.Println("[ERROR] 'git' and 'gh' must be installed and in your PATH.") fmt.Println("[ERROR] 'git' and 'gh' must be installed and in your PATH.")
@ -51,7 +49,7 @@ func runInit(cmd *cobra.Command, args []string) {
} }
fmt.Println("[INFO] Checking GitHub authentication...") fmt.Println("[INFO] Checking GitHub authentication...")
if err := runCommand("gh", "auth", "status"); err != nil { if err := runCommandQuiet("gh", "auth", "status"); err != nil {
fmt.Println("[ERROR] You are not logged into the GitHub CLI. Please run 'gh auth login'.") fmt.Println("[ERROR] You are not logged into the GitHub CLI. Please run 'gh auth login'.")
os.Exit(1) os.Exit(1)
} }
@ -60,7 +58,7 @@ func runInit(cmd *cobra.Command, args []string) {
fullRepoName := fmt.Sprintf("%s/%s", orgName, manifestsRepoName) fullRepoName := fmt.Sprintf("%s/%s", orgName, manifestsRepoName)
fmt.Printf("[INFO] Checking for repository '%s'...\n", fullRepoName) fmt.Printf("[INFO] Checking for repository '%s'...\n", fullRepoName)
if err := runCommand("gh", "repo", "view", fullRepoName); err != nil { if err := runCommandQuiet("gh", "repo", "view", fullRepoName); err != nil {
fmt.Printf("[WARNING] Repository '%s' not found. Creating it now...\n", fullRepoName) fmt.Printf("[WARNING] Repository '%s' not found. Creating it now...\n", fullRepoName)
if err := runCommand("gh", "repo", "create", fullRepoName, "--private", "--description", "Centralized deployment manifests for Flux CD"); err != nil { if err := runCommand("gh", "repo", "create", fullRepoName, "--private", "--description", "Centralized deployment manifests for Flux CD"); err != nil {
fmt.Printf("[ERROR] Failed to create repository: %v\n", err) fmt.Printf("[ERROR] Failed to create repository: %v\n", err)
@ -85,44 +83,8 @@ func runInit(cmd *cobra.Command, args []string) {
os.Exit(1) os.Exit(1)
} }
fmt.Println("[INFO] Ensuring standard directory structure (apps/previews, etc.) exists...") fmt.Println("[INFO] Ensuring standard directory structure and manifests exist...")
for _, env := range []string{"previews", "staging", "production"} { createStructureAndManifests(tempDir)
dirPath := filepath.Join(tempDir, "apps", env)
if err := os.MkdirAll(dirPath, 0755); err != nil {
fmt.Printf("[ERROR] Failed to create directory %s: %v\n", dirPath, err)
os.Exit(1)
}
gitkeepPath := filepath.Join(dirPath, ".gitkeep")
if _, err := os.Stat(gitkeepPath); os.IsNotExist(err) {
f, err := os.Create(gitkeepPath)
if err != nil {
fmt.Printf("[ERROR] Failed to create .gitkeep file: %v\n", err)
os.Exit(1)
}
f.Close()
}
}
fmt.Println("[INFO] Ensuring apps/kustomization.yaml exists...")
kustomizationContent :=
`apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- previews/*.yaml
- staging/*.yaml
- production/*.yaml
`
kustomizationPath := filepath.Join(tempDir, "apps", "kustomization.yaml")
if _, err := os.Stat(kustomizationPath); os.IsNotExist(err) {
if err := os.WriteFile(kustomizationPath, []byte(kustomizationContent), 0644); err != nil {
fmt.Printf("[ERROR] Failed to write kustomization.yaml: %v\n", err)
os.Exit(1)
}
fmt.Println("[SUCCESS] kustomization.yaml created.")
} else {
fmt.Println("[INFO] kustomization.yaml already exists.")
}
fmt.Println("[INFO] Committing and pushing changes if any...") fmt.Println("[INFO] Committing and pushing changes if any...")
runCommandInDir(tempDir, "git", "config", "user.name", "CICD Tool Initializer") runCommandInDir(tempDir, "git", "config", "user.name", "CICD Tool Initializer")
@ -135,7 +97,7 @@ resources:
if len(output) == 0 { if len(output) == 0 {
fmt.Println("[INFO] No changes to commit. Repository is already initialized correctly.") fmt.Println("[INFO] No changes to commit. Repository is already initialized correctly.")
} else { } else {
commitMsg := fmt.Sprintf("feat: Initialize app structure and kustomization") commitMsg := "feat: Initialize repository structure with namespaces and apps"
if err := runCommandInDir(tempDir, "git", "commit", "-m", commitMsg); err != nil { if err := runCommandInDir(tempDir, "git", "commit", "-m", commitMsg); err != nil {
fmt.Printf("[ERROR] Failed to commit changes: %v\n", err) fmt.Printf("[ERROR] Failed to commit changes: %v\n", err)
os.Exit(1) os.Exit(1)
@ -150,43 +112,47 @@ resources:
fmt.Println("\n🎉 Onboarding complete! 🎉") fmt.Println("\n🎉 Onboarding complete! 🎉")
fmt.Println("\n[ACTION REQUIRED] Please update your Flux Kustomization resource in your cluster:") fmt.Println("\n[ACTION REQUIRED] Please update your Flux Kustomization resource in your cluster:")
fmt.Println(" - Find the Kustomization that points to this repository.") fmt.Println(" - Find the Kustomization that points to this repository.")
fmt.Println(" - Change `spec.path` from `./apps` to `./`.") fmt.Println(" - Ensure `spec.path` is set to `./` to process the entire repository.")
fmt.Println(" - This allows Flux to see the new `namespaces` directory.")
fmt.Println("\nExample:") fmt.Println("\nExample:")
fmt.Println(" kubectl edit kustomization all-apps -n flux-system") fmt.Println(" kubectl edit kustomization all-apps -n flux-system")
} }
func createStructureAndManifests(baseDir string) { func createStructureAndManifests(baseDir string) {
// Directories to create environments := []string{"previews", "staging", "production"}
dirs := []string{
filepath.Join(baseDir, "apps", "previews"),
filepath.Join(baseDir, "apps", "staging"),
filepath.Join(baseDir, "apps", "production"),
filepath.Join(baseDir, "namespaces"),
}
for _, dir := range dirs { for _, env := range environments {
if err := os.MkdirAll(dir, 0755); err != nil { dirPath := filepath.Join(baseDir, "apps", env)
fmt.Printf("[ERROR] Failed to create directory %s: %v\n", dir, err) if err := os.MkdirAll(dirPath, 0755); err != nil {
fmt.Printf("[ERROR] Failed to create directory %s: %v\n", dirPath, err)
os.Exit(1) os.Exit(1)
} }
// Create a .gitkeep file in the leaf directories under 'apps' writeFile(filepath.Join(dirPath, ".gitkeep"), "")
if strings.HasPrefix(filepath.Base(dir), "preview") || strings.HasPrefix(filepath.Base(dir), "staging") || strings.HasPrefix(filepath.Base(dir), "production") {
writeFile(filepath.Join(dir, ".gitkeep"), "")
}
} }
// Create namespace manifests appsKustomizationContent := `apiVersion: kustomize.config.k8s.io/v1beta1
for _, ns := range []string{"previews", "staging", "production"} { kind: Kustomization
resources:
- previews/*.yaml
- staging/*.yaml
- production/*.yaml
`
writeFile(filepath.Join(baseDir, "apps", "kustomization.yaml"), appsKustomizationContent)
namespacesDir := filepath.Join(baseDir, "namespaces")
if err := os.MkdirAll(namespacesDir, 0755); err != nil {
fmt.Printf("[ERROR] Failed to create directory %s: %v\n", namespacesDir, err)
os.Exit(1)
}
for _, ns := range environments {
namespaceContent := fmt.Sprintf(`apiVersion: v1 namespaceContent := fmt.Sprintf(`apiVersion: v1
kind: Namespace kind: Namespace
metadata: metadata:
name: %s name: %s
`, ns) `, ns)
writeFile(filepath.Join(baseDir, "namespaces", ns+".yaml"), namespaceContent) writeFile(filepath.Join(namespacesDir, ns+".yaml"), namespaceContent)
} }
// Create kustomization for namespaces
kustomizeNamespaces := `apiVersion: kustomize.config.k8s.io/v1beta1 kustomizeNamespaces := `apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization kind: Kustomization
resources: resources:
@ -194,9 +160,8 @@ resources:
- staging.yaml - staging.yaml
- production.yaml - production.yaml
` `
writeFile(filepath.Join(baseDir, "namespaces", "kustomization.yaml"), kustomizeNamespaces) writeFile(filepath.Join(namespacesDir, "kustomization.yaml"), kustomizeNamespaces)
// Create the ROOT kustomization file
kustomizeRoot := `apiVersion: kustomize.config.k8s.io/v1beta1 kustomizeRoot := `apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization kind: Kustomization
resources: resources:
@ -206,8 +171,6 @@ resources:
writeFile(filepath.Join(baseDir, "kustomization.yaml"), kustomizeRoot) writeFile(filepath.Join(baseDir, "kustomization.yaml"), kustomizeRoot)
} }
// --- Helper Functions ---
func writeFile(path, content string) { func writeFile(path, content string) {
if err := os.WriteFile(path, []byte(content), 0644); err != nil { if err := os.WriteFile(path, []byte(content), 0644); err != nil {
fmt.Printf("[ERROR] Failed to write file %s: %v\n", path, err) fmt.Printf("[ERROR] Failed to write file %s: %v\n", path, err)
@ -215,13 +178,6 @@ func writeFile(path, content string) {
} }
} }
func promptForInput(prompt string) string {
reader := bufio.NewReader(os.Stdin)
fmt.Printf("[PROMPT] %s ", prompt)
input, _ := reader.ReadString('\n')
return strings.TrimSpace(input)
}
func commandExists(cmd string) bool { func commandExists(cmd string) bool {
_, err := exec.LookPath(cmd) _, err := exec.LookPath(cmd)
return err == nil return err == nil
@ -229,12 +185,15 @@ func commandExists(cmd string) bool {
func runCommand(name string, args ...string) error { func runCommand(name string, args ...string) error {
cmd := exec.Command(name, args...) cmd := exec.Command(name, args...)
if name == "gh" && args[0] == "repo" && args[1] == "view" { cmd.Stdout = os.Stdout
// Suppress output for checks cmd.Stderr = os.Stderr
} else { return cmd.Run()
cmd.Stdout = os.Stdout }
cmd.Stderr = os.Stderr
} func runCommandQuiet(name string, args ...string) error {
cmd := exec.Command(name, args...)
cmd.Stdout = nil
cmd.Stderr = os.Stderr
return cmd.Run() return cmd.Run()
} }