Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions src/specify_cli/bundles/command_init.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,13 @@ def bundle_init(
try:
project_root = find_project_root()
if project_root is None:
if bundle:
# Install resolves and validates the manifest before initializing,
# including the bundle-declared integration.
bundle_install(
bundle, integration=integration, offline=offline, refresh=False
)
return
init_integration = _resolve_init_integration(integration, None)
console.print(
f"[cyan]Initializing a Spec Kit project with integration "
Expand Down
47 changes: 44 additions & 3 deletions tests/specify_cli/bundles/test_command_init.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
from __future__ import annotations

import json
from pathlib import Path
from unittest.mock import Mock

Expand All @@ -8,12 +9,47 @@
from typer.testing import CliRunner

from specify_cli import app
from tests.specify_cli.bundles.helpers import write_manifest
from tests.specify_cli.bundles.helpers import valid_manifest_dict, write_manifest

runner = CliRunner()
REPO_ROOT = Path(__file__).parents[3]


def test_bundle_init_uses_declared_integration_in_new_project(tmp_path, monkeypatch):
bundle = write_manifest(
tmp_path / "claude-bundle",
valid_manifest_dict(provides={}, integration={"id": "claude"}),
)
project = tmp_path / "project"
project.mkdir()
monkeypatch.chdir(project)

result = runner.invoke(app, ["bundle", "init", str(bundle), "--offline"])

assert result.exit_code == 0, result.output
state = json.loads((project / ".specify/integration.json").read_text())
assert state["default_integration"] == "claude"
assert (project / ".specify/bundle-records.json").is_file()


def test_bundle_init_rejects_incompatible_bundle_before_initializing(
tmp_path,
monkeypatch,
):
bundle = write_manifest(
tmp_path / "incompatible-bundle",
valid_manifest_dict(provides={}, requires={"speckit_version": ">=9999.0.0"}),
)
project = tmp_path / "project"
project.mkdir()
monkeypatch.chdir(project)

result = runner.invoke(app, ["bundle", "init", str(bundle), "--offline"])

assert result.exit_code == 1, result.output
assert not (project / ".specify").exists()
Comment on lines +49 to +50


def _make_project(tmp_path: Path, name: str) -> Path:
project = tmp_path / name
(project / ".specify").mkdir(parents=True)
Expand All @@ -33,7 +69,10 @@ def test_bundle_init_delegates_without_refresh(project, monkeypatch, bundle):
install.assert_not_called()
else:
install.assert_called_once_with(
bundle, integration=None, offline=True, refresh=False,
bundle,
integration=None,
offline=True,
refresh=False,
)


Expand All @@ -42,7 +81,9 @@ def test_bundle_init_delegates_without_refresh(project, monkeypatch, bundle):
[("init", False), ("install", False), ("install", True)],
)
def test_bundle_init_preserves_workflow_unless_explicitly_refreshed(
project, command, refresh,
project,
command,
refresh,
):
bundle = REPO_ROOT / "bundles" / "bugfix"
initial = runner.invoke(app, ["bundle", "init", str(bundle), "--offline"])
Expand Down
Loading