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
3 changes: 3 additions & 0 deletions scripts/bash/common.sh
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,9 @@ get_feature_paths() {

# Use printf '%q' to safely quote values, preventing shell injection
# via crafted branch names or paths containing special characters
if [[ -z "$current_branch" ]]; then
current_branch="$(basename "$feature_dir")"
fi
printf 'REPO_ROOT=%q\n' "$repo_root"
printf 'CURRENT_BRANCH=%q\n' "$current_branch"
printf 'FEATURE_DIR=%q\n' "$feature_dir"
Expand Down
8 changes: 8 additions & 0 deletions scripts/powershell/common.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,14 @@ function Get-FeaturePathsEnv {
[Console]::Error.WriteLine("ERROR: Feature directory not found. Set SPECIFY_FEATURE_DIRECTORY or run the specify command to create .specify/feature.json.")
exit 1
}

if (-not $currentBranch) {
$normalizedFeatureDir = $featureDir.TrimEnd(
[System.IO.Path]::DirectorySeparatorChar,
[System.IO.Path]::AltDirectorySeparatorChar
)
$currentBranch = Split-Path -Path $normalizedFeatureDir -Leaf
}

[PSCustomObject]@{
REPO_ROOT = $repoRoot
Expand Down
41 changes: 41 additions & 0 deletions tests/test_check_prerequisites_paths_only.py
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,26 @@ def test_paths_only_text_mode_on_non_spec_branch(prereq_repo: Path) -> None:
assert "FEATURE_DIR:" in result.stdout


@requires_bash
def test_paths_only_falls_back_to_feature_dir_basename(prereq_repo: Path) -> None:
"""--paths-only should emit a non-empty branch name from feature.json."""
feat = prereq_repo / "specs" / "001-my-feature"
feat.mkdir(parents=True, exist_ok=True)
_write_feature_json(prereq_repo)
script = prereq_repo / ".specify" / "scripts" / "bash" / "check-prerequisites.sh"
result = subprocess.run(
["bash", str(script), "--json", "--paths-only"],
cwd=prereq_repo,
capture_output=True,
text=True,
check=False,
env=_clean_env(),
)
assert result.returncode == 0, result.stderr
data = json.loads(result.stdout)
assert data["BRANCH"] == "001-my-feature"


@requires_bash
def test_normal_mode_still_validates_branch(prereq_repo: Path) -> None:
"""Without --paths-only, feature directory validation must still fail on main."""
Expand Down Expand Up @@ -211,6 +231,27 @@ def test_ps_paths_only_succeeds_on_spec_branch(prereq_repo: Path) -> None:
assert "FEATURE_DIR" in data


@pytest.mark.skipif(not (HAS_PWSH or _WINDOWS_POWERSHELL), reason="no PowerShell available")
def test_ps_paths_only_falls_back_to_feature_dir_basename(prereq_repo: Path) -> None:
"""-PathsOnly should emit a non-empty branch name from feature.json."""
feat = prereq_repo / "specs" / "001-my-feature"
feat.mkdir(parents=True, exist_ok=True)
_write_feature_json(prereq_repo)
script = prereq_repo / ".specify" / "scripts" / "powershell" / "check-prerequisites.ps1"
exe = "pwsh" if HAS_PWSH else _WINDOWS_POWERSHELL
result = subprocess.run(
[exe, "-NoProfile", "-File", str(script), "-Json", "-PathsOnly"],
cwd=prereq_repo,
capture_output=True,
text=True,
check=False,
env=_clean_env(),
)
assert result.returncode == 0, result.stderr
data = json.loads(result.stdout)
assert data["BRANCH"] == "001-my-feature"


@pytest.mark.skipif(not (HAS_PWSH or _WINDOWS_POWERSHELL), reason="no PowerShell available")
def test_ps_normal_mode_still_validates_branch(prereq_repo: Path) -> None:
"""Without -PathsOnly, feature directory validation must still fail on main."""
Expand Down