Skip to content

Commit 1a4b96c

Browse files
feat(cli): Add feast projects delete command (closes #5095) (#6318)
* feat(cli): Add `feast projects delete` command (closes #5095) Exposes project deletion via the CLI. The new `feast projects delete <name>` command calls store.registry.delete_project() which is already implemented in all concrete registries. - Adds interactive confirmation prompt with --yes/-y flag for scripting - Catches both FeastObjectNotFoundException and ProjectNotFoundException - Exits with code 1 for non-existent projects Signed-off-by: Venkateswarlu Boggavarapu <mailtoboggavarapu@gmail.com> * fix(cli): align project_list and project_current with master implementation Addresses Devin Review findings: - Fix project_list: use utils.tags_list_to_dict() instead of manual tag.split(), and print tabulated output matching master - Fix project_current: call store.get_project(name=None) with error handling instead of store.project Both functions now match master branch exactly. Only project_delete is new code from this PR. Signed-off-by: Venkateswarlu Boggavarapu <mailtoboggavarapu@gmail.com> * refactor(cli): use store.delete_project() instead of registry directly Refactor project listing and deletion commands in CLI. * feat(cli): add delete_project method to FeatureStore Added a method to delete a project from the registry. * fix(store): fix list_saved_datasets indentation in feature_store.py --------- Signed-off-by: Venkateswarlu Boggavarapu <mailtoboggavarapu@gmail.com>
1 parent 50ad181 commit 1a4b96c

2 files changed

Lines changed: 55 additions & 9 deletions

File tree

sdk/python/feast/cli/projects.py

Lines changed: 42 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33

44
from feast import utils
55
from feast.cli.cli_options import tagsOption
6-
from feast.errors import FeastObjectNotFoundException
6+
from feast.errors import FeastObjectNotFoundException, ProjectNotFoundException
77
from feast.repo_operations import create_feature_store
88

99

@@ -23,16 +23,16 @@ def project_describe(ctx: click.Context, name: str):
2323
Describe a project
2424
"""
2525
store = create_feature_store(ctx)
26-
2726
try:
2827
project = store.get_project(name)
2928
except FeastObjectNotFoundException as e:
3029
print(e)
3130
exit(1)
32-
3331
print(
3432
yaml.dump(
35-
yaml.safe_load(str(project)), default_flow_style=False, sort_keys=False
33+
yaml.safe_load(str(project)),
34+
default_flow_style=False,
35+
sort_keys=False,
3636
)
3737
)
3838

@@ -44,20 +44,52 @@ def project_current(ctx: click.Context):
4444
Returns the current project configured with FeatureStore object
4545
"""
4646
store = create_feature_store(ctx)
47-
4847
try:
4948
project = store.get_project(name=None)
5049
except FeastObjectNotFoundException as e:
5150
print(e)
5251
exit(1)
53-
5452
print(
5553
yaml.dump(
56-
yaml.safe_load(str(project)), default_flow_style=False, sort_keys=False
54+
yaml.safe_load(str(project)),
55+
default_flow_style=False,
56+
sort_keys=False,
5757
)
5858
)
5959

6060

61+
@projects_cmd.command("delete")
62+
@click.argument("name", type=click.STRING)
63+
@click.option(
64+
"-y",
65+
"--yes",
66+
is_flag=True,
67+
default=False,
68+
help="Skip confirmation prompt and delete immediately.",
69+
)
70+
@click.pass_context
71+
def project_delete(ctx: click.Context, name: str, yes: bool):
72+
"""
73+
Delete a project and all its resources from the registry.
74+
"""
75+
store = create_feature_store(ctx)
76+
77+
if not yes:
78+
click.confirm(
79+
f"Are you sure you want to delete project '{name}'? "
80+
"This will remove all associated resources from the registry.",
81+
abort=True,
82+
)
83+
84+
try:
85+
store.delete_project(name)
86+
except (FeastObjectNotFoundException, ProjectNotFoundException) as e:
87+
print(str(e))
88+
raise SystemExit(1)
89+
90+
print(f"Project '{name}' deleted successfully.")
91+
92+
6193
@projects_cmd.command(name="list")
6294
@tagsOption
6395
@click.pass_context
@@ -70,11 +102,12 @@ def project_list(ctx: click.Context, tags: list[str]):
70102
tags_filter = utils.tags_list_to_dict(tags)
71103
for project in store.list_projects(tags=tags_filter):
72104
table.append([project.name, project.description, project.tags, project.owner])
73-
74105
from tabulate import tabulate
75106

76107
print(
77108
tabulate(
78-
table, headers=["NAME", "DESCRIPTION", "TAGS", "OWNER"], tablefmt="plain"
109+
table,
110+
headers=["NAME", "DESCRIPTION", "TAGS", "OWNER"],
111+
tablefmt="plain",
79112
)
80113
)

sdk/python/feast/feature_store.py

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3401,6 +3401,19 @@ def get_project(self, name: Optional[str]) -> Project:
34013401
"""
34023402
return self.registry.get_project(name or self.project)
34033403

3404+
def delete_project(self, name: str, commit: bool = True) -> None:
3405+
"""
3406+
Deletes a project from the registry.
3407+
3408+
Args:
3409+
name: Name of the project to delete.
3410+
commit: Whether the change should be persisted immediately.
3411+
3412+
Raises:
3413+
ProjectNotFoundException: The project could not be found.
3414+
"""
3415+
return self.registry.delete_project(name, commit=commit)
3416+
34043417
def list_saved_datasets(
34053418
self, allow_cache: bool = False, tags: Optional[dict[str, str]] = None
34063419
) -> List[SavedDataset]:

0 commit comments

Comments
 (0)