First commit of golang CLI.
This commit is contained in:
138
wild-cli/cmd/wild/app/delete.go
Normal file
138
wild-cli/cmd/wild/app/delete.go
Normal file
@@ -0,0 +1,138 @@
|
||||
package app
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
"github.com/wild-cloud/wild-cli/internal/environment"
|
||||
"github.com/wild-cloud/wild-cli/internal/external"
|
||||
"github.com/wild-cloud/wild-cli/internal/output"
|
||||
)
|
||||
|
||||
var (
|
||||
deleteForce bool
|
||||
deleteDryRun bool
|
||||
)
|
||||
|
||||
func newDeleteCommand() *cobra.Command {
|
||||
cmd := &cobra.Command{
|
||||
Use: "delete <name>",
|
||||
Short: "Delete an application from the cluster",
|
||||
Long: `Delete a Wild Cloud app and all its resources.
|
||||
|
||||
This will delete:
|
||||
- App deployment, services, and other Kubernetes resources
|
||||
- App secrets from the app's namespace
|
||||
- App namespace (if empty after resource deletion)
|
||||
- Local app configuration files from apps/<app_name>
|
||||
|
||||
Examples:
|
||||
wild app delete nextcloud
|
||||
wild app delete nextcloud --force
|
||||
wild app delete nextcloud --dry-run`,
|
||||
Args: cobra.ExactArgs(1),
|
||||
RunE: runAppDelete,
|
||||
}
|
||||
|
||||
cmd.Flags().BoolVar(&deleteForce, "force", false, "skip confirmation prompts")
|
||||
cmd.Flags().BoolVar(&deleteDryRun, "dry-run", false, "show what would be deleted without actually deleting")
|
||||
|
||||
return cmd
|
||||
}
|
||||
|
||||
func runAppDelete(cmd *cobra.Command, args []string) error {
|
||||
appName := args[0]
|
||||
|
||||
// Initialize environment
|
||||
env := environment.New()
|
||||
if err := env.RequiresProject(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Check if app exists
|
||||
appDir := filepath.Join(env.AppsDir(), appName)
|
||||
if _, err := os.Stat(appDir); os.IsNotExist(err) {
|
||||
return fmt.Errorf("app directory 'apps/%s' not found", appName)
|
||||
}
|
||||
|
||||
// Initialize external tools
|
||||
toolManager := external.NewManager()
|
||||
if err := toolManager.CheckTools(cmd.Context(), []string{"kubectl"}); err != nil {
|
||||
return fmt.Errorf("required tools not available: %w", err)
|
||||
}
|
||||
|
||||
kubectl := toolManager.Kubectl()
|
||||
|
||||
// Confirmation prompt (unless --force or --dry-run)
|
||||
if !deleteForce && !deleteDryRun {
|
||||
output.Warning(fmt.Sprintf("This will delete all resources for app '%s'", appName))
|
||||
output.Info("This includes:")
|
||||
output.Info(" - Kubernetes deployments, services, secrets, and other resources")
|
||||
output.Info(" - App namespace (if empty after deletion)")
|
||||
output.Info(" - Local configuration files in apps/" + appName + "/")
|
||||
output.Info("")
|
||||
|
||||
reader := bufio.NewReader(os.Stdin)
|
||||
output.Printf("Are you sure you want to delete app '%s'? (y/N): ", appName)
|
||||
response, err := reader.ReadString('\n')
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to read confirmation: %w", err)
|
||||
}
|
||||
response = strings.TrimSpace(strings.ToLower(response))
|
||||
if response != "y" && response != "yes" {
|
||||
output.Info("Deletion cancelled")
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
if deleteDryRun {
|
||||
output.Header("DRY RUN: Deleting app '" + appName + "'")
|
||||
} else {
|
||||
output.Header("Deleting app '" + appName + "'")
|
||||
}
|
||||
|
||||
// Step 1: Delete namespace (this will delete ALL resources)
|
||||
output.Info("Deleting namespace and all remaining resources...")
|
||||
|
||||
var kubectlArgs []string
|
||||
if deleteDryRun {
|
||||
kubectlArgs = []string{"delete", "namespace", appName, "--dry-run=client", "--ignore-not-found=true"}
|
||||
} else {
|
||||
kubectlArgs = []string{"delete", "namespace", appName, "--ignore-not-found=true"}
|
||||
}
|
||||
|
||||
if _, err := kubectl.Execute(cmd.Context(), kubectlArgs...); err != nil {
|
||||
return fmt.Errorf("failed to delete namespace: %w", err)
|
||||
}
|
||||
|
||||
// Wait for namespace deletion to complete (only if not dry-run)
|
||||
if !deleteDryRun {
|
||||
output.Info("Waiting for namespace deletion to complete...")
|
||||
waitArgs := []string{"wait", "--for=delete", "namespace", appName, "--timeout=60s"}
|
||||
// Ignore error as namespace might already be deleted
|
||||
_, _ = kubectl.Execute(cmd.Context(), waitArgs...)
|
||||
}
|
||||
|
||||
// Step 2: Delete local app configuration files
|
||||
output.Info("Deleting local app configuration...")
|
||||
if deleteDryRun {
|
||||
output.Info(fmt.Sprintf("DRY RUN: Would delete directory 'apps/%s/'", appName))
|
||||
} else {
|
||||
if err := os.RemoveAll(appDir); err != nil {
|
||||
return fmt.Errorf("failed to delete local configuration directory: %w", err)
|
||||
}
|
||||
output.Info(fmt.Sprintf("Deleted local configuration directory: apps/%s/", appName))
|
||||
}
|
||||
|
||||
output.Success(fmt.Sprintf("App '%s' deletion complete!", appName))
|
||||
output.Info("")
|
||||
output.Info("Note: Dependency apps (if any) were not deleted.")
|
||||
output.Info("If you want to delete dependencies, run wild app delete for each dependency separately.")
|
||||
|
||||
return nil
|
||||
}
|
Reference in New Issue
Block a user