From d295b59ce00d3261f74ea78cd7b21b7d6df0b524 Mon Sep 17 00:00:00 2001 From: Andras Bacsai <5845193+andrasbacsai@users.noreply.github.com> Date: Sun, 4 Oct 2026 00:41:44 +0200 Subject: [PATCH] feat(server): add --force and --delete-from-provider flags to remove Pass force and delete_from_provider query parameters when deleting a server, allowing removal of all resources on the server and deletion of the server from its cloud provider (Hetzner, Vultr or DigitalOcean). Update service tests to cover all flag combinations and document the new flags in llms-full.txt. --- cmd/server/remove.go | 12 ++++++++-- internal/service/server.go | 8 ++++--- internal/service/server_test.go | 39 +++++++++++++++++++++++---------- llms-full.txt | 12 +++++++++- 4 files changed, 54 insertions(+), 17 deletions(-) diff --git a/cmd/server/remove.go b/cmd/server/remove.go index c9c833e..5529f8b 100644 --- a/cmd/server/remove.go +++ b/cmd/server/remove.go @@ -11,7 +11,7 @@ import ( // NewRemoveCommand creates the remove command func NewRemoveCommand() *cobra.Command { - return &cobra.Command{ + cmd := &cobra.Command{ Use: "remove ", Args: cli.ExactArgs(1, ""), Short: "Remove a server", @@ -28,7 +28,10 @@ func NewRemoveCommand() *cobra.Command { serverSvc := service.NewServerService(client) uuid := args[0] - if err := serverSvc.Delete(ctx, uuid); err != nil { + force, _ := cmd.Flags().GetBool("force") + deleteFromProvider, _ := cmd.Flags().GetBool("delete-from-provider") + + if err := serverSvc.Delete(ctx, uuid, force, deleteFromProvider); err != nil { return fmt.Errorf("failed to delete server: %w", err) } @@ -36,4 +39,9 @@ func NewRemoveCommand() *cobra.Command { return nil }, } + + cmd.Flags().Bool("force", false, "Also delete all resources on the server") + cmd.Flags().Bool("delete-from-provider", false, "Also delete the server from its cloud provider (Hetzner, Vultr or DigitalOcean). This cannot be undone") + + return cmd } diff --git a/internal/service/server.go b/internal/service/server.go index 823f49e..3ad650f 100644 --- a/internal/service/server.go +++ b/internal/service/server.go @@ -2,6 +2,7 @@ package service import ( "context" + "fmt" "github.com/coollabsio/coolify-cli/internal/api" "github.com/coollabsio/coolify-cli/internal/models" @@ -59,9 +60,10 @@ func (s *ServerService) Update(ctx context.Context, uuid string, req models.Serv return &response, err } -// Delete deletes a server by UUID -func (s *ServerService) Delete(ctx context.Context, uuid string) error { - return s.client.Delete(ctx, "servers/"+uuid) +// Delete deletes a server by UUID. force also deletes all resources on the server, +// deleteFromProvider also deletes the server from its cloud provider. +func (s *ServerService) Delete(ctx context.Context, uuid string, force, deleteFromProvider bool) error { + return s.client.Delete(ctx, fmt.Sprintf("servers/%s?force=%t&delete_from_provider=%t", uuid, force, deleteFromProvider)) } // Validate validates a server by UUID diff --git a/internal/service/server_test.go b/internal/service/server_test.go index ba2f594..fcb57c1 100644 --- a/internal/service/server_test.go +++ b/internal/service/server_test.go @@ -154,21 +154,38 @@ func TestServerService_Update(t *testing.T) { } func TestServerService_Delete(t *testing.T) { - server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - assert.Equal(t, "/api/v1/servers/test-uuid", r.URL.Path) - assert.Equal(t, "DELETE", r.Method) + tests := []struct { + name string + force bool + deleteFromProvider bool + wantQuery string + }{ + {"defaults", false, false, "force=false&delete_from_provider=false"}, + {"force", true, false, "force=true&delete_from_provider=false"}, + {"delete from provider", false, true, "force=false&delete_from_provider=true"}, + {"both", true, true, "force=true&delete_from_provider=true"}, + } - w.WriteHeader(http.StatusOK) - _ = json.NewEncoder(w).Encode(models.Response{Message: "Server deleted"}) - })) - defer server.Close() + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + assert.Equal(t, "/api/v1/servers/test-uuid", r.URL.Path) + assert.Equal(t, "DELETE", r.Method) + assert.Equal(t, tt.wantQuery, r.URL.RawQuery) - client := api.NewClient(server.URL, "test-token") - svc := NewServerService(client) + w.WriteHeader(http.StatusOK) + _ = json.NewEncoder(w).Encode(models.Response{Message: "Server deleted"}) + })) + defer server.Close() - err := svc.Delete(context.Background(), "test-uuid") + client := api.NewClient(server.URL, "test-token") + svc := NewServerService(client) - require.NoError(t, err) + err := svc.Delete(context.Background(), "test-uuid", tt.force, tt.deleteFromProvider) + + require.NoError(t, err) + }) + } } func TestServerService_Validate(t *testing.T) { diff --git a/llms-full.txt b/llms-full.txt index f1e1b06..4a5bac9 100644 --- a/llms-full.txt +++ b/llms-full.txt @@ -3854,7 +3854,17 @@ Parameters: Command: coolify server remove Description: Remove a server -Parameters: (None) +Parameters: + - name: --delete-from-provider + type: boolean + description: Also delete the server from its cloud provider (Hetzner, Vultr or DigitalOcean). This cannot be undone + required: false + default: false + - name: --force + type: boolean + description: Also delete all resources on the server + required: false + default: false Command: coolify server sentinel get Description: Get Sentinel settings