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
6 changes: 5 additions & 1 deletion scripts/powershell/common.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -209,7 +209,11 @@ function Test-FileExists {

function Test-DirHasFiles {
param([string]$Path, [string]$Description)
if ((Test-Path -Path $Path -PathType Container) -and (Get-ChildItem -Path $Path -ErrorAction SilentlyContinue | Where-Object { -not $_.PSIsContainer } | Select-Object -First 1)) {
# A directory counts as non-empty when it contains ANY entry (files or
# subdirectories), matching bash check_dir (`-n $(ls -A ...)`) and the JSON
# contracts checks. Filtering out subdirectories would mis-report a dir whose
# only contents are subdirectories (e.g. contracts/v1/openapi.yaml) as empty.
if ((Test-Path -Path $Path -PathType Container) -and (Get-ChildItem -Path $Path -ErrorAction SilentlyContinue | Select-Object -First 1)) {
Write-Output " [OK] $Description"
return $true
} else {
Expand Down
46 changes: 46 additions & 0 deletions tests/test_setup_tasks.py
Original file line number Diff line number Diff line change
Expand Up @@ -840,3 +840,49 @@ def test_setup_tasks_ps_errors_without_feature_context(
output = result.stderr + result.stdout
assert result.returncode != 0
assert "Feature directory not found" in output


# ---------------------------------------------------------------------------
# Directory non-emptiness parity: a dir whose only contents are subdirectories
# (e.g. contracts/v1/openapi.yaml) must count as non-empty in both shells.
# ---------------------------------------------------------------------------

def _run_bash_check_dir(repo: Path, target: Path) -> subprocess.CompletedProcess:
script = repo / ".specify" / "scripts" / "bash" / "common.sh"
return subprocess.run(
["bash", "-c", 'source "$1"; check_dir "$2" "contracts/"', "bash", str(script), str(target)],
cwd=repo, capture_output=True, text=True, check=False, env=_clean_env(),
)


def _run_powershell_test_dir(repo: Path, target: Path) -> subprocess.CompletedProcess:
script = repo / ".specify" / "scripts" / "powershell" / "common.ps1"
exe = "pwsh" if HAS_PWSH else _WINDOWS_POWERSHELL
return subprocess.run(
[exe, "-NoProfile", "-Command",
'& { param($common, $dir) . $common; Test-DirHasFiles -Path $dir -Description "contracts/" }',
str(script), str(target)],
cwd=repo, capture_output=True, text=True, check=False, env=_clean_env(),
)


@requires_bash
def test_check_dir_bash_counts_subdir_only_contracts(tasks_repo: Path) -> None:
"""bash check_dir treats a dir containing only subdirectories as non-empty."""
contracts = tasks_repo / "contracts" / "v1"
contracts.mkdir(parents=True)
(contracts / "openapi.yaml").write_text("openapi: 3.0\n", encoding="utf-8")
result = _run_bash_check_dir(tasks_repo, tasks_repo / "contracts")
assert result.returncode == 0, result.stderr
assert "✓" in result.stdout and "✗" not in result.stdout


@pytest.mark.skipif(not (HAS_PWSH or _WINDOWS_POWERSHELL), reason="no PowerShell available")
def test_test_dir_has_files_ps_counts_subdir_only_contracts(tasks_repo: Path) -> None:
"""Test-DirHasFiles must match bash: a subdir-only dir counts as non-empty."""
contracts = tasks_repo / "contracts" / "v1"
contracts.mkdir(parents=True)
(contracts / "openapi.yaml").write_text("openapi: 3.0\n", encoding="utf-8")
result = _run_powershell_test_dir(tasks_repo, tasks_repo / "contracts")
assert result.returncode == 0, result.stderr
assert "[OK]" in result.stdout and "[FAIL]" not in result.stdout