diff --git a/hooks/pre-commit b/hooks/pre-commit index 8391c60..cf6ec7d 100755 --- a/hooks/pre-commit +++ b/hooks/pre-commit @@ -1,38 +1,13 @@ #!/bin/sh # pre-commit hook: hygiene checks + shellcheck # Checks (ordered fastest-first): -# 1. Branch ancestry (squad/* must descend from develop) -# 2. ASCII-only on staged *.ps1, *.md, *.sh files -# 3. Refuse commits directly on develop/main/master -# 4. Shellcheck on staged .sh files +# 1. ASCII-only on staged *.ps1, *.md, *.sh files +# 2. Refuse commits directly on develop/main/master +# 3. Shellcheck on staged .sh files set -e # --------------------------------------------------------------------------- -# Check 1: Branch ancestry (fast -- single git command) -# --------------------------------------------------------------------------- -CURRENT_BRANCH=$(git rev-parse --abbrev-ref HEAD 2>/dev/null || echo "") -case "$CURRENT_BRANCH" in - squad/*|goofy/*|mickey/*|chip/*|pluto/*|donald/*|jiminy/*) - if git rev-parse --verify develop >/dev/null 2>&1; then - if ! git merge-base --is-ancestor develop HEAD 2>/dev/null; then - echo "" - echo "ERROR: Branch ancestry bleed detected." - echo "" - echo " Branch '$CURRENT_BRANCH' is not descended from 'develop'." - echo " squad/* branches must be forked from develop, not from other squad branches." - echo "" - echo " Fix: rebase onto develop or recreate the branch from develop." - echo " git rebase develop" - echo " # or: git checkout develop && git checkout -b " - echo "" - exit 1 - fi - fi - ;; -esac - -# --------------------------------------------------------------------------- -# Check 2: ASCII-only on staged *.ps1, *.md, *.sh files +# Check 1: ASCII-only on staged *.ps1, *.md, *.sh files # # Scanned extensions: # .ps1 -- PS 5.1 on Windows uses CP1252; non-ASCII breaks string literals @@ -74,7 +49,7 @@ if [ -n "$ASCII_STAGED" ]; then fi # --------------------------------------------------------------------------- -# Check 3: Refuse commits directly on develop / main / master +# Check 2: Refuse commits directly on develop / main / master # --------------------------------------------------------------------------- current_branch="$(git rev-parse --abbrev-ref HEAD 2>/dev/null)" case "$current_branch" in @@ -82,14 +57,14 @@ case "$current_branch" in echo "" echo "ERROR: refusing to commit directly on '$current_branch'." echo " Create a feature branch first:" - echo " git checkout -b squad/-" + echo " git checkout -b feat/-" echo "" exit 1 ;; esac # --------------------------------------------------------------------------- -# Check 4: Shellcheck on staged .sh files +# Check 3: Shellcheck on staged .sh files # --------------------------------------------------------------------------- if ! command -v shellcheck >/dev/null 2>&1; then exit 0 diff --git a/tests/test_precommit_hygiene.sh b/tests/test_precommit_hygiene.sh index 560b804..5deb50c 100644 --- a/tests/test_precommit_hygiene.sh +++ b/tests/test_precommit_hygiene.sh @@ -3,10 +3,9 @@ # Tests for pre-commit hygiene checks (Issue #240) and pre-push guard (Issue #224) # # Covers: -# Check 1: Branch ancestry (squad/* must descend from develop) -# Check 2: ASCII-only on staged *.ps1, *.md, *.sh files -# Check 3: Protected branch refuse (develop/main/master) -# Check 4: Shellcheck on staged .sh files +# Check 1: ASCII-only on staged *.ps1, *.md, *.sh files +# Check 2: Protected branch refuse (develop/main/master) +# Check 3: Shellcheck on staged .sh files # pre-push: Main push guard + advisory PSScriptAnalyzer exit-code # # Usage: @@ -31,7 +30,7 @@ mkdir -p "$TMPDIR_BASE" cleanup() { rm -rf "$TMPDIR_BASE"; } trap cleanup EXIT -# Helper: create a fresh git repo with develop branch and a squad branch +# Helper: create a fresh git repo with develop branch and a feature branch setup_test_repo() { local repo_dir="$1" mkdir -p "$repo_dir" @@ -51,118 +50,103 @@ setup_test_repo() { } # =========================================================================== -# Check 1 Tests: Branch ancestry (removed - squad-specific) +# Check 1 Tests: ASCII-only on staged .ps1 / .md / .sh files # =========================================================================== echo "" -echo "=== Check 1: Branch ancestry (SKIPPED - no longer applicable) ===" +echo "=== Check 1: ASCII-only .ps1 / .md / .sh ===" -# Test 1a: SKIPPED - squad branch ancestry check was squad-specific -pass "T1a: Branch ancestry check removed (squad-specific)" - -# Test 1b: SKIPPED -pass "T1b: Branch ancestry check removed (squad-specific)" - -# Test 1c: SKIPPED -pass "T1c: Branch ancestry check removed (squad-specific)" - -# =========================================================================== -# Check 2 Tests: ASCII-only on staged .ps1 / .md / .sh files -# =========================================================================== -echo "" -echo "=== Check 2: ASCII-only .ps1 / .md / .sh ===" - -# Test 2a: FAIL - .ps1 with non-ASCII -T2A_DIR="${TMPDIR_BASE}/t2a" -setup_test_repo "$T2A_DIR" +# Test 1a: FAIL - .ps1 with non-ASCII +T1A_DIR="${TMPDIR_BASE}/t1a" +setup_test_repo "$T1A_DIR" git checkout -q -b feature/ascii-test # Create a .ps1 with an em dash (UTF-8 bytes for U+2014: E2 80 94) printf 'Write-Host "hello \xe2\x80\x94 world"\n' > test.ps1 git add test.ps1 if sh "$HOOK" >/dev/null 2>&1; then - fail "T2a: .ps1 with non-ASCII bytes should fail" + fail "T1a: .ps1 with non-ASCII bytes should fail" else - pass "T2a: .ps1 with non-ASCII bytes fails" + pass "T1a: .ps1 with non-ASCII bytes fails" fi -# Test 2b: PASS - .ps1 with only ASCII -T2B_DIR="${TMPDIR_BASE}/t2b" -setup_test_repo "$T2B_DIR" +# Test 1b: PASS - .ps1 with only ASCII +T1B_DIR="${TMPDIR_BASE}/t1b" +setup_test_repo "$T1B_DIR" git checkout -q -b feature/ascii-pass echo 'Write-Host "hello -- world"' > test.ps1 git add test.ps1 if sh "$HOOK" >/dev/null 2>&1; then - pass "T2b: .ps1 with ASCII-only passes" + pass "T1b: .ps1 with ASCII-only passes" else - fail "T2b: .ps1 with ASCII-only passes" + fail "T1b: .ps1 with ASCII-only passes" fi -# Test 2c: FAIL - .md with non-ASCII (em-dash) is now rejected (#322 part B) -T2C_DIR="${TMPDIR_BASE}/t2c" -setup_test_repo "$T2C_DIR" +# Test 1c: FAIL - .md with non-ASCII (em-dash) is now rejected (#322 part B) +T1C_DIR="${TMPDIR_BASE}/t1c" +setup_test_repo "$T1C_DIR" git checkout -q -b feature/md-nonascii printf 'hello \xe2\x80\x94 world\n' > notes.md git add notes.md if sh "$HOOK" >/dev/null 2>&1; then - fail "T2c: .md with non-ASCII bytes should fail" + fail "T1c: .md with non-ASCII bytes should fail" else - pass "T2c: .md with non-ASCII bytes fails" + pass "T1c: .md with non-ASCII bytes fails" fi -# Test 2d: FAIL - .sh with non-ASCII (em-dash) is rejected (#322 part B) -T2D_DIR="${TMPDIR_BASE}/t2d" -setup_test_repo "$T2D_DIR" +# Test 1d: FAIL - .sh with non-ASCII (em-dash) is rejected (#322 part B) +T1D_DIR="${TMPDIR_BASE}/t1d" +setup_test_repo "$T1D_DIR" git checkout -q -b feature/sh-nonascii printf 'echo "hello \xe2\x80\x94 world"\n' > script.sh git add script.sh if sh "$HOOK" >/dev/null 2>&1; then - fail "T2d: .sh with non-ASCII bytes should fail" + fail "T1d: .sh with non-ASCII bytes should fail" else - pass "T2d: .sh with non-ASCII bytes fails" + pass "T1d: .sh with non-ASCII bytes fails" fi -# Test 2e: PASS - non-scanned extension (.txt) with non-ASCII is allowed -T2E_DIR="${TMPDIR_BASE}/t2e" -setup_test_repo "$T2E_DIR" +# Test 1e: PASS - non-scanned extension (.txt) with non-ASCII is allowed +T1E_DIR="${TMPDIR_BASE}/t1e" +setup_test_repo "$T1E_DIR" git checkout -q -b feature/txt-nonascii printf 'hello \xe2\x80\x94 world\n' > notes.txt git add notes.txt if sh "$HOOK" >/dev/null 2>&1; then - pass "T2e: non-scanned extension (.txt) with non-ASCII is allowed" + pass "T1e: non-scanned extension (.txt) with non-ASCII is allowed" else - fail "T2e: non-scanned extension (.txt) with non-ASCII is allowed" + fail "T1e: non-scanned extension (.txt) with non-ASCII is allowed" fi # =========================================================================== -# Check 3 Tests: Refuse commits on protected branches +# Check 2 Tests: Refuse commits on protected branches # =========================================================================== echo "" -echo "=== Check 3: Protected branch refuse ===" +echo "=== Check 2: Protected branch refuse ===" -# Test 3a: FAIL - commit on develop should be refused +# Test 2a: FAIL - commit on develop should be refused T5A_DIR="${TMPDIR_BASE}/t5a" setup_test_repo "$T5A_DIR" # Already on develop after setup_test_repo echo "bad" > bad.txt git add bad.txt if sh "$HOOK" >/dev/null 2>&1; then - fail "T3a: commit on develop should be refused" + fail "T2a: commit on develop should be refused" else - pass "T3a: commit on develop is refused" + pass "T2a: commit on develop is refused" fi -# Test 3b: FAIL - commit on main should be refused +# Test 2b: FAIL - commit on main should be refused T5B_DIR="${TMPDIR_BASE}/t5b" setup_test_repo "$T5B_DIR" git checkout -q -b main echo "bad" > bad.txt git add bad.txt if sh "$HOOK" >/dev/null 2>&1; then - fail "T3b: commit on main should be refused" + fail "T2b: commit on main should be refused" else - pass "T3b: commit on main is refused" + pass "T2b: commit on main is refused" fi -# Test 3c: FAIL - commit on master should be refused +# Test 2c: FAIL - commit on master should be refused T5C_DIR="${TMPDIR_BASE}/t5c" mkdir -p "$T5C_DIR" cd "$T5C_DIR" @@ -177,33 +161,33 @@ git branch -m master 2>/dev/null || true echo "bad" > bad.txt git add bad.txt if sh "$HOOK" >/dev/null 2>&1; then - fail "T3c: commit on master should be refused" + fail "T2c: commit on master should be refused" else - pass "T3c: commit on master is refused" + pass "T2c: commit on master is refused" fi -# Test 3d: PASS - commit on feature branch is allowed +# Test 2d: PASS - commit on feature branch is allowed T5D_DIR="${TMPDIR_BASE}/t5d" setup_test_repo "$T5D_DIR" git checkout -q -b feature/123-feature echo "good" > good.txt git add good.txt if sh "$HOOK" >/dev/null 2>&1; then - pass "T3d: commit on feature branch is allowed" + pass "T2d: commit on feature branch is allowed" else - fail "T3d: commit on feature branch is allowed" + fail "T2d: commit on feature branch is allowed" fi -# Test 3e: PASS - commit on pluto/* branch is allowed +# Test 2e: PASS - commit on feature branch is allowed T5E_DIR="${TMPDIR_BASE}/t5e" setup_test_repo "$T5E_DIR" -git checkout -q -b pluto/249-fix +git checkout -q -b feat/249-fix echo "good" > good.txt git add good.txt if sh "$HOOK" >/dev/null 2>&1; then - pass "T3e: commit on pluto/* branch is allowed" + pass "T2e: commit on feature branch is allowed" else - fail "T3e: commit on pluto/* branch is allowed" + fail "T2e: commit on feature branch is allowed" fi # =========================================================================== diff --git a/tests/test_windows_setup.ps1 b/tests/test_windows_setup.ps1 index 0dce150..c26a508 100644 --- a/tests/test_windows_setup.ps1 +++ b/tests/test_windows_setup.ps1 @@ -1521,7 +1521,7 @@ if (-not (Get-Command sh -ErrorAction SilentlyContinue)) { New-YTestRepo $repoDir Push-Location $repoDir try { - & git checkout -q -b pluto/ascii-fail 2>&1 | Out-Null + & git checkout -q -b feat/ascii-fail 2>&1 | Out-Null # Write a .ps1 containing a UTF-8 em-dash (bytes: 0xE2 0x80 0x94) $before = [System.Text.Encoding]::ASCII.GetBytes('Write-Host "hello ') $emDash = [byte[]](0xE2, 0x80, 0x94) @@ -1546,7 +1546,7 @@ if (-not (Get-Command sh -ErrorAction SilentlyContinue)) { New-YTestRepo $repoDir Push-Location $repoDir try { - & git checkout -q -b pluto/ascii-pass 2>&1 | Out-Null + & git checkout -q -b feat/ascii-pass 2>&1 | Out-Null 'Write-Host "hello -- world"' | Set-Content "test.ps1" -Encoding ASCII & git add "test.ps1" 2>&1 | Out-Null $out = & sh $preCommitHook 2>&1 @@ -1586,7 +1586,7 @@ if (-not (Get-Command sh -ErrorAction SilentlyContinue)) { try { $hookUnix = $prePushHook.Replace('\', '/') $stdinFile = Join-Path $yTmpBase "push_stdin_y5.txt" - Set-Content $stdinFile "refs/heads/squad/224-test abc1234 refs/heads/develop def5678" -Encoding ASCII + Set-Content $stdinFile "refs/heads/feat/224-test abc1234 refs/heads/develop def5678" -Encoding ASCII $stdinUnix = $stdinFile.Replace('\', '/') $out = & sh -c "sh '$hookUnix' origin 'https://github.com/test/repo' < '$stdinUnix'" 2>&1 if ($LASTEXITCODE -ne 0) { @@ -1604,14 +1604,14 @@ if (-not (Get-Command sh -ErrorAction SilentlyContinue)) { New-YTestRepo $repoDir Push-Location $repoDir try { - & git checkout -q -b squad/224-advisory-test 2>&1 | Out-Null + & git checkout -q -b feat/224-advisory-test 2>&1 | Out-Null # Commit a .ps1 so the hook has content to (optionally) analyze 'Write-Host "advisory test"' | Set-Content "advisory.ps1" -Encoding ASCII & git add "advisory.ps1" 2>&1 | Out-Null & git commit -q -m "test: advisory ps1" 2>&1 | Out-Null $hookUnix = $prePushHook.Replace('\', '/') $stdinFile = Join-Path $yTmpBase "push_stdin_y6.txt" - Set-Content $stdinFile "refs/heads/squad/224-advisory-test abc1234 refs/heads/squad/224-advisory-test def5678" -Encoding ASCII + Set-Content $stdinFile "refs/heads/feat/224-advisory-test abc1234 refs/heads/feat/224-advisory-test def5678" -Encoding ASCII $stdinUnix = $stdinFile.Replace('\', '/') $out = & sh -c "sh '$hookUnix' origin 'https://github.com/test/repo' < '$stdinUnix'" 2>&1 if ($LASTEXITCODE -ne 0) {