chore: import upstream snapshot with attribution
This commit is contained in:
@@ -0,0 +1,199 @@
|
||||
"""Tests for OpencodeIntegration."""
|
||||
|
||||
import warnings
|
||||
|
||||
from specify_cli.agents import CommandRegistrar
|
||||
from specify_cli.integrations import get_integration
|
||||
from specify_cli.integrations.manifest import IntegrationManifest
|
||||
|
||||
from .test_integration_base_markdown import MarkdownIntegrationTests
|
||||
|
||||
|
||||
class TestOpencodeIntegration(MarkdownIntegrationTests):
|
||||
KEY = "opencode"
|
||||
FOLDER = ".opencode/"
|
||||
COMMANDS_SUBDIR = "commands"
|
||||
REGISTRAR_DIR = ".opencode/commands"
|
||||
|
||||
def test_build_exec_args_uses_run_command_dispatch(self):
|
||||
integration = get_integration(self.KEY)
|
||||
|
||||
args = integration.build_exec_args(
|
||||
"/speckit.specify build a login page",
|
||||
output_json=False,
|
||||
)
|
||||
|
||||
assert args == [
|
||||
"opencode",
|
||||
"run",
|
||||
"--command",
|
||||
"speckit.specify",
|
||||
"build a login page",
|
||||
]
|
||||
assert "-p" not in args
|
||||
assert "--output-format" not in args
|
||||
|
||||
def test_build_exec_args_maps_model_and_json_flags(self):
|
||||
integration = get_integration(self.KEY)
|
||||
|
||||
args = integration.build_exec_args(
|
||||
"/speckit.plan add OAuth",
|
||||
model="anthropic/claude-sonnet-4",
|
||||
output_json=True,
|
||||
)
|
||||
|
||||
assert args == [
|
||||
"opencode",
|
||||
"run",
|
||||
"--command",
|
||||
"speckit.plan",
|
||||
"-m",
|
||||
"anthropic/claude-sonnet-4",
|
||||
"--format",
|
||||
"json",
|
||||
"add OAuth",
|
||||
]
|
||||
|
||||
def test_build_exec_args_keeps_plain_prompt_dispatch(self):
|
||||
integration = get_integration(self.KEY)
|
||||
|
||||
args = integration.build_exec_args("explain this repository", output_json=False)
|
||||
|
||||
assert args == ["opencode", "run", "explain this repository"]
|
||||
|
||||
def test_registrar_config_has_legacy_dir(self):
|
||||
integration = get_integration(self.KEY)
|
||||
assert integration.registrar_config["legacy_dir"] == ".opencode/command"
|
||||
|
||||
def test_legacy_dir_extension_registration(self, tmp_path):
|
||||
"""Extensions register in legacy .opencode/command/ with a warning."""
|
||||
# Seed a legacy project with only .opencode/command/
|
||||
legacy_dir = tmp_path / ".opencode" / "command"
|
||||
legacy_dir.mkdir(parents=True)
|
||||
(legacy_dir / "speckit.specify.md").write_text("# existing", encoding="utf-8")
|
||||
|
||||
# Create a source command file for the registrar
|
||||
src_dir = tmp_path / "_ext_src"
|
||||
src_dir.mkdir()
|
||||
(src_dir / "myext.md").write_text(
|
||||
"---\ndescription: test\n---\n# ext command", encoding="utf-8",
|
||||
)
|
||||
|
||||
registrar = CommandRegistrar()
|
||||
commands = [{"name": "speckit.myext", "file": "myext.md"}]
|
||||
|
||||
with warnings.catch_warnings(record=True) as caught:
|
||||
warnings.simplefilter("always")
|
||||
results = registrar.register_commands_for_all_agents(
|
||||
commands, "test-ext", src_dir, tmp_path,
|
||||
)
|
||||
|
||||
# Should have registered in the legacy directory
|
||||
assert "opencode" in results
|
||||
assert (legacy_dir / "speckit.myext.md").exists()
|
||||
# Canonical directory should NOT have been created
|
||||
assert not (tmp_path / ".opencode" / "commands").exists()
|
||||
# Should have emitted a deprecation warning
|
||||
opencode_warnings = [
|
||||
w for w in caught
|
||||
if "legacy" in str(w.message) and "opencode" in str(w.message)
|
||||
]
|
||||
assert len(opencode_warnings) == 1, (
|
||||
f"Expected exactly 1 legacy-dir warning, got {len(opencode_warnings)}"
|
||||
)
|
||||
assert "specify integration upgrade" in str(opencode_warnings[0].message)
|
||||
|
||||
def test_legacy_dir_unregister(self, tmp_path):
|
||||
"""Unregister finds commands in legacy .opencode/command/ dir."""
|
||||
legacy_dir = tmp_path / ".opencode" / "command"
|
||||
legacy_dir.mkdir(parents=True)
|
||||
cmd_file = legacy_dir / "speckit.myext.md"
|
||||
cmd_file.write_text("# ext command", encoding="utf-8")
|
||||
|
||||
registrar = CommandRegistrar()
|
||||
|
||||
with warnings.catch_warnings(record=True):
|
||||
warnings.simplefilter("always")
|
||||
registrar.unregister_commands(
|
||||
{"opencode": ["speckit.myext"]}, tmp_path,
|
||||
)
|
||||
|
||||
assert not cmd_file.exists()
|
||||
|
||||
def test_unregister_cleans_legacy_when_both_dirs_exist(self, tmp_path):
|
||||
"""Unregister removes files from legacy dir even when canonical exists."""
|
||||
# Set up both canonical and legacy dirs
|
||||
canonical_dir = tmp_path / ".opencode" / "commands"
|
||||
canonical_dir.mkdir(parents=True)
|
||||
legacy_dir = tmp_path / ".opencode" / "command"
|
||||
legacy_dir.mkdir(parents=True)
|
||||
|
||||
# Place a command file in the legacy dir (orphaned after upgrade)
|
||||
legacy_cmd = legacy_dir / "speckit.myext.md"
|
||||
legacy_cmd.write_text("# orphaned ext command", encoding="utf-8")
|
||||
# Place the same command in the canonical dir (current)
|
||||
canonical_cmd = canonical_dir / "speckit.myext.md"
|
||||
canonical_cmd.write_text("# ext command", encoding="utf-8")
|
||||
|
||||
registrar = CommandRegistrar()
|
||||
|
||||
with warnings.catch_warnings(record=True):
|
||||
warnings.simplefilter("always")
|
||||
registrar.unregister_commands(
|
||||
{"opencode": ["speckit.myext"]}, tmp_path,
|
||||
)
|
||||
|
||||
# Both files should be removed
|
||||
assert not canonical_cmd.exists(), (
|
||||
"Command file in canonical dir should be removed"
|
||||
)
|
||||
assert not legacy_cmd.exists(), (
|
||||
"Orphaned command file in legacy dir should also be removed"
|
||||
)
|
||||
|
||||
def test_canonical_dir_preferred_over_legacy(self, tmp_path):
|
||||
"""When both dirs exist, canonical .opencode/commands/ is used."""
|
||||
legacy_dir = tmp_path / ".opencode" / "command"
|
||||
legacy_dir.mkdir(parents=True)
|
||||
canonical_dir = tmp_path / ".opencode" / "commands"
|
||||
canonical_dir.mkdir(parents=True)
|
||||
(canonical_dir / "speckit.specify.md").write_text("# cmd", encoding="utf-8")
|
||||
|
||||
# Create a source command file for the registrar
|
||||
src_dir = tmp_path / "_ext_src"
|
||||
src_dir.mkdir()
|
||||
(src_dir / "myext.md").write_text(
|
||||
"---\ndescription: test\n---\n# ext command", encoding="utf-8",
|
||||
)
|
||||
|
||||
registrar = CommandRegistrar()
|
||||
commands = [{"name": "speckit.myext", "file": "myext.md"}]
|
||||
|
||||
with warnings.catch_warnings(record=True) as caught:
|
||||
warnings.simplefilter("always")
|
||||
results = registrar.register_commands_for_all_agents(
|
||||
commands, "test-ext", src_dir, tmp_path,
|
||||
)
|
||||
|
||||
# Should register in canonical dir, not legacy
|
||||
assert "opencode" in results
|
||||
assert (canonical_dir / "speckit.myext.md").exists()
|
||||
assert not (legacy_dir / "speckit.myext.md").exists()
|
||||
# No legacy warning when canonical dir exists
|
||||
opencode_warnings = [
|
||||
w for w in caught
|
||||
if "legacy" in str(w.message) and "opencode" in str(w.message)
|
||||
]
|
||||
assert len(opencode_warnings) == 0
|
||||
|
||||
def test_setup_writes_to_canonical_dir(self, tmp_path):
|
||||
"""New installs always write to .opencode/commands/ (plural)."""
|
||||
integration = get_integration(self.KEY)
|
||||
manifest = IntegrationManifest(self.KEY, tmp_path)
|
||||
integration.setup(tmp_path, manifest)
|
||||
|
||||
canonical = tmp_path / ".opencode" / "commands"
|
||||
legacy = tmp_path / ".opencode" / "command"
|
||||
assert canonical.is_dir()
|
||||
assert not legacy.exists()
|
||||
assert any(canonical.glob("speckit.*.md"))
|
||||
Reference in New Issue
Block a user