mirror of
https://github.com/github/spec-kit.git
synced 2026-08-03 06:26:30 +08:00
fix(scripts): tolerate an unusable integration.json in the Python helper (#3785)
* fix(scripts): tolerate an unusable integration.json in the Python helper
`get_invoke_separator()` in scripts/python/common.py indexed the parsed JSON
directly, so two shapes escaped its `except (OSError, json.JSONDecodeError)`
while BOTH of its twins fall back to "." for them:
* A non-mapping top level is valid JSON, so JSONDecodeError never fires and
`state.get(...)` raised AttributeError.
* A non-UTF-8 file raises UnicodeDecodeError -- a ValueError, not an OSError.
Realistic on Windows, where PowerShell 5.1's Out-File/`>` default to UTF-16.
Measured on main -- 6 of 7 inputs crashed the Python helper while bash and
PowerShell 5.1 returned "." for every one:
input python bash pwsh 5.1
{"default_integration":"forge"} '.' . .
[] AttributeError . .
"forge" AttributeError . .
42 AttributeError . .
null AttributeError . .
UTF-16 file UnicodeDecodeError . .
Split the parse out of the lookup, complete the exception tuple, and guard the
top-level shape -- matching `read_feature_json_feature_directory` in this same
module, which already does exactly this. The hyphen-separator feature is
unchanged (regression test included).
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* docs(scripts): point the parity comment at the sibling above, not below
read_feature_json_feature_directory is defined at line 81, above
get_invoke_separator, so "below" sent maintainers the wrong way.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -258,16 +258,27 @@ def get_invoke_separator(repo_root: Path) -> str:
|
||||
integration_json = repo_root / ".specify" / "integration.json"
|
||||
if not integration_json.is_file():
|
||||
return "."
|
||||
# Split the parse out of the lookup and guard the top-level shape, matching
|
||||
# read_feature_json_feature_directory above and the bash/PowerShell twins,
|
||||
# which both fall back to "." for any unusable integration.json:
|
||||
# * a non-mapping top level ([], "forge", 42, null) is valid JSON, so
|
||||
# json.JSONDecodeError never fires and state.get(...) raised
|
||||
# AttributeError;
|
||||
# * a non-UTF-8 file raises UnicodeDecodeError, which is a ValueError --
|
||||
# not an OSError -- so it escaped the except tuple. Realistic on
|
||||
# Windows, where PowerShell 5.1's Out-File/`>` default to UTF-16.
|
||||
try:
|
||||
state = json.loads(integration_json.read_text(encoding="utf-8"))
|
||||
key = state.get("default_integration") or state.get("integration") or ""
|
||||
settings = state.get("integration_settings")
|
||||
if isinstance(key, str) and isinstance(settings, dict):
|
||||
entry = settings.get(key)
|
||||
if isinstance(entry, dict) and entry.get("invoke_separator") in {".", "-"}:
|
||||
return entry["invoke_separator"]
|
||||
except (OSError, json.JSONDecodeError):
|
||||
pass
|
||||
except (OSError, UnicodeError, json.JSONDecodeError):
|
||||
return "."
|
||||
if not isinstance(state, dict):
|
||||
return "."
|
||||
key = state.get("default_integration") or state.get("integration") or ""
|
||||
settings = state.get("integration_settings")
|
||||
if isinstance(key, str) and isinstance(settings, dict):
|
||||
entry = settings.get(key)
|
||||
if isinstance(entry, dict) and entry.get("invoke_separator") in {".", "-"}:
|
||||
return entry["invoke_separator"]
|
||||
return "."
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user