From 0523f43370236f556358b3b313aabaf53bdd3df6 Mon Sep 17 00:00:00 2001 From: luohui1 <3053763193@qq.com> Date: Thu, 18 Jun 2026 22:03:42 +0800 Subject: [PATCH] fix: derive paths-only branch from feature directory --- scripts/bash/common.sh | 3 ++ scripts/powershell/common.ps1 | 8 ++++ tests/test_check_prerequisites_paths_only.py | 41 ++++++++++++++++++++ 3 files changed, 52 insertions(+) diff --git a/scripts/bash/common.sh b/scripts/bash/common.sh index 3ea66a652d..72b5abbbb3 100644 --- a/scripts/bash/common.sh +++ b/scripts/bash/common.sh @@ -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" diff --git a/scripts/powershell/common.ps1 b/scripts/powershell/common.ps1 index 35406d3f66..627ffe5714 100644 --- a/scripts/powershell/common.ps1 +++ b/scripts/powershell/common.ps1 @@ -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 diff --git a/tests/test_check_prerequisites_paths_only.py b/tests/test_check_prerequisites_paths_only.py index 03e2fc6e8b..d6e0a5be76 100644 --- a/tests/test_check_prerequisites_paths_only.py +++ b/tests/test_check_prerequisites_paths_only.py @@ -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.""" @@ -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."""