Skip to content

Commit 495e96a

Browse files
Chore: Show resources to be deleted and enhance warnings in destroy
1 parent 107fe25 commit 495e96a

File tree

6 files changed

+115
-16
lines changed

6 files changed

+115
-16
lines changed

docs/reference/cli.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -149,7 +149,7 @@ Options:
149149
```
150150
Usage: sqlmesh destroy
151151
152-
Removes all project resources, including warehouse objects, state tables, the SQLMesh cache and any build artifacts.
152+
Removes all state tables, the SQLMesh cache and all project resources, including warehouse objects. This includes all tables, views and schemas managed by SQLMesh, as well as any external resources that may have been created by other tools within those schemas.
153153
154154
Options:
155155
--help Show this message and exit.

docs/reference/notebook.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -250,7 +250,7 @@ options:
250250
```
251251
%destroy
252252
253-
Removes all project resources, including warehouse objects, state tables, the SQLMesh cache and any build artifacts.
253+
Removes all state tables, the SQLMesh cache, and other project resources, including warehouse objects. This includes all tables, views, and schemas managed by SQLMesh, as well as any external resources that may have been created by other tools within those schemas.
254254
```
255255

256256
#### dlt_refresh

sqlmesh/core/console.py

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1277,14 +1277,20 @@ def stop_cleanup(self, success: bool = False) -> None:
12771277
self.log_error("Cleanup failed!")
12781278

12791279
def start_destroy(self) -> bool:
1280-
self.log_warning(
1280+
self.log_error(
12811281
(
1282-
"This will permanently delete all engine-managed objects, state tables and SQLMesh cache.\n"
1282+
"!!! EXTREME CAUTION: DESTRUCTIVE OPERATION !!!\n\n"
1283+
"The 'destroy' command will PERMANENTLY DELETE:\n"
1284+
" • ALL state tables and metadata\n"
1285+
" • ALL SQLMesh cache and build artifacts\n"
1286+
" • ALL tables and views in the project's schemas/datasets\n"
1287+
" • ALL schemas/datasets managed by SQLMesh in this project\n\n"
1288+
"!!! WARNING: This includes external tables created or managed by other tools !!!\n\n"
12831289
"The operation is irreversible and may disrupt any currently running or scheduled plans.\n"
1284-
"Use this command only when you intend to fully reset the project."
1290+
"Only use this command when you intend to COMPLETELY DESTROY the project.\n"
12851291
)
12861292
)
1287-
if not self._confirm("Proceed?"):
1293+
if not self._confirm("Do you understand the risks and want to see what will be deleted?"):
12881294
self.log_error("Destroy aborted!")
12891295
return False
12901296
return True

sqlmesh/core/context.py

Lines changed: 78 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -842,8 +842,7 @@ def destroy(self) -> bool:
842842

843843
if self.console.start_destroy():
844844
try:
845-
self._destroy()
846-
success = True
845+
success = self._destroy()
847846
finally:
848847
self.console.stop_destroy(success=success)
849848

@@ -2705,7 +2704,81 @@ def _context_diff(
27052704
always_recreate_environment=always_recreate_environment,
27062705
)
27072706

2708-
def _destroy(self) -> None:
2707+
def _destroy(self) -> bool:
2708+
environments = self.state_reader.get_environments()
2709+
2710+
schemas_to_delete = set()
2711+
tables_to_delete = set()
2712+
views_to_delete = set()
2713+
all_snapshot_infos = set()
2714+
2715+
# For each environment find schemas and tables
2716+
for environment in environments:
2717+
all_snapshot_infos.update(environment.snapshots)
2718+
snapshots = self.state_reader.get_snapshots(environment.snapshots).values()
2719+
for snapshot in snapshots:
2720+
if snapshot.is_model and not snapshot.is_symbolic:
2721+
# Get the appropriate adapter
2722+
if environment.gateway_managed and snapshot.model_gateway:
2723+
adapter = self.engine_adapters.get(
2724+
snapshot.model_gateway, self.engine_adapter
2725+
)
2726+
else:
2727+
adapter = self.engine_adapter
2728+
2729+
if environment.suffix_target.is_schema or environment.suffix_target.is_catalog:
2730+
schema = snapshot.qualified_view_name.schema_for_environment(
2731+
environment.naming_info, dialect=adapter.dialect
2732+
)
2733+
catalog = snapshot.qualified_view_name.catalog_for_environment(
2734+
environment.naming_info, dialect=adapter.dialect
2735+
)
2736+
if catalog:
2737+
schemas_to_delete.add(f"{catalog}.{schema}")
2738+
else:
2739+
schemas_to_delete.add(schema)
2740+
2741+
if environment.suffix_target.is_table:
2742+
view_name = snapshot.qualified_view_name.for_environment(
2743+
environment.naming_info, dialect=adapter.dialect
2744+
)
2745+
views_to_delete.add(view_name)
2746+
2747+
# Add snapshot tables
2748+
table_name = snapshot.table_name()
2749+
tables_to_delete.add(table_name)
2750+
2751+
# Display what will be deleted
2752+
self.console.log_error("\n" + "=" * 50 + "\n")
2753+
if schemas_to_delete:
2754+
self.console.log_error("Schemas to be deleted:")
2755+
for schema in sorted(schemas_to_delete):
2756+
self.console.log_error(f" • {schema}")
2757+
2758+
if views_to_delete:
2759+
self.console.log_error("\nEnvironment views to be deleted:")
2760+
for view in sorted(views_to_delete):
2761+
self.console.log_error(f" • {view}")
2762+
2763+
if tables_to_delete:
2764+
self.console.log_error("\nSnapshot tables to be deleted:")
2765+
for table in sorted(tables_to_delete):
2766+
self.console.log_error(f" • {table}")
2767+
2768+
self.console.log_error("\nAll SQLMesh state tables will be deleted")
2769+
self.console.log_error("\n" + "=" * 50 + "\n")
2770+
2771+
# Final confirmation with stronger warning
2772+
self.console.log_error(
2773+
"!!! CRITICAL WARNING: This action will PERMANENTLY DELETE ALL the above resources!\n"
2774+
"This includes ALL tables, views and schemas managed by SQLMesh AND potentially\n"
2775+
"external resources created by other tools in these schemas. This action is IRREVERSIBLE!\n"
2776+
)
2777+
2778+
if not self.console._confirm("Are you ABSOLUTELY SURE you want to proceed with deletion?"): # type: ignore
2779+
self.console.log_error("Destroy operation cancelled.")
2780+
return False
2781+
27092782
# Invalidate all environments, including prod
27102783
for environment in self.state_reader.get_environments():
27112784
self.state_sync.invalidate_environment(name=environment.name, protect_prod=False)
@@ -2721,6 +2794,8 @@ def _destroy(self) -> None:
27212794
# Finally clear caches
27222795
self.clear_caches()
27232796

2797+
return True
2798+
27242799
def _run_janitor(self, ignore_ttl: bool = False) -> None:
27252800
current_ts = now_timestamp()
27262801

tests/core/test_integration.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6281,7 +6281,9 @@ def test_destroy(copy_to_temp_path):
62816281
context.fetchdf(f"SELECT * FROM db_1.first_schema.model_two")
62826282

62836283
# Use the destroy command to remove all data objects and state
6284-
context._destroy()
6284+
# Mock the console confirmation to automatically return True
6285+
with patch.object(context.console, "_confirm", return_value=True):
6286+
context._destroy()
62856287

62866288
# Ensure all tables have been removed
62876289
for table_name in state_tables:

tests/integrations/jupyter/test_magics.py

Lines changed: 22 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -898,16 +898,32 @@ def test_destroy(
898898
assert not output.stderr
899899
text_output = convert_all_html_output_to_text(output)
900900
expected_messages = [
901-
"[WARNING] This will permanently delete all engine-managed objects, state tables and SQLMesh cache.\n"
902-
"The operation is irreversible and may disrupt any currently running or scheduled plans.\n"
903-
"Use this command only when you intend to fully reset the project.",
901+
(
902+
"!!! EXTREME CAUTION: DESTRUCTIVE OPERATION !!!\n\n"
903+
"The 'destroy' command will PERMANENTLY DELETE:\n"
904+
" • ALL state tables and metadata\n"
905+
" • ALL SQLMesh cache and build artifacts\n"
906+
" • ALL tables and views in the project's schemas/datasets\n"
907+
" • ALL schemas/datasets managed by SQLMesh in this project\n\n"
908+
"!!! WARNING: This includes external tables created or managed by other tools !!!\n\n"
909+
"The operation is irreversible and may disrupt any currently running or scheduled plans.\n"
910+
"Only use this command when you intend to COMPLETELY DESTROY the project."
911+
),
912+
"Do you understand the risks and want to see what will be deleted? [y/n]:",
913+
"Schemas to be deleted:",
914+
"• memory.sushi",
915+
"Snapshot tables to be deleted:",
916+
"All SQLMesh state tables will be deleted",
917+
(
918+
"!!! CRITICAL WARNING: This action will PERMANENTLY DELETE ALL the above resources!\n"
919+
"This includes ALL tables, views and schemas managed by SQLMesh AND potentially\n"
920+
"external resources created by other tools in these schemas. This action is IRREVERSIBLE!"
921+
),
922+
"Are you ABSOLUTELY SURE you want to proceed with deletion? [y/n]:",
904923
"Environment 'prod' invalidated.",
905924
"Deleted object memory.sushi",
906925
'Deleted object "memory"."raw"."model1"',
907-
'Deleted object "memory"."raw"."model1"',
908926
'Deleted object "memory"."raw"."model2"',
909-
'Deleted object "memory"."raw"."model2"',
910-
'Deleted object "memory"."raw"."demographics"',
911927
'Deleted object "memory"."raw"."demographics"',
912928
"State tables removed.",
913929
"Destroy completed successfully.",

0 commit comments

Comments
 (0)