1717CHECK_PREREQS_PS = PROJECT_ROOT / "scripts" / "powershell" / "check-prerequisites.ps1"
1818
1919HAS_PWSH = shutil .which ("pwsh" ) is not None
20- _WINDOWS_POWERSHELL = (shutil .which ("powershell.exe" ) or shutil .which ("powershell" )) if os .name == "nt" else None
20+ _WINDOWS_POWERSHELL = (
21+ (shutil .which ("powershell.exe" ) or shutil .which ("powershell" ))
22+ if os .name == "nt"
23+ else None
24+ )
2125
2226
2327def _install_bash_scripts (repo : Path ) -> None :
@@ -141,6 +145,41 @@ def test_paths_only_text_mode_on_non_spec_branch(prereq_repo: Path) -> None:
141145 assert "FEATURE_DIR:" in result .stdout
142146
143147
148+ @requires_bash
149+ def test_paths_only_does_not_overwrite_feature_json (prereq_repo : Path ) -> None :
150+ """--paths-only must not rewrite .specify/feature.json when env differs."""
151+ common = (prereq_repo / ".specify" / "scripts" / "bash" / "common.sh" ).read_text (
152+ encoding = "utf-8"
153+ )
154+ script_text = (
155+ prereq_repo / ".specify" / "scripts" / "bash" / "check-prerequisites.sh"
156+ ).read_text (encoding = "utf-8" )
157+ assert "SPECIFY_NO_PERSIST_FEATURE_JSON" not in common
158+ assert "get_feature_paths --no-persist" in script_text
159+
160+ feat = prereq_repo / "specs" / "001-my-feature"
161+ feat .mkdir (parents = True , exist_ok = True )
162+ _write_feature_json (prereq_repo )
163+ before = (prereq_repo / ".specify" / "feature.json" ).read_text (encoding = "utf-8" )
164+ script = prereq_repo / ".specify" / "scripts" / "bash" / "check-prerequisites.sh"
165+ env = _clean_env ()
166+ env ["SPECIFY_FEATURE_DIRECTORY" ] = "specs/999-temp"
167+ result = subprocess .run (
168+ ["bash" , str (script ), "--json" , "--paths-only" ],
169+ cwd = prereq_repo ,
170+ capture_output = True ,
171+ text = True ,
172+ check = False ,
173+ env = env ,
174+ )
175+ assert result .returncode == 0 , result .stderr
176+ assert (prereq_repo / ".specify" / "feature.json" ).read_text (
177+ encoding = "utf-8"
178+ ) == before
179+ data = json .loads (result .stdout )
180+ assert data ["FEATURE_DIR" ].endswith ("specs/999-temp" )
181+
182+
144183@requires_bash
145184def test_normal_mode_still_validates_branch (prereq_repo : Path ) -> None :
146185 """Without --paths-only, feature directory validation must still fail on main."""
@@ -160,13 +199,17 @@ def test_normal_mode_still_validates_branch(prereq_repo: Path) -> None:
160199# ── PowerShell tests ──────────────────────────────────────────────────────
161200
162201
163- @pytest .mark .skipif (not (HAS_PWSH or _WINDOWS_POWERSHELL ), reason = "no PowerShell available" )
202+ @pytest .mark .skipif (
203+ not (HAS_PWSH or _WINDOWS_POWERSHELL ), reason = "no PowerShell available"
204+ )
164205def test_ps_paths_only_succeeds_on_non_spec_branch (prereq_repo : Path ) -> None :
165206 """-PathsOnly must return paths when feature.json pins the feature dir."""
166207 feat = prereq_repo / "specs" / "001-my-feature"
167208 feat .mkdir (parents = True , exist_ok = True )
168209 _write_feature_json (prereq_repo )
169- script = prereq_repo / ".specify" / "scripts" / "powershell" / "check-prerequisites.ps1"
210+ script = (
211+ prereq_repo / ".specify" / "scripts" / "powershell" / "check-prerequisites.ps1"
212+ )
170213 exe = "pwsh" if HAS_PWSH else _WINDOWS_POWERSHELL
171214 result = subprocess .run (
172215 [exe , "-NoProfile" , "-File" , str (script ), "-Json" , "-PathsOnly" ],
@@ -183,7 +226,9 @@ def test_ps_paths_only_succeeds_on_non_spec_branch(prereq_repo: Path) -> None:
183226 assert "FEATURE_DIR" in data
184227
185228
186- @pytest .mark .skipif (not (HAS_PWSH or _WINDOWS_POWERSHELL ), reason = "no PowerShell available" )
229+ @pytest .mark .skipif (
230+ not (HAS_PWSH or _WINDOWS_POWERSHELL ), reason = "no PowerShell available"
231+ )
187232def test_ps_paths_only_succeeds_on_spec_branch (prereq_repo : Path ) -> None :
188233 """-PathsOnly must also work when feature.json and SPECIFY_FEATURE agree."""
189234 subprocess .run (
@@ -194,7 +239,9 @@ def test_ps_paths_only_succeeds_on_spec_branch(prereq_repo: Path) -> None:
194239 feat = prereq_repo / "specs" / "001-my-feature"
195240 feat .mkdir (parents = True , exist_ok = True )
196241 _write_feature_json (prereq_repo )
197- script = prereq_repo / ".specify" / "scripts" / "powershell" / "check-prerequisites.ps1"
242+ script = (
243+ prereq_repo / ".specify" / "scripts" / "powershell" / "check-prerequisites.ps1"
244+ )
198245 exe = "pwsh" if HAS_PWSH else _WINDOWS_POWERSHELL
199246 env = _clean_env ()
200247 env ["SPECIFY_FEATURE" ] = "001-my-feature"
@@ -211,10 +258,54 @@ def test_ps_paths_only_succeeds_on_spec_branch(prereq_repo: Path) -> None:
211258 assert "FEATURE_DIR" in data
212259
213260
214- @pytest .mark .skipif (not (HAS_PWSH or _WINDOWS_POWERSHELL ), reason = "no PowerShell available" )
261+ @pytest .mark .skipif (
262+ not (HAS_PWSH or _WINDOWS_POWERSHELL ), reason = "no PowerShell available"
263+ )
264+ def test_ps_paths_only_does_not_overwrite_feature_json (prereq_repo : Path ) -> None :
265+ """-PathsOnly must not rewrite .specify/feature.json when env differs."""
266+ common = (
267+ prereq_repo / ".specify" / "scripts" / "powershell" / "common.ps1"
268+ ).read_text (encoding = "utf-8" )
269+ script_text = (
270+ prereq_repo / ".specify" / "scripts" / "powershell" / "check-prerequisites.ps1"
271+ ).read_text (encoding = "utf-8" )
272+ assert "SPECIFY_NO_PERSIST_FEATURE_JSON" not in common
273+ assert "Get-FeaturePathsEnv -NoPersist" in script_text
274+
275+ feat = prereq_repo / "specs" / "001-my-feature"
276+ feat .mkdir (parents = True , exist_ok = True )
277+ _write_feature_json (prereq_repo )
278+ before = (prereq_repo / ".specify" / "feature.json" ).read_text (encoding = "utf-8" )
279+ script = (
280+ prereq_repo / ".specify" / "scripts" / "powershell" / "check-prerequisites.ps1"
281+ )
282+ exe = "pwsh" if HAS_PWSH else _WINDOWS_POWERSHELL
283+ env = _clean_env ()
284+ env ["SPECIFY_FEATURE_DIRECTORY" ] = "specs/999-temp"
285+ result = subprocess .run (
286+ [exe , "-NoProfile" , "-File" , str (script ), "-Json" , "-PathsOnly" ],
287+ cwd = prereq_repo ,
288+ capture_output = True ,
289+ text = True ,
290+ check = False ,
291+ env = env ,
292+ )
293+ assert result .returncode == 0 , result .stderr
294+ assert (prereq_repo / ".specify" / "feature.json" ).read_text (
295+ encoding = "utf-8"
296+ ) == before
297+ data = json .loads (result .stdout )
298+ assert data ["FEATURE_DIR" ].replace ("\\ " , "/" ).endswith ("specs/999-temp" )
299+
300+
301+ @pytest .mark .skipif (
302+ not (HAS_PWSH or _WINDOWS_POWERSHELL ), reason = "no PowerShell available"
303+ )
215304def test_ps_normal_mode_still_validates_branch (prereq_repo : Path ) -> None :
216305 """Without -PathsOnly, feature directory validation must still fail on main."""
217- script = prereq_repo / ".specify" / "scripts" / "powershell" / "check-prerequisites.ps1"
306+ script = (
307+ prereq_repo / ".specify" / "scripts" / "powershell" / "check-prerequisites.ps1"
308+ )
218309 exe = "pwsh" if HAS_PWSH else _WINDOWS_POWERSHELL
219310 result = subprocess .run (
220311 [exe , "-NoProfile" , "-File" , str (script ), "-Json" ],
0 commit comments