Skip to content

Commit 96e6615

Browse files
Chore: Show resources to be deleted and enhance warnings in destroy
1 parent 4ee6cb3 commit 96e6615

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
@@ -1283,14 +1283,20 @@ def stop_cleanup(self, success: bool = False) -> None:
12831283
self.log_error("Cleanup failed!")
12841284

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

sqlmesh/core/context.py

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

861861
if self.console.start_destroy():
862862
try:
863-
self._destroy()
864-
success = True
863+
success = self._destroy()
865864
finally:
866865
self.console.stop_destroy(success=success)
867866

@@ -2723,7 +2722,81 @@ def _context_diff(
27232722
always_recreate_environment=always_recreate_environment,
27242723
)
27252724

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

2815+
return True
2816+
27422817
def _run_janitor(self, ignore_ttl: bool = False) -> None:
27432818
current_ts = now_timestamp()
27442819

tests/core/test_integration.py

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

63566356
# Use the destroy command to remove all data objects and state
6357-
context._destroy()
6357+
# Mock the console confirmation to automatically return True
6358+
with patch.object(context.console, "_confirm", return_value=True):
6359+
context._destroy()
63586360

63596361
# Ensure all tables have been removed
63606362
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)