mirror of
https://github.com/github/spec-kit.git
synced 2026-07-03 12:28:06 +08:00
refactor: create commands/ package and move init handler (PR-4/8) (#2615)
* refactor: create commands/ package and move init handler (PR-4/8) - Extract agent configuration constants (AGENT_CONFIG, AI_ASSISTANT_HELP, SCRIPT_TYPE_CHOICES, etc.) to _agent_config.py to avoid circular imports - Create commands/ package skeleton with stub modules for each command group - Move init command handler (~670 lines) from __init__.py to commands/init.py using the register(app) pattern; lazy imports inside the handler body prevent circular dependencies with __init__.py - Re-export AGENT_CONFIG, AI_ASSISTANT_HELP, SCRIPT_TYPE_CHOICES from __init__.py for backward compatibility - Add tests/test_commands_package.py to verify package structure * fix(tests): update patch targets after moving init handler to commands/init.py _stdin_is_interactive and select_with_arrows are now bound in specify_cli.commands.init, not specify_cli directly. * fix(lint): remove unused imports and mark re-exports in __init__.py - Remove shutil, shlex top-level imports (used lazily inside functions) - Remove rich.live.Live import (moved to commands/init.py) - Mark select_with_arrows and _locate_bundled_workflow as explicit re-exports to satisfy ruff F401 * chore: add from __future__ import annotations to new modules Aligns with the project convention established in _console.py, _assets.py, _utils.py, and other modules. * docs(cli): align init help with bundled scaffolding Potential fix for pull request finding Update command package documentation and init help text to reflect the current implementation: init uses bundled assets and integration setup, while placeholder command modules are import anchors until extracted. Remove the unused tracker-active flag assignment that had no reader in the codebase. Constraint: --offline is hidden/no-op and init no longer downloads templates from GitHub releases Rejected: Add no-op register functions to placeholder modules | would imply extracted command groups are implemented there Confidence: high Scope-risk: narrow Directive: Keep CLI help text aligned with the actual init scaffolding path Tested: uv run specify init --help; uv run pytest tests/test_commands_package.py tests/test_agent_config_consistency.py -q; uv run pytest tests/test_commands_package.py tests/test_console_imports.py tests/integrations/test_cli.py -q Not-tested: full test suite * fix(init): align preset failure reporting with _print_cli_warning helper Use the _print_cli_warning helper (introduced in main) for preset install failures so that output matches the expected format: "Failed to install preset '<name>': ..." "Continuing without the optional preset." * fix(init): remove unused lazy imports The init command imported CLI error formatting helpers through its circular-dependency-safe lazy import block, but the module does not use them. Remove those imports so ruff does not report F401. Constraint: uvx ruff check src/ must pass. Rejected: Wire the helpers into init error handling | Existing preset warnings already use _print_cli_warning, and changing behavior is unnecessary for this lint fix. Confidence: high Scope-risk: narrow Directive: Keep lazy import blocks limited to names consumed in the importing module. Tested: uvx ruff check src/ Not-tested: Full pytest suite Co-authored-by: OmX <omx@oh-my-codex.dev> --------- Co-authored-by: OmX <omx@oh-my-codex.dev>
This commit is contained in:
48
tests/test_commands_package.py
Normal file
48
tests/test_commands_package.py
Normal file
@@ -0,0 +1,48 @@
|
||||
"""Tests for the commands/ package structure."""
|
||||
import importlib
|
||||
|
||||
|
||||
def test_commands_package_importable():
|
||||
mod = importlib.import_module("specify_cli.commands")
|
||||
assert mod is not None
|
||||
|
||||
|
||||
def test_commands_init_importable():
|
||||
mod = importlib.import_module("specify_cli.commands.init")
|
||||
assert hasattr(mod, "register")
|
||||
assert callable(mod.register)
|
||||
|
||||
|
||||
def test_commands_stubs_importable():
|
||||
for name in ("integration", "preset", "extension", "workflow"):
|
||||
mod = importlib.import_module(f"specify_cli.commands.{name}")
|
||||
assert mod is not None
|
||||
|
||||
|
||||
def test_agent_config_importable():
|
||||
from specify_cli._agent_config import (
|
||||
AGENT_CONFIG,
|
||||
AI_ASSISTANT_ALIASES,
|
||||
AI_ASSISTANT_HELP,
|
||||
DEFAULT_INIT_INTEGRATION,
|
||||
SCRIPT_TYPE_CHOICES,
|
||||
)
|
||||
assert isinstance(AGENT_CONFIG, dict)
|
||||
assert isinstance(AI_ASSISTANT_ALIASES, dict)
|
||||
assert isinstance(AI_ASSISTANT_HELP, str)
|
||||
assert DEFAULT_INIT_INTEGRATION == "copilot"
|
||||
assert "sh" in SCRIPT_TYPE_CHOICES
|
||||
|
||||
|
||||
def test_agent_config_re_exported_from_init():
|
||||
from specify_cli import AGENT_CONFIG, AI_ASSISTANT_ALIASES, AI_ASSISTANT_HELP, SCRIPT_TYPE_CHOICES
|
||||
assert isinstance(AGENT_CONFIG, dict)
|
||||
assert "sh" in SCRIPT_TYPE_CHOICES
|
||||
|
||||
|
||||
def test_init_command_registered():
|
||||
from specify_cli import app
|
||||
callback_names = [
|
||||
cmd.callback.__name__ for cmd in app.registered_commands if cmd.callback
|
||||
]
|
||||
assert "init" in callback_names
|
||||
Reference in New Issue
Block a user