Skip to content

Commit 4cc2ddc

Browse files
feat: support hard delete (#205)
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
1 parent f1175a6 commit 4cc2ddc

60 files changed

Lines changed: 30046 additions & 81 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
kind: added
2+
body: adds hard flag to rm command (permanent delete)
3+
time: 2026-04-03T10:41:00.7101911+03:00
4+
custom:
5+
Author: v-alexmoraru
6+
AuthorLink: https://github.com/v-alexmoraru

docs/commands/fs/rm.md

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,16 +7,24 @@ Delete a workspace, item, or file.
77
**Usage:**
88

99
```
10-
fab rm <path> [-f]
10+
fab rm <path> [-f] [--hard]
1111
```
1212

1313
**Parameters:**
1414

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

1819
**Example:**
1920

2021
```
22+
# Soft delete
2123
fab rm ws1.Workspace/nb1.Notebook
24+
25+
# Force delete without confirmation
26+
fab rm ws1.Workspace/nb1.Notebook --force
27+
28+
# Hard delete (permanent removal)
29+
fab rm ws1.Workspace/nb1.Notebook --hard --force
2230
```

src/fabric_cli/client/fab_api_utils.py

Lines changed: 29 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -19,16 +19,34 @@ def delete_resource(
1919
verbose: bool = True,
2020
operation: Optional[str] = "delete",
2121
) -> bool:
22+
request_params = getattr(args, "request_params", {}) or {}
23+
hard = request_params.get("hardDelete") == "true"
24+
2225
if not bypass_confirmation:
23-
if utils_ui.prompt_confirm():
24-
return _do_delete_resource(args, operation=operation)
26+
if hard:
27+
resource_name = getattr(args, 'name', 'resource')
28+
confirm_message = f"'{resource_name}' will be deleted forever. Are you sure you want to proceed?"
29+
else:
30+
confirm_message = "Are you sure?"
31+
32+
if utils_ui.prompt_confirm(confirm_message):
33+
if hard and verbose:
34+
utils_ui.print_warning("! Executing hard delete")
35+
return _do_delete_resource(args, verbose=verbose, operation=operation)
2536
else:
2637
if verbose:
27-
utils_ui.print_warning(f"Resource {operation} cancelled")
38+
utils_ui.print_warning(
39+
f"Resource {operation or 'operation'} cancelled"
40+
)
2841
return False
2942
else:
3043
if verbose:
31-
utils_ui.print_warning(f"Executing force {operation}...")
44+
if hard:
45+
utils_ui.print_warning("! Executing force hard delete")
46+
elif operation:
47+
utils_ui.print_warning(f"Executing force {operation}...")
48+
else:
49+
utils_ui.print_warning("Executing force operation...")
3250
return _do_delete_resource(args, verbose=verbose, operation=operation)
3351

3452

@@ -125,7 +143,8 @@ def get_api_version(resource_uri: str) -> Any:
125143
return rt["apiVersions"][0]
126144

127145
raise FabricCLIError(
128-
ErrorMessages.Client.resource_type_not_found_in_provider(args.resource_type, args.provider_namespace),
146+
ErrorMessages.Client.resource_type_not_found_in_provider(
147+
args.resource_type, args.provider_namespace),
129148
status_code=constant.ERROR_NOT_SUPPORTED,
130149
)
131150

@@ -136,7 +155,8 @@ def _do_delete_resource(
136155
) -> bool:
137156
if verbose:
138157
if operation is not None:
139-
utils_ui.print_grey(f"{_to_gerund_capitalized(operation)} '{args.name}'...")
158+
utils_ui.print_grey(
159+
f"{_to_gerund_capitalized(operation)} '{args.name}'...")
140160
response = fabric_api.do_request(args)
141161

142162
return _validate_success_and_print_on_verbose(
@@ -187,6 +207,7 @@ def _do_unassign_resource(
187207
args, "unassigned", response.status_code, verbose
188208
)
189209

210+
190211
def _to_gerund_capitalized(operation: str) -> str:
191212
if operation.endswith("e") and not operation.endswith("ee"):
192213
result = f"{operation[:-1]}ing"
@@ -200,7 +221,8 @@ def _validate_success_and_print_on_verbose(
200221
) -> bool:
201222
if status_code in [200, 201]:
202223
if verbose:
203-
utils_ui.print_output_format(args, message=f"'{args.name}' {action}")
224+
utils_ui.print_output_format(
225+
args, message=f"'{args.name}' {action}")
204226
return True
205227
if status_code == 202:
206228
if verbose:

src/fabric_cli/commands/fs/rm/fab_fs_rm_item.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
from fabric_cli.client import fab_api_item as item_api
77
from fabric_cli.core.hiearchy.fab_hiearchy import Item
88
from fabric_cli.utils import fab_mem_store as utils_mem_store
9+
from fabric_cli.utils import fab_cmd_rm_utils as rm_utils
910

1011

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

18+
rm_utils.setup_delete_request_params(args)
19+
1720
if item_api.delete_item(args, force_delete):
1821
# Remove from mem_store
1922
utils_mem_store.delete_item_from_cache(item)

src/fabric_cli/commands/fs/rm/fab_fs_rm_workspace.py

Lines changed: 17 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -13,16 +13,18 @@
1313
from fabric_cli.core.hiearchy.fab_hiearchy import Item, Tenant, Workspace
1414
from fabric_cli.utils import fab_mem_store as utils_mem_store
1515
from fabric_cli.utils import fab_ui as utils_ui
16-
from fabric_cli.utils import fab_util as utils
16+
from fabric_cli.utils import fab_cmd_rm_utils as rm_utils
1717
from fabric_cli.utils import fab_item_util as item_utils
1818

1919

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

2425
names = [workspace.name for workspace in sorted_workspaces]
25-
selected_workspaces = utils_ui.prompt_select_items("Select workspaces:", names)
26+
selected_workspaces = utils_ui.prompt_select_items(
27+
"Select workspaces:", names)
2628
if selected_workspaces:
2729
for workspace_str in selected_workspaces:
2830
utils_ui.print_grey(workspace_str)
@@ -51,7 +53,8 @@ def bulk(tenant: Tenant, args: Namespace, force_delete: bool) -> None:
5153
utils_mem_store.delete_workspace_from_cache(workspace)
5254

5355
utils_ui.print("")
54-
utils_ui.print_output_format(args, message=f"{deleted_workspaces} workspaces deleted successfully")
56+
utils_ui.print_output_format(
57+
args, message=f"{deleted_workspaces} workspaces deleted successfully")
5558

5659

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

7982
if force_delete:
80-
utils_ui.print_grey(f"This will delete {len(ws_items)} underlying items")
83+
utils_ui.print_grey(
84+
f"This will delete {len(ws_items)} underlying items")
8185

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

96100
names = [item.name for item in sorted_items]
97-
selected_items = utils_ui.prompt_select_items("Select items:", names)
101+
selected_items = utils_ui.prompt_select_items(
102+
"Select items:", names)
98103
if selected_items:
99104
for item_str in selected_items:
100105
utils_ui.print_grey(item_str)
@@ -113,18 +118,22 @@ def single(workspace: Workspace, args: Namespace, force_delete: bool) -> None:
113118
args.name = item.name
114119
args.item_type = str(item.item_type)
115120

121+
rm_utils.setup_delete_request_params(args)
122+
116123
# Reset args for subsequent calls
117124
args.uri = None
118125
args.method = None
119126

120127
if item_api.delete_item(
121128
args, bypass_confirmation=True, verbose=False
122129
):
123-
utils_ui.print_output_format(args, message=f"'{args.name}' deleted")
130+
utils_ui.print_output_format(
131+
args, message=f"'{args.name}' deleted")
124132
deleted_items = deleted_items + 1
125133

126134
# Remove from mem_store
127135
utils_mem_store.delete_item_from_cache(item)
128136

129137
utils_ui.print("")
130-
utils_ui.print_output_format(args, message=f"{deleted_items} items deleted successfully")
138+
utils_ui.print_output_format(
139+
args, message=f"{deleted_items} items deleted successfully")

0 commit comments

Comments
 (0)