Skip to content

Commit 4a51428

Browse files
committed
fix: render managed script command hints
1 parent 028bb5f commit 4a51428

3 files changed

Lines changed: 42 additions & 10 deletions

File tree

src/specify_cli/shared_infra.py

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
from __future__ import annotations
44

55
import os
6+
import re
67
import tempfile
78
from pathlib import Path
89
from typing import Any
@@ -194,6 +195,37 @@ def _write_shared_bytes(
194195
temp_path.unlink()
195196

196197

198+
_BASH_FORMAT_COMMAND_RE = re.compile(
199+
r"\$\(\s*format_speckit_command\s+(['\"]?)([A-Za-z0-9_.-]+)\1(?:\s+[^)]*)?\)"
200+
)
201+
_POWERSHELL_FORMAT_COMMAND_RE = re.compile(
202+
r"Format-SpecKitCommand\s+-CommandName\s+(['\"])([A-Za-z0-9_.-]+)\1(?:\s+-RepoRoot\s+[^\r\n]+)?"
203+
)
204+
205+
206+
def _format_speckit_command(command_name: str, separator: str) -> str:
207+
name = command_name.strip().lstrip("/")
208+
if name.startswith("speckit."):
209+
name = name[len("speckit.") :]
210+
elif name.startswith("speckit-"):
211+
name = name[len("speckit-") :]
212+
name = name.replace(".", separator)
213+
return f"/speckit{separator}{name}"
214+
215+
216+
def _resolve_dynamic_command_refs(content: str, separator: str) -> str:
217+
"""Render script runtime command helpers for managed shared infra copies."""
218+
219+
content = _BASH_FORMAT_COMMAND_RE.sub(
220+
lambda match: _format_speckit_command(match.group(2), separator),
221+
content,
222+
)
223+
return _POWERSHELL_FORMAT_COMMAND_RE.sub(
224+
lambda match: f"'{_format_speckit_command(match.group(2), separator)}'",
225+
content,
226+
)
227+
228+
197229
def refresh_shared_templates(
198230
project_path: Path,
199231
*,
@@ -371,6 +403,7 @@ def _ensure_or_bucket_dir(directory: Path) -> bool:
371403
continue
372404
content = src_path.read_text(encoding="utf-8")
373405
content = IntegrationBase.resolve_command_refs(content, invoke_separator)
406+
content = _resolve_dynamic_command_refs(content, invoke_separator)
374407
planned_copies.append(
375408
(
376409
dst_path,

tests/integrations/test_integration_subcommand.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@
33
import json
44
import os
55

6-
import pytest
76
from typer.testing import CliRunner
87

98
from specify_cli import app

tests/test_setup_tasks.py

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -178,7 +178,7 @@ def test_setup_tasks_bash_core_template_resolved(tasks_repo: Path) -> None:
178178
setup-tasks.sh --json should exit 0 and return an absolute, existing
179179
TASKS_TEMPLATE path pointing to the core template.
180180
"""
181-
feat = _minimal_feature(tasks_repo)
181+
_minimal_feature(tasks_repo)
182182
script = tasks_repo / ".specify" / "scripts" / "bash" / "setup-tasks.sh"
183183

184184
result = subprocess.run(
@@ -205,7 +205,7 @@ def test_setup_tasks_bash_override_wins(tasks_repo: Path) -> None:
205205
When an override exists at .specify/templates/overrides/tasks-template.md,
206206
setup-tasks.sh --json must return the override path, not the core path.
207207
"""
208-
feat = _minimal_feature(tasks_repo)
208+
_minimal_feature(tasks_repo)
209209

210210
# Create the override
211211
overrides_dir = tasks_repo / ".specify" / "templates" / "overrides"
@@ -242,7 +242,7 @@ def test_setup_tasks_bash_extension_wins_over_core(tasks_repo: Path) -> None:
242242
When an extension template exists, setup-tasks.sh --json must resolve
243243
tasks-template.md from the extension before falling back to the core path.
244244
"""
245-
feat = _minimal_feature(tasks_repo)
245+
_minimal_feature(tasks_repo)
246246

247247
# FIX: real extension layout is .specify/extensions/<id>/templates/<name>.md
248248
extension_dir = (
@@ -280,7 +280,7 @@ def test_setup_tasks_bash_preset_wins_over_extension(tasks_repo: Path) -> None:
280280
When both preset and extension templates exist, setup-tasks.sh --json must
281281
resolve the preset path because presets outrank extensions.
282282
"""
283-
feat = _minimal_feature(tasks_repo)
283+
_minimal_feature(tasks_repo)
284284

285285
# FIX: real extension layout is .specify/extensions/<id>/templates/<name>.md
286286
extension_dir = (
@@ -324,7 +324,7 @@ def test_setup_tasks_bash_preset_priority_order(tasks_repo: Path) -> None:
324324
When two presets both provide tasks-template.md, the one listed first in
325325
.specify/presets/.registry wins.
326326
"""
327-
feat = _minimal_feature(tasks_repo)
327+
_minimal_feature(tasks_repo)
328328

329329
# resolve_template reads .specify/presets/.registry as a JSON object with a
330330
# "presets" map where each entry has a numeric "priority" (lower = higher
@@ -384,7 +384,7 @@ def test_setup_tasks_bash_missing_template_errors(tasks_repo: Path) -> None:
384384
When tasks-template.md is absent from all locations, setup-tasks.sh must
385385
exit non-zero and print a helpful ERROR message to stderr.
386386
"""
387-
feat = _minimal_feature(tasks_repo)
387+
_minimal_feature(tasks_repo)
388388

389389
# Remove the core template so no template exists anywhere
390390
core = tasks_repo / ".specify" / "templates" / "tasks-template.md"
@@ -609,7 +609,7 @@ def test_setup_tasks_ps_core_template_resolved(tasks_repo: Path) -> None:
609609
setup-tasks.ps1 -Json should exit 0 and return an absolute, existing
610610
TASKS_TEMPLATE path.
611611
"""
612-
feat = _minimal_feature(tasks_repo)
612+
_minimal_feature(tasks_repo)
613613
script = tasks_repo / ".specify" / "scripts" / "powershell" / "setup-tasks.ps1"
614614
exe = "pwsh" if HAS_PWSH else _POWERSHELL
615615

@@ -637,7 +637,7 @@ def test_setup_tasks_ps_override_wins(tasks_repo: Path) -> None:
637637
When an override exists at .specify/templates/overrides/tasks-template.md,
638638
setup-tasks.ps1 -Json must return the override path, not the core path.
639639
"""
640-
feat = _minimal_feature(tasks_repo)
640+
_minimal_feature(tasks_repo)
641641

642642
overrides_dir = tasks_repo / ".specify" / "templates" / "overrides"
643643
overrides_dir.mkdir(parents=True, exist_ok=True)
@@ -673,7 +673,7 @@ def test_setup_tasks_ps_missing_template_errors(tasks_repo: Path) -> None:
673673
When tasks-template.md is absent from all locations, setup-tasks.ps1 must
674674
exit non-zero and write a helpful error to stderr.
675675
"""
676-
feat = _minimal_feature(tasks_repo)
676+
_minimal_feature(tasks_repo)
677677

678678
core = tasks_repo / ".specify" / "templates" / "tasks-template.md"
679679
core.unlink()

0 commit comments

Comments
 (0)