mirror of
https://github.com/github/spec-kit.git
synced 2026-07-03 12:28:06 +08:00
* support controlled multi-install integrations * fix: harden multi-install integration state * refactor: isolate integration runtime helpers * fix: address copilot review feedback * fix: address follow-up copilot feedback * fix: tighten integration switch semantics * fix: address final copilot review feedback * fix: harden integration manifest read errors * fix: refuse symlinked shared infra paths * test: filter expected self-test preset warning * test: address copilot review nits * refactor: centralize safe shared infra writes * fix: use no-follow writes for shared infra * fix: keep default integration atomic on template refresh * fix: harden shared infra error paths * fix: preflight shared infra and future state schemas * fix: support nested shared scripts during preflight * test: tolerate wrapped schema error output * fix: use safe default mode for shared text writes * fix: use posix paths in shared skip output * fix: share project guard for integration use * fix: centralize spec-kit project guards * fix: use posix project paths in cli output * fix: harden shared manifest and upgrade refresh
91 lines
2.7 KiB
Python
91 lines
2.7 KiB
Python
"""Runtime helpers for integration commands."""
|
|
|
|
from __future__ import annotations
|
|
|
|
from collections.abc import Callable
|
|
from typing import Any
|
|
|
|
from .integration_state import integration_setting, integration_settings
|
|
|
|
|
|
ParseOptions = Callable[[Any, str], dict[str, Any] | None]
|
|
|
|
|
|
def resolve_integration_options(
|
|
integration: Any,
|
|
state: dict[str, Any],
|
|
key: str,
|
|
raw_options: str | None,
|
|
*,
|
|
parse_options: ParseOptions,
|
|
) -> tuple[str | None, dict[str, Any] | None]:
|
|
"""Resolve raw and parsed options for an integration operation."""
|
|
if raw_options is not None:
|
|
return raw_options, parse_options(integration, raw_options)
|
|
|
|
setting = integration_setting(state, key)
|
|
stored_raw = setting.get("raw_options")
|
|
if not isinstance(stored_raw, str):
|
|
stored_raw = None
|
|
|
|
stored_parsed = setting.get("parsed_options")
|
|
if isinstance(stored_parsed, dict):
|
|
return stored_raw, stored_parsed or None
|
|
|
|
if stored_raw:
|
|
return stored_raw, parse_options(integration, stored_raw)
|
|
|
|
return None, None
|
|
|
|
|
|
def with_integration_setting(
|
|
state: dict[str, Any],
|
|
key: str,
|
|
integration: Any,
|
|
*,
|
|
script_type: str | None = None,
|
|
raw_options: str | None = None,
|
|
parsed_options: dict[str, Any] | None = None,
|
|
) -> dict[str, dict[str, Any]]:
|
|
"""Return integration settings with *key* updated."""
|
|
settings = integration_settings(state)
|
|
current = dict(settings.get(key, {}))
|
|
|
|
if script_type:
|
|
current["script"] = script_type
|
|
if raw_options is not None:
|
|
current["raw_options"] = raw_options
|
|
elif "raw_options" in current and not current.get("raw_options"):
|
|
current.pop("raw_options", None)
|
|
|
|
if parsed_options is not None:
|
|
current["parsed_options"] = parsed_options
|
|
elif raw_options is not None:
|
|
current.pop("parsed_options", None)
|
|
|
|
current["invoke_separator"] = integration.effective_invoke_separator(parsed_options)
|
|
settings[key] = current
|
|
return settings
|
|
|
|
|
|
def invoke_separator_for_integration(
|
|
integration: Any,
|
|
state: dict[str, Any],
|
|
key: str,
|
|
parsed_options: dict[str, Any] | None = None,
|
|
) -> str:
|
|
"""Resolve the invocation separator for stored/default integration state."""
|
|
if parsed_options is not None:
|
|
return integration.effective_invoke_separator(parsed_options)
|
|
|
|
setting = integration_setting(state, key)
|
|
stored_separator = setting.get("invoke_separator")
|
|
if isinstance(stored_separator, str) and stored_separator:
|
|
return stored_separator
|
|
|
|
stored_parsed = setting.get("parsed_options")
|
|
if isinstance(stored_parsed, dict):
|
|
return integration.effective_invoke_separator(stored_parsed)
|
|
|
|
return integration.effective_invoke_separator(None)
|