Skip to content

fix: paths-only skips branch validation, setup-plan preserves existing plan#2672

Open
mnriem wants to merge 4 commits into
github:mainfrom
mnriem:fix/2653-shell-script-paths-only-and-plan-overwrite
Open

fix: paths-only skips branch validation, setup-plan preserves existing plan#2672
mnriem wants to merge 4 commits into
github:mainfrom
mnriem:fix/2653-shell-script-paths-only-and-plan-overwrite

Conversation

@mnriem
Copy link
Copy Markdown
Collaborator

@mnriem mnriem commented May 22, 2026

Fixes #2653

Summary

Two shell-script bug fixes reported in #2653:

1. check-prerequisites --paths-only no longer validates branch name

--paths-only / -PathsOnly is documented as "no prerequisite validation", but check_feature_branch ran before the PATHS_ONLY early exit, causing failures on non-spec branches (e.g. main).

Fix: Move branch validation after the PATHS_ONLY block in both bash and PowerShell scripts.

2. setup-plan preserves existing plan.md

setup-plan.sh / setup-plan.ps1 unconditionally copied the plan template to $IMPL_PLAN, silently overwriting user-authored plans on reruns.

Fix: Skip template copy when plan.md already exists. Also redirect status messages to stderr in --json mode so stdout remains parseable JSON.

Changes

  • scripts/bash/check-prerequisites.sh — move check_feature_branch after PATHS_ONLY exit
  • scripts/powershell/check-prerequisites.ps1 — move Test-FeatureBranch after $PathsOnly exit
  • scripts/bash/setup-plan.sh — guard cp with existence check; status messages to stderr in JSON mode
  • scripts/powershell/setup-plan.ps1 — guard template write with existence check

Tests

  • tests/test_check_prerequisites_paths_only.py — 7 tests (bash + PowerShell): paths-only on non-spec branch, paths-only on spec branch, text mode, normal mode still validates
  • tests/test_setup_plan_no_overwrite.py — 6 tests (bash + PowerShell): creates plan when missing, preserves existing plan, JSON parseable on first run, skip message on stderr

…g plan (github#2653)

- check-prerequisites.sh/ps1: move branch validation after --paths-only
  early exit so --paths-only returns paths without requiring a spec branch
- setup-plan.sh/ps1: skip template copy when plan.md already exists to
  prevent overwriting user-authored plans on reruns
- setup-plan.sh: send status messages to stderr in --json mode so stdout
  remains parseable JSON
- Add tests for both fixes (bash + PowerShell)
Copilot AI review requested due to automatic review settings May 22, 2026 00:13
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Fixes two script behaviors affecting automation and reruns: check-prerequisites should honor --paths-only as “no validation”, and setup-plan should avoid overwriting an existing plan.md (while keeping --json output machine-parseable).

Changes:

  • Move branch validation to occur after --paths-only early-exit in both bash and PowerShell check-prerequisites scripts.
  • Update setup-plan (bash + PowerShell) to skip copying the plan template when plan.md already exists.
  • Add pytest coverage for --paths-only behavior and for “do not overwrite plan.md” behavior.
Show a summary per file
File Description
scripts/bash/check-prerequisites.sh Defers branch validation until after --paths-only early exit.
scripts/powershell/check-prerequisites.ps1 Same as bash: -PathsOnly exits before branch validation.
scripts/bash/setup-plan.sh Skips template copy if plan.md exists; emits status to stderr in --json mode.
scripts/powershell/setup-plan.ps1 Skips template write if plan.md exists (but currently writes a status line to stdout).
tests/test_check_prerequisites_paths_only.py Adds coverage for paths-only behavior in bash and PowerShell.
tests/test_setup_plan_no_overwrite.py Adds coverage for initial creation + non-overwrite behavior in bash and PowerShell.

Copilot's findings

Tip

Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

  • Files reviewed: 6/6 changed files
  • Comments generated: 2

Comment thread scripts/powershell/setup-plan.ps1 Outdated
Comment thread tests/test_setup_plan_no_overwrite.py
…tions

Address review: setup-plan.ps1 Write-Output polluted stdout in -Json
mode when plan.md already existed. Use [Console]::Error.WriteLine()
when -Json is set. Add json.loads + stderr assertions to the PS rerun
test to catch regressions.
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot's findings

  • Files reviewed: 6/6 changed files
  • Comments generated: 1

Comment thread scripts/powershell/setup-plan.ps1 Outdated
Bare Test-Path matches directories too, which would silently skip plan
creation if a directory existed at the plan.md path.
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot's findings

  • Files reviewed: 6/6 changed files
  • Comments generated: 2

Comment on lines +24 to +60
def _install_bash_scripts(repo: Path) -> None:
d = repo / ".specify" / "scripts" / "bash"
d.mkdir(parents=True, exist_ok=True)
shutil.copy(COMMON_SH, d / "common.sh")
shutil.copy(SETUP_PLAN_SH, d / "setup-plan.sh")


def _install_ps_scripts(repo: Path) -> None:
d = repo / ".specify" / "scripts" / "powershell"
d.mkdir(parents=True, exist_ok=True)
shutil.copy(COMMON_PS, d / "common.ps1")
shutil.copy(SETUP_PLAN_PS, d / "setup-plan.ps1")


def _minimal_templates(repo: Path) -> None:
tdir = repo / ".specify" / "templates"
tdir.mkdir(parents=True, exist_ok=True)
shutil.copy(PLAN_TEMPLATE, tdir / "plan-template.md")


def _clean_env() -> dict[str, str]:
env = os.environ.copy()
for key in list(env):
if key.startswith("SPECIFY_"):
env.pop(key)
return env


def _git_init(repo: Path) -> None:
subprocess.run(["git", "init", "-q"], cwd=repo, check=True)
subprocess.run(
["git", "config", "user.email", "test@example.com"], cwd=repo, check=True
)
subprocess.run(["git", "config", "user.name", "Test User"], cwd=repo, check=True)
subprocess.run(
["git", "commit", "--allow-empty", "-m", "init", "-q"], cwd=repo, check=True
)
Comment on lines +23 to +54
def _install_bash_scripts(repo: Path) -> None:
d = repo / ".specify" / "scripts" / "bash"
d.mkdir(parents=True, exist_ok=True)
shutil.copy(COMMON_SH, d / "common.sh")
shutil.copy(CHECK_PREREQS_SH, d / "check-prerequisites.sh")


def _install_ps_scripts(repo: Path) -> None:
d = repo / ".specify" / "scripts" / "powershell"
d.mkdir(parents=True, exist_ok=True)
shutil.copy(COMMON_PS, d / "common.ps1")
shutil.copy(CHECK_PREREQS_PS, d / "check-prerequisites.ps1")


def _clean_env() -> dict[str, str]:
env = os.environ.copy()
for key in list(env):
if key.startswith("SPECIFY_"):
env.pop(key)
return env


def _git_init(repo: Path) -> None:
subprocess.run(["git", "init", "-q"], cwd=repo, check=True)
subprocess.run(
["git", "config", "user.email", "test@example.com"], cwd=repo, check=True
)
subprocess.run(["git", "config", "user.name", "Test User"], cwd=repo, check=True)
subprocess.run(
["git", "commit", "--allow-empty", "-m", "init", "-q"], cwd=repo, check=True
)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Shell scripts: paths-only validates branch and setup-plan can overwrite plan.md

2 participants