mirror of
https://github.com/github/spec-kit.git
synced 2026-07-03 12:28:06 +08:00
fix(scripts): keep PowerShell branch-name acronym match case-sensitive (parity with bash) (#3129)
* fix(scripts): keep PowerShell branch-name acronym match case-sensitive
Get-BranchName keeps a sub-3-character word only when it appears as an
UPPERCASE acronym in the description. The bash twin checks this
case-sensitively (grep "\b${word^^}\b" / grep -qw -- "${word^^}"), but the
PowerShell twin used -match, which is case-INSENSITIVE, so it kept EVERY
short word regardless of case -- contradicting its own comment and diverging
from bash. The same description then produced different spec-directory and
branch names on Windows/PowerShell vs macOS/Linux (e.g. "Add go support" ->
001-go-support instead of 001-support), desyncing specs/, feature.json, and
git branches across a mixed-OS team.
Use the case-sensitive -cmatch so a short word is kept only for a genuine
uppercase acronym, matching bash. Applied to both the core
scripts/powershell/create-new-feature.ps1 and the git extension's
create-new-feature-branch.ps1.
Add bash + PowerShell regression tests (core and git-extension) asserting a
lowercase short word is dropped while an uppercase acronym is kept.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* test: fix article grammar in branch-name docstrings
Address review: 'an UPPERCASE acronym' -> 'an acronym in UPPERCASE' across the four branch-name case-sensitivity test docstrings (the indefinite article reads cleanly before 'acronym'). Docstring-only; no behavior change.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -252,7 +252,10 @@ function Get-BranchName {
|
||||
if ($stopWords -contains $word) { continue }
|
||||
if ($word.Length -ge 3) {
|
||||
$meaningfulWords += $word
|
||||
} elseif ($Description -match "\b$($word.ToUpper())\b") {
|
||||
} elseif ($Description -cmatch "\b$($word.ToUpper())\b") {
|
||||
# Case-sensitive (-cmatch) to mirror the bash twin's `grep -qw -- "${word^^}"`:
|
||||
# keep a short word only when its UPPERCASE form appears in the original
|
||||
# (an acronym). -match is case-insensitive and would keep every short word.
|
||||
$meaningfulWords += $word
|
||||
}
|
||||
}
|
||||
|
||||
@@ -298,6 +298,24 @@ class TestCreateFeatureBash:
|
||||
assert data["BRANCH_NAME"] == "001-user-auth"
|
||||
assert data["FEATURE_NUM"] == "001"
|
||||
|
||||
def test_branch_name_short_word_case_sensitivity(self, tmp_path: Path):
|
||||
"""A short word is dropped from the derived branch name unless it appears
|
||||
as an acronym in UPPERCASE in the description (case-sensitive, must match the
|
||||
PowerShell twin)."""
|
||||
project = _setup_project(tmp_path)
|
||||
# lowercase "go" (<3 chars, not an uppercase acronym) is dropped
|
||||
r1 = _run_bash(
|
||||
"create-new-feature-branch.sh", project, "--json", "--dry-run", "Add go support",
|
||||
)
|
||||
assert r1.returncode == 0, r1.stderr
|
||||
assert json.loads(r1.stdout)["BRANCH_NAME"] == "001-support"
|
||||
# uppercase "GO" is kept as an acronym
|
||||
r2 = _run_bash(
|
||||
"create-new-feature-branch.sh", project, "--json", "--dry-run", "Use GO now",
|
||||
)
|
||||
assert r2.returncode == 0, r2.stderr
|
||||
assert json.loads(r2.stdout)["BRANCH_NAME"] == "001-use-go-now"
|
||||
|
||||
def test_creates_branch_timestamp(self, tmp_path: Path):
|
||||
"""Extension create-new-feature-branch.sh creates timestamp branch."""
|
||||
project = _setup_project(tmp_path)
|
||||
@@ -426,6 +444,21 @@ class TestCreateFeaturePowerShell:
|
||||
data = json.loads(result.stdout)
|
||||
assert data["BRANCH_NAME"] == "001-user-auth"
|
||||
|
||||
def test_branch_name_short_word_case_sensitivity(self, tmp_path: Path):
|
||||
"""PowerShell must match the bash twin: a short word is dropped unless it
|
||||
appears as an acronym in UPPERCASE (case-sensitive -cmatch, not -match)."""
|
||||
project = _setup_project(tmp_path)
|
||||
r1 = _run_pwsh(
|
||||
"create-new-feature-branch.ps1", project, "-Json", "-DryRun", "Add go support",
|
||||
)
|
||||
assert r1.returncode == 0, r1.stderr
|
||||
assert json.loads(r1.stdout)["BRANCH_NAME"] == "001-support"
|
||||
r2 = _run_pwsh(
|
||||
"create-new-feature-branch.ps1", project, "-Json", "-DryRun", "Use GO now",
|
||||
)
|
||||
assert r2.returncode == 0, r2.stderr
|
||||
assert json.loads(r2.stdout)["BRANCH_NAME"] == "001-use-go-now"
|
||||
|
||||
def test_dry_run_counts_branches_checked_out_in_worktrees(self, tmp_path: Path):
|
||||
"""Branches checked out in sibling worktrees still reserve their prefix."""
|
||||
project = _setup_project(tmp_path / "project")
|
||||
|
||||
@@ -240,6 +240,17 @@ class TestSequentialBranch:
|
||||
assert branch is not None
|
||||
assert re.match(r"^\d{3,}-new-feat$", branch), f"unexpected branch: {branch}"
|
||||
|
||||
def test_branch_name_short_word_case_sensitivity(self, git_repo: Path):
|
||||
"""A short word is dropped from the derived branch name unless it appears
|
||||
as an acronym in UPPERCASE in the description. The PowerShell twin must use
|
||||
case-sensitive -cmatch to produce the same result."""
|
||||
r1 = run_script(git_repo, "--json", "--dry-run", "Add go support")
|
||||
assert r1.returncode == 0, r1.stderr
|
||||
assert json.loads(r1.stdout)["BRANCH_NAME"] == "001-support"
|
||||
r2 = run_script(git_repo, "--json", "--dry-run", "Use GO now")
|
||||
assert r2.returncode == 0, r2.stderr
|
||||
assert json.loads(r2.stdout)["BRANCH_NAME"] == "001-use-go-now"
|
||||
|
||||
def test_sequential_ignores_timestamp_dirs(self, git_repo: Path):
|
||||
"""Sequential numbering skips timestamp dirs when computing next number."""
|
||||
(git_repo / "specs" / "002-first-feat").mkdir(parents=True)
|
||||
@@ -272,6 +283,25 @@ class TestSequentialBranchPowerShell:
|
||||
assert "[long]::TryParse($matches[1], [ref]$num)" in content
|
||||
assert "$num = [int]$matches[1]" not in content
|
||||
|
||||
@pytest.mark.skipif(not _has_pwsh(), reason="pwsh not installed")
|
||||
def test_branch_name_short_word_case_sensitivity(self, ps_git_repo: Path):
|
||||
"""Core create-new-feature.ps1 must drop a short word unless it appears as
|
||||
an acronym in UPPERCASE (case-sensitive -cmatch), matching the bash twin."""
|
||||
script = ps_git_repo / "scripts" / "powershell" / "create-new-feature.ps1"
|
||||
|
||||
def _run(desc: str) -> subprocess.CompletedProcess:
|
||||
return subprocess.run(
|
||||
["pwsh", "-NoProfile", "-File", str(script), "-Json", "-DryRun", desc],
|
||||
cwd=ps_git_repo, capture_output=True, text=True,
|
||||
)
|
||||
|
||||
r1 = _run("Add go support")
|
||||
assert r1.returncode == 0, r1.stderr
|
||||
assert json.loads(r1.stdout)["BRANCH_NAME"] == "001-support"
|
||||
r2 = _run("Use GO now")
|
||||
assert r2.returncode == 0, r2.stderr
|
||||
assert json.loads(r2.stdout)["BRANCH_NAME"] == "001-use-go-now"
|
||||
|
||||
|
||||
# ── check_feature_branch Tests ───────────────────────────────────────────────
|
||||
|
||||
|
||||
Reference in New Issue
Block a user