Files
wild-cloud/wild-cli/cmd/wild/app/delete.go

139 lines
4.2 KiB
Go

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
}