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
Original file line number Diff line number Diff line change
Expand Up @@ -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
}
}
Expand Down
7 changes: 5 additions & 2 deletions scripts/powershell/create-new-feature.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -111,8 +111,11 @@ function Get-BranchName {
# Keep words that are length >= 3 OR appear as uppercase in original (likely acronyms)
if ($word.Length -ge 3) {
$meaningfulWords += $word
} elseif ($Description -match "\b$($word.ToUpper())\b") {
# Keep short words if they appear as uppercase in original (likely acronyms)
} elseif ($Description -cmatch "\b$($word.ToUpper())\b") {
# Keep short words if they appear as uppercase in original (likely acronyms).
# Use -cmatch (case-sensitive) so this matches the bash twin's
# case-sensitive `grep "\b${word^^}\b"`; -match would also match the
# lowercased word and keep every short word regardless of case.
$meaningfulWords += $word
}
}
Expand Down
33 changes: 33 additions & 0 deletions tests/extensions/git/test_git_extension.py
Original file line number Diff line number Diff line change
Expand Up @@ -298,6 +298,24 @@ def test_creates_branch_sequential(self, tmp_path: Path):
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)
Expand Down Expand Up @@ -426,6 +444,21 @@ def test_creates_branch_sequential(self, tmp_path: Path):
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")
Expand Down
30 changes: 30 additions & 0 deletions tests/test_timestamp_branches.py
Original file line number Diff line number Diff line change
Expand Up @@ -240,6 +240,17 @@ def test_sequential_default_with_existing_specs(self, git_repo: Path):
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)
Expand Down Expand Up @@ -272,6 +283,25 @@ def test_powershell_scanner_uses_long_tryparse_for_large_prefixes(self):
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 ───────────────────────────────────────────────

Expand Down