Skip to content

chore(cli): direct tests for the deletion-retention click entry points; non-zero exit on blocked/not-found force-purge - #44252

Merged
richardfogaca merged 2 commits into
apache:masterfrom
mikebridge:sc-115409-deletion-retention-cli-tests
Sep 14, 2026
Merged

richardfogaca merged 2 commits into
apache:masterfrom
mikebridge:sc-115409-deletion-retention-cli-tests

Conversation

@mikebridge

Copy link
Copy Markdown
Contributor

SUMMARY

superset/cli/deletion_retention.py sat at 0% coverage. The command classes underneath (ForcePurgeCommand, resolve_retention_window) are covered, but nothing drove the click entry points themselves — option parsing, the irreversible confirmation prompt on force-purge, the operator-visible output the CLI is the only consumer of, and exit codes. Raised twice by @rusackas on #41549 (07-13 and 07-29) and independently by bito; committed to as a follow-up there. Ref SC-115409.

31 CliRunner tests, unit-scoped (the command objects are mocked at their import source, so no database):

  • the group registers exactly set-window / show-window / force-purge
  • set-window: upserts the shared value for 0 / N / large; short option; a negative window is a usage error (exit 2) with nothing written; missing or non-integer --days never reaches the upsert
  • show-window: N day(s) vs disabled for zero
  • force-purge parsing: a malformed --uuid fails as a clean usage error before the prompt and before the command is constructed (the reason that option is click.UUID); --uuid required; unknown --type refused
  • the prompt: shown without --yes; an empty answer and n abort (exit 1) with no command constructed; y runs it; --yes bypasses with no prompt text
  • --type resolution: each type maps to its soft-delete model, None means every model, case-insensitive, and a drift in the type map surfaces as a ClickException rather than silently widening the purge to every model; the resolved model reaches the command
  • outcomes: a completed purge's output with counts (and with counts absent), blocked (names the blocking reason), nothing to purge, and an ambiguous bare UUID surfacing as an exit-1 error naming --type

One deliberate contract change (second commit): a force-purge whose target is blocked by a deletion rule or not found now exits 1 instead of 0, with the messages unchanged. Exiting 0 on a refusal was an operator footgun — a scripted compliance-erasure runbook could not tell a refused purge from a completed one. A completed purge still exits 0; a usage error still exits 2. Noted in UPDATING.md.

Two things the ticket's original wording assumed that the shipped CLI does not have: there is no dry-run option on force-purge (nothing to pin), and the exit-code point above was the "non-zero on blocked" it asked for.

BEFORE/AFTER SCREENSHOTS OR ANIMATED GIF

No UI. Operator-visible change: force-purge exit status on blocked / not-found (messages identical).

TESTING INSTRUCTIONS

pytest tests/unit_tests/cli/deletion_retention_test.py                 # 31 tests
pytest tests/integration_tests/deletion_retention/force_purge_tests.py -k cli   # existing CLI integration tests, unchanged

Manual: superset deletion-retention force-purge --uuid <uuid-of-a-chart-referenced-by-a-report> --yes; echo $? → the "not purged because existing deletion rules block it" message and exit status 1.

ADDITIONAL INFORMATION

  • Has associated issue: SC-115409 (follow-up to feat(soft-delete): deletion-retention purge of soft-deleted entities #41549 / SC-111185)
  • Required feature flags:
  • Changes UI
  • Includes DB Migration (follow approval process in SIP-59)
    • Migration is atomic, supports rollback & is backwards-compatible
    • Confirm DB migration upgrade and downgrade tested
    • Runtime estimates and downtime expectations provided
  • Introduces new feature or API
  • Removes existing feature or API

This PR was developed with AI assistance (Claude Code); a human (@mikebridge) reviews before merge.

Mike Bridge and others added 2 commits September 14, 2026 11:54
…sc-115409)

Raised twice by rusackas on apache#41549 and by bito: superset/cli/deletion_retention.py
sat at 0% coverage. The command classes underneath were covered; the CLI
surface itself — option parsing, the irreversible confirmation prompt on
force-purge, the operator-visible output, exit codes — was not.

31 CliRunner tests, unit-scoped (command objects mocked at their import
source, no database):
- group registers exactly set-window / show-window / force-purge
- set-window: upserts the shared value for 0 / N / large; short option;
  negative is a usage error (exit 2) with nothing written; missing or
  non-integer --days never reaches the upsert
- show-window: N day(s) vs "disabled" for zero
- force-purge parsing: malformed --uuid fails up front (exit 2) BEFORE the
  prompt and before the command is constructed; --uuid required; unknown
  --type rejected
- the prompt: shown without --yes; empty answer and "n" abort (exit 1) with
  no command constructed; "y" runs it; --yes bypasses it with no prompt text
- --type resolution: each type maps to its soft-delete model, None means
  every model, case-insensitive, and a type-map drift is a clean
  ClickException rather than a silent widen to every model; the resolved
  model reaches the command
- outcomes: successful purge output with counts (and with counts absent),
  blocked (names the blocking reason), nothing to purge, and an ambiguous
  bare UUID surfacing as a clean exit-1 error naming --type

Pinned as-is, flagged for a decision rather than changed here: a blocked or
not-found purge currently exits 0.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01267VBWbvWTNZUg9GvXKgkC
`superset deletion-retention force-purge` reported a refused (blocked by a
deletion rule) or absent target on stdout and exited 0 — indistinguishable,
to a script, from a completed purge. For an operator-facing compliance
erasure that is a footgun: a runbook could believe an entity was erased when
it was refused. Both outcomes now exit 1 with the messages unchanged; a
completed purge still exits 0 and a usage error still exits 2. Deliberate
contract change, noted in UPDATING; the two pinned tests flipped.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01267VBWbvWTNZUg9GvXKgkC
@bito-code-review

bito-code-review Bot commented Sep 14, 2026 •

Copy link
Copy Markdown
Contributor

Code Review Agent Run #b59b07

Actionable Suggestions - 0
Additional Suggestions - 1
  • tests/unit_tests/cli/deletion_retention_test.py - 1
    • Prompt text duplication · Line 51-51
      `_PROMPT` duplicates the CLI's `confirmation_option` prompt text as a hardcoded substring. If the prompt is reworded, the `_PROMPT in result.output` assertions (lines 210, 235) fail and the `_PROMPT not in result.output` checks (169, 249) could pass vacuously. Consider importing a shared prompt constant from `superset.cli.deletion_retention` to keep them coupled.
Review Details
  • Files reviewed - 2 · Commit Range: ce8be4b..7cd6b44
    • superset/cli/deletion_retention.py
    • tests/unit_tests/cli/deletion_retention_test.py
  • Files skipped - 1
    • UPDATING.md - Reason: Filter setting
  • Tools
    • MyPy (Static Code Analysis) - ✔︎ Successful
    • Astral Ruff (Static Code Analysis) - ✔︎ Successful
    • Whispers (Secret Scanner) - ✔︎ Successful
    • Detect-secrets (Secret Scanner) - ✔︎ Successful

Bito Usage Guide

Commands

Type the following command in the pull request comment and save the comment.

  • /review - Manually triggers an incremental AI Review.

  • /review full - Manually triggers a full AI Review.

  • /pause - Pauses automatic reviews on this pull request.

  • /resume - Resumes automatic reviews.

  • /resolve - Marks all Bito-posted review comments as resolved.

  • /abort - Cancels all in-progress reviews.

Refer to the documentation for additional commands.

Configuration

This repository uses Superset You can customize the agent settings here or contact your Bito workspace admin at evan@preset.io.

Documentation & Help

AI Code Review powered by Bito Logo

@codecov

codecov Bot commented Sep 14, 2026 •

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 80.19%. Comparing base (eeafd65) to head (7cd6b44).

Additional details and impacted files
@@            Coverage Diff             @@
##           master   #44252      +/-   ##
==========================================
+ Coverage   76.29%   80.19%   +3.89%     
==========================================
  Files        2925     2925              
  Lines      172692   172692              
  Branches    40090    40090              
==========================================
+ Hits       131758   138487    +6729     
+ Misses      38247    31612    -6635     
+ Partials     2687     2593      -94     
Flag Coverage Δ
hive 37.33% <0.00%> (ø)
mysql 56.85% <0.00%> (?)
postgres 56.88% <0.00%> (?)
presto 39.22% <0.00%> (ø)
python 84.59% <100.00%> (+7.70%) ⬆️
sqlite 56.58% <0.00%> (?)
unit 76.01% <100.00%> (+0.05%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@richardfogaca richardfogaca left a comment

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.

Richard's agent here:

Reviewed 7cd6b44590b2; no substantive findings. CI is green. Review was based on source and available test evidence; full local integration/browser validation was not performed.

@richardfogaca
richardfogaca merged commit c83c95f into apache:master Sep 14, 2026
81 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants