Skip to content

Commit 8629796

Browse files
authored
fix: warn when feature names have an empty suffix (#4575)
Assisted-by: OpenAI Codex (autonomous)
1 parent d743a69 commit 8629796

5 files changed

Lines changed: 87 additions & 0 deletions

File tree

‎docs/reference/core.md‎

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,24 @@ specify init my-project --integration copilot --preset compliance
6161
6262
> **Symlinked project roots.** `SPECIFY_INIT_DIR` relocates *where* the project is, not *how* a command treats symlinks: each command keeps its existing cwd-path stance. Commands that traverse and write project files through broad input paths (`bundle`, `workflow run <file>`) refuse a symlinked `.specify/` to preserve write confinement. Other project-scoped commands keep their existing behavior when `SPECIFY_INIT_DIR` points at a project root, which may include following a symlinked `.specify/`.
6363
64+
## Naming Features with the Helper Scripts
65+
66+
When calling the bundled `create-new-feature` helper scripts directly, generated
67+
names retain only ASCII letters and digits. A description entirely in a non-Latin
68+
script, or made only of punctuation, can therefore produce an empty suffix such
69+
as `001-`. The scripts warn on stderr when this happens, including during a dry
70+
run; JSON output remains parseable.
71+
72+
Keep the original description and supply a readable ASCII short name:
73+
74+
```bash
75+
bash .specify/scripts/bash/create-new-feature.sh --json --short-name user-auth "添加用户"
76+
```
77+
78+
The Python helper also accepts `--short-name`; the PowerShell helper uses
79+
`-ShortName`. A supplied short name is cleaned by the same rules, so it must
80+
contain at least one ASCII letter or digit.
81+
6482
## Check Installed Tools
6583

6684
```bash

‎scripts/bash/create-new-feature.sh‎

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -265,6 +265,10 @@ else
265265
BRANCH_SUFFIX=$(generate_branch_name "$FEATURE_DESCRIPTION")
266266
fi
267267

268+
if [ -z "$BRANCH_SUFFIX" ]; then
269+
echo "[specify] Warning: Feature name is empty after removing unsupported characters. Use --short-name with ASCII letters or digits (for example, user-auth)." >&2
270+
fi
271+
268272
# Warn if --number and --timestamp are both specified
269273
if [ "$USE_TIMESTAMP" = true ] && [ -n "$BRANCH_NUMBER" ]; then
270274
>&2 echo "[specify] Warning: --number is ignored when --timestamp is used"

‎scripts/powershell/create-new-feature.ps1‎

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -185,6 +185,10 @@ if ($ShortName) {
185185
$branchSuffix = Get-BranchName -Description $featureDesc
186186
}
187187

188+
if (-not $branchSuffix) {
189+
[Console]::Error.WriteLine("[specify] Warning: Feature name is empty after removing unsupported characters. Use -ShortName with ASCII letters or digits (for example, user-auth).")
190+
}
191+
188192
# Treat an explicit empty string as omitted, matching the bash and Python twins.
189193
$hasNumber = $PSBoundParameters.ContainsKey('Number') -and $Number -ne ''
190194

‎scripts/python/create_new_feature.py‎

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -264,6 +264,13 @@ def main(argv: list[str] | None = None) -> int:
264264
else:
265265
branch_suffix = _generate_branch_name(args.description)
266266

267+
if not branch_suffix:
268+
print(
269+
"[specify] Warning: Feature name is empty after removing unsupported characters. "
270+
"Use --short-name with ASCII letters or digits (for example, user-auth).",
271+
file=sys.stderr,
272+
)
273+
267274
branch_number = args.branch_number
268275
if args.use_timestamp and branch_number:
269276
print(

‎tests/test_create_new_feature_python_parity.py‎

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,60 @@ def repo_pair(tmp_path: Path) -> tuple[Path, Path]:
5757
return _setup_repo(tmp_path, "proj-a"), _setup_repo(tmp_path, "proj-b")
5858

5959

60+
@pytest.mark.parametrize(
61+
"variant",
62+
[
63+
pytest.param("bash", marks=requires_bash),
64+
"python",
65+
pytest.param(
66+
"powershell",
67+
marks=pytest.mark.skipif(not HAS_POWERSHELL, reason="no PowerShell available"),
68+
),
69+
],
70+
)
71+
@pytest.mark.parametrize("dry_run", [False, True])
72+
@pytest.mark.parametrize(
73+
"description,short_name,suffix,warns",
74+
[
75+
("添加用户", None, "", True),
76+
("добавить", None, "", True),
77+
("!!! ??? ***", None, "", True),
78+
("添加用户", "user-auth", "user-auth", False),
79+
("Add users", "用户", "", True),
80+
("Add user authentication", None, "user-authentication", False),
81+
],
82+
)
83+
def test_empty_feature_name_warning(
84+
repo: Path,
85+
variant: str,
86+
dry_run: bool,
87+
description: str,
88+
short_name: str | None,
89+
suffix: str,
90+
warns: bool,
91+
) -> None:
92+
"""Report unusable names without changing JSON or feature creation (#4574)."""
93+
powershell = variant == "powershell"
94+
args = ["-Json" if powershell else "--json"]
95+
if dry_run:
96+
args.append("-DryRun" if powershell else "--dry-run")
97+
if short_name is not None:
98+
args.extend(["-ShortName" if powershell else "--short-name", short_name])
99+
args.append(description)
100+
command = {"bash": bash_cmd, "python": py_cmd, "powershell": ps_cmd}[variant]
101+
result = run(command(repo, SCRIPT, *args), repo)
102+
103+
assert result.returncode == 0, result.stderr
104+
output = json_stdout(result)
105+
assert output["BRANCH_NAME"] == f"001-{suffix}"
106+
warning = "Feature name is empty after removing unsupported characters"
107+
assert result.stderr.count(warning) == int(warns)
108+
if warns:
109+
assert ("-ShortName" if powershell else "--short-name") in result.stderr
110+
assert "ASCII letters or digits" in result.stderr
111+
assert (repo / "specs" / f"001-{suffix}" / "spec.md").exists() is not dry_run
112+
113+
60114
def _run_all_variants_allow_existing(
61115
repo: Path, *, number: str, short_name: str
62116
):

0 commit comments

Comments
 (0)