Skip to content

Commit be10cdf

Browse files
committed
fix(presets): clean up a deleted standalone override's stale script
reconcile_all_script_chains()'s worklist was built from script names a preset manifest declares plus override files currently on disk. A deleted standalone override's name drops out of that scan entirely, so the stale canonical script it left behind survives even an explicit reconcile call forever -- nothing ever learns the name needs re-checking again. Also fold in every name with a provenance sidecar (recorded the last time this manager generated a canonical script for it), not only names still declared somewhere today. _reconcile_script_chain() already restores-to-core or removes a name nothing provides any more, and already preserves a canonical file the user edited after the fact via the same provenance hash check -- this just makes sure a deleted override's name actually reaches that logic again. Assisted-by: Claude Code (model: Claude Sonnet 5, autonomous)
1 parent d1b55df commit be10cdf

2 files changed

Lines changed: 49 additions & 0 deletions

File tree

‎src/specify_cli/presets/_manager.py‎

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -973,6 +973,19 @@ def reconcile_all_script_chains(self) -> None:
973973
self-materialize: a project-local override added directly to the
974974
filesystem outside any lifecycle command still needs this called
975975
explicitly.
976+
977+
A *deleted* standalone override is the same situation from the
978+
other side: once the override file is gone, scanning the overrides
979+
directory alone can never find its name again, so the stale
980+
canonical script it left behind -- generated while the override
981+
still existed -- would survive even this explicit call forever
982+
(#4709 review). Every name with provenance metadata (recorded the
983+
last time this manager generated a canonical script for it) is
984+
reconciled too, not only names still declared somewhere today;
985+
``_reconcile_script_chain`` already restores-to-core or cleans up
986+
a name nothing provides any more, and already preserves a
987+
canonical file the user edited after the fact via the same
988+
provenance hash check.
976989
"""
977990
script_names: Set[str] = set()
978991
for pack_id, _metadata in self.registry.list_by_priority():
@@ -994,6 +1007,12 @@ def reconcile_all_script_chains(self) -> None:
9941007
override_file.stem
9951008
for override_file in overrides_scripts_dir.glob("*.sh")
9961009
)
1010+
scripts_dir = self.project_root / ".specify" / "scripts" / "bash"
1011+
if scripts_dir.is_dir():
1012+
script_names.update(
1013+
provenance_file.name[: -len(_SCRIPT_PROVENANCE_SUFFIX)]
1014+
for provenance_file in scripts_dir.glob(f"*{_SCRIPT_PROVENANCE_SUFFIX}")
1015+
)
9971016
for script_name in script_names:
9981017
try:
9991018
self._reconcile_script_chain(script_name)

‎tests/specify_cli/presets/test_manager.py‎

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2089,6 +2089,36 @@ def test_reconcile_all_script_chains_covers_standalone_override(
20892089
chain = PresetResolver(project_dir).resolve_script_chain("setup-plan")
20902090
assert [p.read_text() for p in chain] == ["echo overridden\n"]
20912091

2092+
def test_reconcile_all_script_chains_cleans_up_deleted_standalone_override(
2093+
self, project_dir
2094+
):
2095+
"""A deleted standalone override's script name drops out of the
2096+
overrides-directory scan entirely, so scanning that directory alone
2097+
can never find it again to clean up the stale canonical script it
2098+
left behind -- even on an explicit reconcile_all_script_chains()
2099+
call (#4709 review). Provenance metadata recorded when this manager
2100+
generated the canonical script must be consulted too, not just
2101+
names still declared somewhere today."""
2102+
override_dir = (
2103+
project_dir / ".specify" / "templates" / "overrides" / "scripts"
2104+
)
2105+
override_dir.mkdir(parents=True, exist_ok=True)
2106+
(override_dir / "deleted-override-script.sh").write_text("echo overridden\n")
2107+
2108+
manager = PresetManager(project_dir)
2109+
manager.reconcile_all_script_chains()
2110+
2111+
canonical = self._canonical(project_dir, "deleted-override-script")
2112+
assert canonical.read_text() == "echo overridden\n"
2113+
2114+
(override_dir / "deleted-override-script.sh").unlink()
2115+
manager.reconcile_all_script_chains()
2116+
2117+
# No core/bundled fallback exists for this name either, so the
2118+
# stale canonical file (and its provenance sidecar) must be
2119+
# removed entirely, not merely left with its old content.
2120+
assert not canonical.exists()
2121+
20922122
def test_enable_disable_and_set_priority_rematerialize_scripts(
20932123
self, project_dir, temp_dir, valid_pack_data
20942124
):

0 commit comments

Comments
 (0)