# feat(control-plane): idempotent deletes + command-level wiring tests

`ed45929`·  
  
toothbrush·3w ago·2 files·+105 added/-0 removed

- org/project/repo delete now treat a 404 from the delete call as the  
desired end state (already gone), printing "<noun> <label> not found;  
nothing to delete" instead of surfacing a raw 404.
- Add command-level tests driving each delete command through cobra  
against a fake control plane: --force issues DELETE on the right path,  
an already-gone resource is idempotent, and a non-interactive run  
without --force refuses rather than deleting unprompted.

Addresses trail #642 findings.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

## Sessions

416181183067View transcript

## Changes

2

- cmd/entire/cli

- Mcorecmd.go+7

- Acorecmd_delete_test.go+98

```
89 unmodified lines

return nil
}
if err := del(ctx, c, id); err != nil {
	// Idempotent delete: a resource that's already gone (a 404 from the
	// delete call — e.g. a ULID passed straight through, or a concurrent
	// delete) is the desired end state, not an error.
	if isNotFound(err) {
		cmd.Printf("%s not found; nothing to delete\n", label)
		return nil
	}
	return err
}
cmd.Printf("Deleted %s\n", label)
```

Mcmd/entire/cli/corecmd.go+7

```
package cli

import (
	"bytes"
	"context"
	"net/http"
	"net/http/httptest"
	"testing"

"github.com/spf13/cobra"
	"github.com/stretchr/testify/require"

"github.com/entireio/cli/internal/coreapi"
)

// testDeleteULID is a syntactically valid ULID (26 Crockford base32 chars, no
// I/L/O/U) so it passes looksLikeULID and the delete commands skip the name
// lookup, addressing the resource by id directly.
const testDeleteULID = "01HZX7QABCDEFGHJKMNPQRSTVW"

// runDeleteCmd points the active-context client at srv via the activeCoreClient
// seam, runs newCmd() with args, and returns its stdout and error. The caller
// must not be parallel: the seam is package-global.
func runDeleteCmd(t *testing.T, newCmd func() *cobra.Command, srvURL string, args ...string) (string, error) {
	t.Helper()
	prev := activeCoreClient
	activeCoreClient = func(context.Context) (*coreapi.Client, error) {
		return coreapi.NewWithBearer(srvURL, "tok")
	}
	t.Cleanup(func() { activeCoreClient = prev })

cmd := newCmd()
	var out bytes.Buffer
	cmd.SetOut(&out)
	cmd.SetErr(&bytes.Buffer{})
	cmd.SetArgs(args)
	err := cmd.ExecuteContext(t.Context())
	return out.String(), err
}

// TestControlPlaneDelete_Wiring exercises the org/project/repo delete commands
// end-to-end through cobra: that --force bypasses the prompt and issues DELETE
// against the right path, that an already-gone resource (404) is idempotent,
// and that a non-interactive run without --force refuses rather than deleting
// unprompted.
//
// Not parallel: swaps the package-level activeCoreClient seam.
func TestControlPlaneDelete_Wiring(t *testing.T) {
	cases := []struct {
		noun     string
		newCmd   func() *cobra.Command
		wantPath string
	}{
		{"org", newOrgDeleteCmd, "/api/v1/orgs/" + testDeleteULID},
		{"project", newProjectDeleteCmd, "/api/v1/projects/" + testDeleteULID},
		{"repo", newRepoDeleteCmd, "/api/v1/repos/" + testDeleteULID},
	}

for _, tc := range cases {
		t.Run(tc.noun+"/force deletes via the right path", func(t *testing.T) {
			var gotMethod, gotPath string
			srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
				gotMethod, gotPath = r.Method, r.URL.Path
				w.WriteHeader(http.StatusNoContent)
			}))
			t.Cleanup(srv.Close)

out, err := runDeleteCmd(t, tc.newCmd, srv.URL, testDeleteULID, "--force")
			require.NoError(t, err)
			require.Equal(t, http.MethodDelete, gotMethod)
			require.Equal(t, tc.wantPath, gotPath)
			require.Contains(t, out, "Deleted "+tc.noun+" "+testDeleteULID)
		})

t.Run(tc.noun+"/already-gone is idempotent", func(t *testing.T) {
			srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {
				writeNotFoundProblem(t, w)
			}))
			t.Cleanup(srv.Close)

out, err := runDeleteCmd(t, tc.newCmd, srv.URL, testDeleteULID, "--force")
			require.NoError(t, err)
			require.Contains(t, out, "not found; nothing to delete")
		})

t.Run(tc.noun+"/refuses without --force when non-interactive", func(t *testing.T) {
			// A ULID needs no resolve, so the refusal lands before any request.
			srv := httptest.NewServer(http.HandlerFunc(func(_ http.ResponseWriter, r *http.Request) {
				t.Errorf("unexpected request %s %s", r.Method, r.URL.Path)
			}))
			t.Cleanup(srv.Close)

_, err := runDeleteCmd(t, tc.newCmd, srv.URL, testDeleteULID)
			require.Error(t, err)
			require.Contains(t, err.Error(), "--force")
		})
	}
}
