Skip to content
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions .changes/unreleased/added-20260403-104100.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
kind: added
body: adds purge flag to rm command (permanent delete)
time: 2026-04-03T10:41:00.7101911+03:00
custom:
Author: v-alexmoraru
AuthorLink: https://github.com/v-alexmoraru
10 changes: 9 additions & 1 deletion docs/commands/fs/rm.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,16 +7,24 @@ Delete a workspace, item, or file.
**Usage:**

```
fab rm <path> [-f]
fab rm <path> [-f] [--purge]
```

**Parameters:**

- `<path>`: Path to delete.
- `-f, --force`: Force deletion without confirmation. Optional.
- `--purge`: Permanently delete items (when applicable). Cannot be recovered. Ignored for workspace force deletion. Optional.

**Example:**

```
# Soft delete
fab rm ws1.Workspace/nb1.Notebook

# Force delete without confirmation
fab rm ws1.Workspace/nb1.Notebook --force

# Purge delete (permanent removal)
fab rm ws1.Workspace/nb1.Notebook --purge --force
```
29 changes: 23 additions & 6 deletions src/fabric_cli/client/fab_api_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,16 +19,29 @@ def delete_resource(
verbose: bool = True,
operation: Optional[str] = "delete",
) -> bool:
purge = bool(getattr(args, 'purge', False))

if not bypass_confirmation:
if utils_ui.prompt_confirm():
return _do_delete_resource(args, operation=operation)
if purge:
resource_name = getattr(args, 'name', 'resource')
confirm_message = f"'{resource_name}' will be deleted forever. Are you sure you want to proceed?"
else:
confirm_message = "Are you sure?"

if utils_ui.prompt_confirm(confirm_message):
if purge and verbose:
utils_ui.print_warning("! Executing purge delete")
return _do_delete_resource(args, verbose=verbose, operation=operation)
else:
if verbose:
utils_ui.print_warning(f"Resource {operation} cancelled")
return False
else:
if verbose:
utils_ui.print_warning(f"Executing force {operation}...")
if purge:
utils_ui.print_warning("! Executing force purge delete")
else:
utils_ui.print_warning(f"Executing force {operation}...")
return _do_delete_resource(args, verbose=verbose, operation=operation)
Comment thread
v-alexmoraru marked this conversation as resolved.


Expand Down Expand Up @@ -125,7 +138,8 @@ def get_api_version(resource_uri: str) -> Any:
return rt["apiVersions"][0]

raise FabricCLIError(
ErrorMessages.Client.resource_type_not_found_in_provider(args.resource_type, args.provider_namespace),
ErrorMessages.Client.resource_type_not_found_in_provider(
args.resource_type, args.provider_namespace),
Comment thread
v-alexmoraru marked this conversation as resolved.
Comment thread
v-alexmoraru marked this conversation as resolved.
status_code=constant.ERROR_NOT_SUPPORTED,
)

Expand All @@ -136,7 +150,8 @@ def _do_delete_resource(
) -> bool:
if verbose:
if operation is not None:
utils_ui.print_grey(f"{_to_gerund_capitalized(operation)} '{args.name}'...")
utils_ui.print_grey(
f"{_to_gerund_capitalized(operation)} '{args.name}'...")
response = fabric_api.do_request(args)

return _validate_success_and_print_on_verbose(
Expand Down Expand Up @@ -187,6 +202,7 @@ def _do_unassign_resource(
args, "unassigned", response.status_code, verbose
)


def _to_gerund_capitalized(operation: str) -> str:
if operation.endswith("e") and not operation.endswith("ee"):
result = f"{operation[:-1]}ing"
Expand All @@ -200,7 +216,8 @@ def _validate_success_and_print_on_verbose(
) -> bool:
if status_code in [200, 201]:
if verbose:
utils_ui.print_output_format(args, message=f"'{args.name}' {action}")
utils_ui.print_output_format(
args, message=f"'{args.name}' {action}")
return True
if status_code == 202:
if verbose:
Expand Down
3 changes: 3 additions & 0 deletions src/fabric_cli/commands/fs/rm/fab_fs_rm_item.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
from fabric_cli.client import fab_api_item as item_api
from fabric_cli.core.hiearchy.fab_hiearchy import Item
from fabric_cli.utils import fab_mem_store as utils_mem_store
from fabric_cli.utils import fab_util as utils


def exec(item: Item, args: Namespace, force_delete: bool) -> None:
Expand All @@ -14,6 +15,8 @@ def exec(item: Item, args: Namespace, force_delete: bool) -> None:
args.name = item.name
args.item_type = item.type.value

utils.setup_delete_request_params(args)

if item_api.delete_item(args, force_delete):
# Remove from mem_store
utils_mem_store.delete_item_from_cache(item)
23 changes: 16 additions & 7 deletions src/fabric_cli/commands/fs/rm/fab_fs_rm_workspace.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,12 @@

def bulk(tenant: Tenant, args: Namespace, force_delete: bool) -> None:
workspaces: list[Workspace] = utils_mem_store.get_workspaces(tenant)
sorted_workspaces: list[Workspace] = sorted(workspaces, key=lambda ws: ws.name)
sorted_workspaces: list[Workspace] = sorted(
workspaces, key=lambda ws: ws.name)

names = [workspace.name for workspace in sorted_workspaces]
selected_workspaces = utils_ui.prompt_select_items("Select workspaces:", names)
selected_workspaces = utils_ui.prompt_select_items(
"Select workspaces:", names)
if selected_workspaces:
for workspace_str in selected_workspaces:
utils_ui.print_grey(workspace_str)
Expand Down Expand Up @@ -51,7 +53,8 @@ def bulk(tenant: Tenant, args: Namespace, force_delete: bool) -> None:
utils_mem_store.delete_workspace_from_cache(workspace)

utils_ui.print("")
utils_ui.print_output_format(args, message=f"{deleted_workspaces} workspaces deleted successfully")
utils_ui.print_output_format(
args, message=f"{deleted_workspaces} workspaces deleted successfully")


def single(workspace: Workspace, args: Namespace, force_delete: bool) -> None:
Expand All @@ -77,7 +80,8 @@ def single(workspace: Workspace, args: Namespace, force_delete: bool) -> None:
pass

if force_delete:
utils_ui.print_grey(f"This will delete {len(ws_items)} underlying items")
utils_ui.print_grey(
f"This will delete {len(ws_items)} underlying items")

if workspace_api.delete_workspace(args, force_delete):
# Remove from mem_store
Expand All @@ -94,7 +98,8 @@ def single(workspace: Workspace, args: Namespace, force_delete: bool) -> None:
sorted_items = item_utils.sort_ws_elems_by_config(supported_items)

names = [item.name for item in sorted_items]
selected_items = utils_ui.prompt_select_items("Select items:", names)
selected_items = utils_ui.prompt_select_items(
"Select items:", names)
if selected_items:
for item_str in selected_items:
utils_ui.print_grey(item_str)
Expand All @@ -113,18 +118,22 @@ def single(workspace: Workspace, args: Namespace, force_delete: bool) -> None:
args.name = item.name
args.item_type = str(item.item_type)

utils.setup_delete_request_params(args)

# Reset args for subsequent calls
args.uri = None
args.method = None

if item_api.delete_item(
args, bypass_confirmation=True, verbose=False
):
utils_ui.print_output_format(args, message=f"'{args.name}' deleted")
utils_ui.print_output_format(
args, message=f"'{args.name}' deleted")
deleted_items = deleted_items + 1

# Remove from mem_store
utils_mem_store.delete_item_from_cache(item)

utils_ui.print("")
utils_ui.print_output_format(args, message=f"{deleted_items} items deleted successfully")
utils_ui.print_output_format(
args, message=f"{deleted_items} items deleted successfully")
Loading
Loading