fix(scripts): portable uppercase for branch-name acronym retention (bash 3.2)#3192
Conversation
Branch-name generation keeps short uppercase acronyms (e.g. "AI") by re-checking
the lowercased word against the original description with ${word^^}. That
parameter expansion is bash 4+ only; on macOS's default bash 3.2 it errors with
"bad substitution", so the acronym/short-word retention branch never matches and
those words are dropped ("go AI now" yields 001-now instead of 001-ai-now). Use
tr '[:lower:]' '[:upper:]' instead, which is portable.
Applies to both the core create-new-feature.sh and the git extension's
create-new-feature-branch.sh. The existing
test_branch_name_short_word_case_sensitivity / test_short_word_retention tests
cover this and now pass on bash 3.2 (CI runs on bash 4+/Linux, so they passed
there already).
(Disclosure: an AI coding agent surfaced the failure while running the suite on
macOS and pinned the root cause; fix written and reviewed by me.)
- core create-new-feature.sh: match the acronym with `grep -qw` (POSIX whole-word) instead of `\b...\b` (GNU/BSD-only), matching the git extension and dropping a non-POSIX construct. - lint: add a CI guard rejecting bash 4+ case-modification expansions in *.sh. shellcheck assumes bash 4+ from the shebang and can't flag them, and CI has no bash-3.2 lane, so this prevents silently re-shipping the macOS regression this PR fixes. - update a stale PowerShell extension comment that cited the removed bash idiom. (Disclosure: prompted by an AI code review of the PR; written and reviewed by me.)
There was a problem hiding this comment.
Pull request overview
This PR fixes branch-name generation on macOS’s default Bash 3.2 by removing Bash-4-only ${var^^} case expansion from the short-word/acronym retention logic, replacing it with a portable tr-based uppercase conversion and a whole-word match.
Changes:
- Replace
${word^^}withtr '[:lower:]' '[:upper:]'for acronym detection in both core and git-extension Bash scripts. - Align matching behavior to use
grep -wwhole-word matching rather than\bword boundaries. - Add a CI lint guard to prevent future use of Bash 4+ case-modification expansions in
*.shfiles, and document the fix in the changelog.
Show a summary per file
| File | Description |
|---|---|
| scripts/bash/create-new-feature.sh | Uses portable uppercase conversion + whole-word matching to retain acronyms on Bash 3.2. |
| extensions/git/scripts/bash/create-new-feature-branch.sh | Applies the same portable acronym retention logic in the git extension’s branch script. |
| extensions/git/scripts/powershell/create-new-feature-branch.ps1 | Comment-only clarification about case-sensitive acronym matching parity. |
| CHANGELOG.md | Documents the portability fix. |
| .github/workflows/lint.yml | Adds a CI guard to reject Bash 4+ case-modification expansions in shell scripts. |
Review details
Tip
Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
- Files reviewed: 5/5 changed files
- Comments generated: 2
- Review effort level: Low
mnriem
left a comment
There was a problem hiding this comment.
Please address Copilot feedback
Assisted-by: OpenAI Codex (model: GPT-5, autonomous)
|
Please address Copillot feedback. If not applicable, please explain why. And please resolve test & lint errors. Also please revert CHANGELOG.md as it is automatically generated. |
Assisted-by: OpenAI Codex (model: GPT-5, autonomous)
|
Posted on behalf of @PascalThuet by OpenAI Codex (model: GPT-5). Addressed the latest Copilot review round in commit 61470a2. The branch-description pipelines now use printf before grep in both bash implementations, the bash case-modification guard now requires the closing brace and catches trailing patterns, and the merge from origin/main keeps CHANGELOG.md generated-only by dropping the manual entry. Validation: targeted pytest suite passed locally: 106 passed, 45 skipped. |
|
Thank you! |
Upstream commits merged (19): - Retire iflow/roo/windsurf integrations (github#3166, github#3167, github#3168, github#3211, github#3212, github#3213) - Move version_satisfies to _utils.py, allow prereleases (github#2695) - Workflow fan-out max_concurrency via bounded thread pool (github#3224) - Reject bool max_iterations in while/do-while validation (github#3237) - bash 3.2 portability: echo→printf, ${word^^}→tr (github#3192) - --no-persist in common.sh for read-only path resolution (github#3025) - Reject host-less catalog URLs (github#3209, github#3227) - Extension updates: Intake v0.1.3, Architecture Workflow v1.2.2, Repository Governance, Workflow Preset v1.3.11 - Release 0.12.1 → 0.12.2 → 0.12.3.dev0 (github#3253, github#3259) - CI Python matrix alignment + bash 3.2 portability (github#3244) - Docs: Windsurf→Kilo Code references throughout Conflicts resolved (2): - pyproject.toml: kept fork name/description, bumped to 0.12.2+adlc1 - AGENTS.md: accepted upstream's condensed agent table (retired agents removed) Assisted-by: opencode (model: glm-5.2, supervised)
Description
Branch-name generation keeps short uppercase acronyms (e.g.
AI) by re-checking the lowercased word against the original description with${word^^}. That parameter expansion is bash 4+ only; on macOS's default bash 3.2 it errors withbad substitution, so the acronym / short-word retention branch never matches and those words are silently dropped (go AI nowyields001-nowinstead of001-ai-now).Replace
${word^^}withtr '[:lower:]' '[:upper:]', which is portable. Applies to both the corescripts/bash/create-new-feature.shand the git extension'sextensions/git/scripts/bash/create-new-feature-branch.sh. No behavior change on bash 4+.CI runs on bash 4+/Linux, so the existing tests passed there; the bug only shows on the default macOS shell.
Testing
test_branch_name_short_word_case_sensitivityandtest_short_word_retention[go AI now-001-ai-now]now pass (they failed before this fix).test_timestamp_branches,test_git_extension,test_branch_numbering(99 passed, 35 skipped).shellcheck --severity=errorclean on both scripts.AI Disclosure
An AI coding agent surfaced the failing tests while running the suite on macOS and pinned the root cause (
${word^^}vs bash 3.2); the fix was written and reviewed by me.