Skip to content

feat: add --ignore-not-found flag for delete command#6733

Merged
vsukhin merged 2 commits intokubeshop:dhimanAbhi/feat/add-ignore-not-found-flagfrom
dhimanAbhi:feat/add-ignore-not-found-flag
May 5, 2026
Merged

feat: add --ignore-not-found flag for delete command#6733
vsukhin merged 2 commits intokubeshop:dhimanAbhi/feat/add-ignore-not-found-flagfrom
dhimanAbhi:feat/add-ignore-not-found-flag

Conversation

@dhimanAbhi
Copy link
Copy Markdown
Contributor

@dhimanAbhi dhimanAbhi commented Oct 6, 2025

Pull request description

This PR introduces the --ignore-not-found flag to the testkube delete command. When enabled, this flag suppresses the error and non-zero exit code if the specified resource is does not exist.

This improves usability in scripting and CI/CD environments by preventing unnecessary command failures when attempting to delete non-existent resources as descrinbed in #2304

Changes

  • Added persistent flag to parent delete command
  • Implemented ignore logic in all delete subcommands:
    • testkube delete test
    • testkube delete testsuite
    • testkube delete testworkflow
    • testkube delete executor
    • testkube delete template
    • testkube delete testsource
    • testkube delete webhook
    • testkube delete webhooktemplate
    • testkube delete testworkflowtemplate

Proof Manifests

Before

$ testkube delete testworkflow idonotexist

Context:  (999.0.0-a378893ba)   Namespace: testkube
---------------------------------------------------

delete test workflow idonotexist from namespace testkube (error: api/DELETE-v1/test-workflows/idonotexist returned error: api server problem: failed to delete test workflow 'idonotexist': client not found: testworkflows.testworkflows.testkube.io "idonotexist" not found, context: null;
resp error:the server could not find the requested resource (delete services testkube-api-server:8088))

After

$ testkube delete testworkflow idonotexist --ignore-not-found

Context:  (999.0.0-a378893ba)   Namespace: testkube
---------------------------------------------------
Testworkflow 'idonotexist' not found, but ignoring since --ignore-not-found was passed
Operation completed 🥇

@dhimanAbhi dhimanAbhi requested a review from a team as a code owner October 6, 2025 07:37
@dhimanAbhi dhimanAbhi changed the title add --ignore-not-found flag for delete command feat: add --ignore-not-found flag for delete command Oct 6, 2025
Copy link
Copy Markdown
Collaborator

@vsukhin vsukhin left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

hey, @dhimanAbhi
thank you for your contribution

but some of these resource will be deprecated very soon
testkube delete test
testkube delete testsuite
testkube delete executor
testkube delete template
testkube delete testsource

@dhimanAbhi
Copy link
Copy Markdown
Contributor Author

@vsukhin , Thanks for your review. As per your your suggestions, I will provide this flag for these resources only -

  • testworkflow
  • testworkflowtemplate
  • webhook
  • webhooktemplate

@olensmar olensmar added the 👽 external-contribution External contribution label Jan 17, 2026
@vsukhin
Copy link
Copy Markdown
Collaborator

vsukhin commented Feb 20, 2026

@greptile

@greptile-apps
Copy link
Copy Markdown
Contributor

greptile-apps Bot commented Feb 20, 2026

Greptile Summary

This PR adds an --ignore-not-found persistent flag to the testkube delete command family so that scripting and CI/CD pipelines do not fail when attempting to delete a resource that does not exist. The flag is registered on the parent delete command (making it available to all subcommands) and each subcommand reads it via cmd.Flags().GetBool("ignore-not-found"), calling ui.SuccessAndExit instead of ui.ExitOnError when the condition is met.

Key findings:

  • apiutils.IsNotFound is incompatible with HTTP client errors (critical): apiutils.IsNotFound was written for server-side use — it recognises mongo.ErrNoDocuments, pgx.ErrNoRows, Kubernetes StatusError (via k8serrors.IsNotFound), secretmanager.ErrNotFound, and gRPC codes.NotFound. The CLI's ProxyClient and DirectClient both surface 404 responses as plain formatted strings (fmt.Errorf("api server problem: %s", ...) / fmt.Errorf("problem: %+v", ...)). These carry no typed error in their unwrap chain, so every check inside apiutils.IsNotFound returns false. The flag will therefore never suppress an error in the proxy or direct client modes, making the feature a functional no-op for the standard CLI use-case.
  • deleteAll path lacks the not-found guard: In both testworkflows/delete.go and testworkflowtemplates/delete.go, the branch that deletes all resources with --all does not apply the --ignore-not-found logic, creating an inconsistency.
  • Flag error silently discarded: All subcommands use ignoreNotFound, _ = cmd.Flags().GetBool(...), discarding the error returned from GetBool. While this is unlikely to cause a runtime problem (the flag is always registered on the parent), it is inconsistent with how other flag reads in the codebase are handled.

Confidence Score: 2/5

  • Not safe to merge — the core feature is effectively a no-op due to apiutils.IsNotFound being incompatible with HTTP client error types.
  • The flag is wired up correctly at the CLI level, but the apiutils.IsNotFound helper used to detect 404 conditions only understands typed server-side errors (MongoDB, pgx, gRPC, k8s StatusError). Both ProxyClient and DirectClient convert HTTP 404 responses into plain formatted strings with no typed error in the unwrap chain, so apiutils.IsNotFound always returns false. The feature would silently not work for all standard client modes, which is worse than the feature not existing at all because users would believe errors are being suppressed when they are not.
  • All four subcommand delete files (testworkflows/delete.go, testworkflowtemplates/delete.go, webhooks/delete.go, webhooktemplates/delete.go) and the underlying client transport error handling in pkg/api/v1/client/proxy_client.go and pkg/api/v1/client/direct_client.go.

Important Files Changed

Filename Overview
cmd/kubectl-testkube/commands/delete.go Adds the --ignore-not-found persistent flag to the parent delete command so all subcommands inherit it. Change is minimal and correct.
cmd/kubectl-testkube/commands/testworkflows/delete.go Adds --ignore-not-found handling via apiutils.IsNotFound, which only recognises server-side typed errors (MongoDB, pgx, gRPC, k8s StatusError). The proxy and direct HTTP clients return plain string errors for 404s, so apiutils.IsNotFound always returns false and the flag is effectively a no-op. The deleteAll branch is also missing the guard.
cmd/kubectl-testkube/commands/testworkflowtemplates/delete.go Same apiutils.IsNotFound issue as testworkflows/delete.go; will not correctly suppress 404 errors from HTTP-based clients. deleteAll path also lacks the guard.
cmd/kubectl-testkube/commands/webhooks/delete.go Applies --ignore-not-found for both single-name and selector-based deletions, but suffers from the same apiutils.IsNotFound incompatibility with HTTP client error strings.
cmd/kubectl-testkube/commands/webhooktemplates/delete.go Same pattern and same apiutils.IsNotFound compatibility issue as the webhook delete command.

Sequence Diagram

sequenceDiagram
    participant User
    participant CLI as testkube CLI (delete subcommand)
    participant Transport as ProxyClient / DirectClient
    participant API as Testkube API Server

    User->>CLI: testkube delete testworkflow foo --ignore-not-found
    CLI->>CLI: ignoreNotFound, _ = cmd.Flags().GetBool("ignore-not-found")
    CLI->>Transport: client.DeleteTestWorkflow("foo")
    Transport->>API: DELETE /v1/test-workflows/foo
    API-->>Transport: HTTP 404 + problem JSON body
    Note over Transport: responseError() parses problem JSON<br/>returns fmt.Errorf("api server problem: %s", detail)<br/>(plain string, no typed error wrapper)
    Transport-->>CLI: error = "api/DELETE-... returned error: api server problem: ..."
    CLI->>CLI: apiutils.IsNotFound(err)
    Note over CLI: Checks: mongo.ErrNoDocuments? NO<br/>pgx.ErrNoRows? NO<br/>k8serrors.IsNotFound? NO (plain string)<br/>secretmanager.ErrNotFound? NO<br/>gRPC codes.NotFound? NO<br/>→ returns false
    CLI->>User: ui.ExitOnError(...) — exits with non-zero ❌
    Note over User,CLI: --ignore-not-found flag has no effect
Loading

Comments Outside Diff (1)

  1. cmd/kubectl-testkube/commands/testworkflows/delete.go, line 38-41 (link)

    --ignore-not-found not applied to deleteAll path

    The deleteAll branch (line 38–41) does not apply the --ignore-not-found logic. Attempting to delete all test workflows in a namespace that has none could return a "not found" error from the server. For consistency with the rest of the implementation, consider adding the same guard here:

Last reviewed commit: 3e29773

Copy link
Copy Markdown
Contributor

@greptile-apps greptile-apps Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

10 files reviewed, 3 comments

Edit Code Review Agent Settings | Greptile

Comment thread cmd/kubectl-testkube/commands/testworkflows/delete.go Outdated
Comment thread cmd/kubectl-testkube/commands/tests/delete.go Outdated
Comment thread cmd/kubectl-testkube/commands/templates/delete.go Outdated
Copy link
Copy Markdown
Collaborator

@vsukhin vsukhin left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

hey @dhimanAbhi it looks good, you need just back merge main branch and fix a couple of greptile comments

@olensmar
Copy link
Copy Markdown
Member

olensmar commented Mar 3, 2026

@dhimanAbhi will you be able to fix this as requested above? 🙏

@dhimanAbhi
Copy link
Copy Markdown
Contributor Author

Hi @olensmar, I’ll address the review comments and update this PR by the end of the week. Thanks for the reminder.

Signed-off-by: Abhishek Dhiman <abhi2002dhiman@gmail.com>
Signed-off-by: Abhishek Dhiman <abhi2002dhiman@gmail.com>
@dhimanAbhi dhimanAbhi force-pushed the feat/add-ignore-not-found-flag branch from 4ea86e1 to 3e29773 Compare March 9, 2026 06:14
@vsukhin
Copy link
Copy Markdown
Collaborator

vsukhin commented Mar 10, 2026

@greptile

Comment on lines +50 to +53
if ignoreNotFound && apiutils.IsNotFound(err) {
ui.Info("Testworkflow '" + name + "' not found, but ignoring since --ignore-not-found was passed")
ui.SuccessAndExit("Operation completed")
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

apiutils.IsNotFound won't detect HTTP client errors

apiutils.IsNotFound checks for mongo.ErrNoDocuments, pgx.ErrNoRows, k8serrors.IsNotFound, secretmanager.ErrNotFound, and gRPC codes.NotFound — it is designed for server-side error detection.

However, the CLI clients (ProxyClient, DirectClient) return plain-string formatted errors for 404 responses:

  • Proxy client: fmt.Errorf("api server problem: %s", pr.Detail) (no %w, no typed error wrapping)
  • Direct client: fmt.Errorf("problem: %+v", pr.Detail) (same)

Neither of these carries a wrapped typed error that the checks in apiutils.IsNotFound can detect. Consequently, apiutils.IsNotFound(err) will always return false for errors coming from the HTTP API clients, making --ignore-not-found a functional no-op — the error will still be passed to ui.ExitOnError.

The same issue affects every other site in this PR where apiutils.IsNotFound is used (lines 32–35 in this file, and corresponding locations in testworkflowtemplates/delete.go, webhooks/delete.go, webhooktemplates/delete.go).

A common workaround used in similar CLI tools is a string-based check, or adding a typed ErrNotFound sentinel in the client package that the transport layers wrap their 404 errors into. For example, a minimal string-based helper in the client package:

func IsNotFound(err error) bool {
    if err == nil {
        return false
    }
    msg := strings.ToLower(err.Error())
    return strings.Contains(msg, "not found") || strings.Contains(msg, "404")
}

This approach is fragile but consistent with how the existing proxy/direct client surfaces errors. Ideally a typed sentinel error should be introduced in the transport layer.

Comment on lines +32 to +35
if ignoreNotFound && apiutils.IsNotFound(err) {
ui.Info("Testworkflow not found for matching selector '" + selector + "', but ignoring since --ignore-not-found was passed")
ui.SuccessAndExit("Operation completed")
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

--ignore-not-found with selector never exits the function on ignore

When the ignoreNotFound check fires and calls ui.SuccessAndExit, control never reaches return (line 46). The ui.SuccessAndExit call does call os.Exit(0), so it terminates the process. However, this creates a subtle inconsistency: for the selector path the function uses return after the success/error pair, while the ignore path relies on os.Exit. This is consistent with the surrounding pattern but worth noting that the ignored-not-found path in the selector branch also skips the return statement on line 45, which is fine here because SuccessAndExit exits the process — but a future refactor that replaces SuccessAndExit with a non-exiting function would introduce a bug.

@vsukhin
Copy link
Copy Markdown
Collaborator

vsukhin commented Mar 10, 2026

hey @dhimanAbhi please check above feedback

@vsukhin
Copy link
Copy Markdown
Collaborator

vsukhin commented Mar 19, 2026

hey @dhimanAbhi, will you be able to check it or do yo need our help?

@vsukhin vsukhin changed the base branch from main to dhimanAbhi/feat/add-ignore-not-found-flag May 5, 2026 10:16
@vsukhin vsukhin merged commit 9aef050 into kubeshop:dhimanAbhi/feat/add-ignore-not-found-flag May 5, 2026
5 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

👽 external-contribution External contribution

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants