diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 8a83df474..c4b25e329 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -60,6 +60,10 @@ jobs: timeout-minutes: 8 steps: - uses: actions/checkout@v7 + with: + # Contract tests resolve reviewed historical subjects and create + # non-shallow fresh clones; the default one-commit checkout cannot. + fetch-depth: 0 - name: Install uv uses: astral-sh/setup-uv@v7 with: @@ -135,16 +139,20 @@ jobs: - name: Run E2E smoke tests run: | - echo "### E2E Test Results" >> $GITHUB_STEP_SUMMARY uv run pytest tests/e2e/ -m e2e \ --override-ini="addopts=--strict-markers --verbose --tb=short" \ --timeout=60 -v > e2e-output.txt 2>&1 || touch e2e_failed cat e2e-output.txt - echo '```text' >> $GITHUB_STEP_SUMMARY - tail -n 25 e2e-output.txt >> $GITHUB_STEP_SUMMARY - echo '```' >> $GITHUB_STEP_SUMMARY + { + echo "### E2E Test Results" + echo '```text' + tail -n 25 e2e-output.txt + echo '```' + if [ -f e2e_failed ]; then + echo "E2E tests failed — see above for server stderr output." + fi + } >> "$GITHUB_STEP_SUMMARY" if [ -f e2e_failed ]; then - echo "E2E tests failed — see above for server stderr output." >> $GITHUB_STEP_SUMMARY exit 1 fi shell: bash @@ -204,14 +212,14 @@ jobs: steps: - name: Check Overall Status run: | - echo "### 🏆 Final Quality Gate Status" >> $GITHUB_STEP_SUMMARY + echo "### 🏆 Final Quality Gate Status" >> "$GITHUB_STEP_SUMMARY" SUCCESS=true check_required() { local name="$1" local result="$2" if [[ "$result" != "success" ]]; then - echo "❌ ${name} failed: ${result}" >> $GITHUB_STEP_SUMMARY + echo "❌ ${name} failed: ${result}" >> "$GITHUB_STEP_SUMMARY" SUCCESS=false fi } @@ -222,10 +230,10 @@ jobs: local name="$1" local result="$2" if [[ "$result" == "failure" || "$result" == "cancelled" ]]; then - echo "❌ ${name} failed: ${result}" >> $GITHUB_STEP_SUMMARY + echo "❌ ${name} failed: ${result}" >> "$GITHUB_STEP_SUMMARY" SUCCESS=false else - echo "✅ ${name}: ${result}" >> $GITHUB_STEP_SUMMARY + echo "✅ ${name}: ${result}" >> "$GITHUB_STEP_SUMMARY" fi } @@ -253,13 +261,13 @@ jobs: # run where neither the test matrix nor the docs-check executed (guards # against a route misfire that skips everything). if [[ "$TEST" == "skipped" && "$DOCS" == "skipped" ]]; then - echo "❌ Neither Test Suite nor Docs Check ran — route misfire?" >> $GITHUB_STEP_SUMMARY + echo "❌ Neither Test Suite nor Docs Check ran — route misfire?" >> "$GITHUB_STEP_SUMMARY" SUCCESS=false fi if [ "$SUCCESS" = true ]; then - echo "✅ All systems go! This version meets our authority standards." >> $GITHUB_STEP_SUMMARY + echo "✅ All systems go! This version meets our authority standards." >> "$GITHUB_STEP_SUMMARY" else - echo "⚠️ Quality Gate rejected this version." >> $GITHUB_STEP_SUMMARY + echo "⚠️ Quality Gate rejected this version." >> "$GITHUB_STEP_SUMMARY" exit 1 fi diff --git a/tests/governance/test_ci_routing_contract.py b/tests/governance/test_ci_routing_contract.py index 00287b055..d2c6a1ffc 100644 --- a/tests/governance/test_ci_routing_contract.py +++ b/tests/governance/test_ci_routing_contract.py @@ -94,9 +94,7 @@ def test_ci_full_language_suite_runs_once_per_reusable_test_matrix() -> None: workflow = PROJECT_ROOT / ".github" / "workflows" / "reusable-test.yml" text = workflow.read_text(encoding="utf-8") - assert ( - '-m "not slow and not e2e and not network and not benchmark"' in text - ) + assert '-m "not slow and not e2e and not network and not benchmark"' in text assert ( '-m "not slow and not e2e and not network and not benchmark and not full_language"' in text @@ -231,3 +229,19 @@ def test_bandit_security_scan_is_blocking_and_configured() -> None: assert "bandit -c pyproject.toml -r tree_sitter_analyzer/" in body assert "|| true" not in body assert 'exit "$BANDIT_STATUS"' in body + + +def test_docs_check_fetches_history_for_contract_subjects() -> None: + """Regression for PR #1255: docs contracts require a non-shallow clone.""" + ci_text = (PROJECT_ROOT / ".github" / "workflows" / "ci.yml").read_text( + encoding="utf-8" + ) + _, marker, remainder = ci_text.partition("\n docs-check:\n") + docs_job, next_marker, _ = remainder.partition("\n quality-check:\n") + + assert marker == "\n docs-check:\n" + assert next_marker == "\n quality-check:\n" + checkout_start = docs_job.index(" - uses: actions/checkout@v7\n") + checkout_end = docs_job.index("\n - name:", checkout_start) + checkout_step = docs_job[checkout_start:checkout_end] + assert checkout_step.splitlines().count(" fetch-depth: 0") == 1