chore: Root Directory Cleanup - Remove 1,100 Lines Outdated Docs #462
Workflow file for this run
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: PR Validation | |
| on: | |
| pull_request: | |
| branches: | |
| - main | |
| - integrate/mvp | |
| concurrency: | |
| group: ${{ github.ref }} | |
| cancel-in-progress: true | |
| permissions: | |
| contents: read | |
| jobs: | |
| scope-classifier: | |
| name: Scope Classifier | |
| runs-on: ubuntu-latest | |
| outputs: | |
| full_gate: ${{ steps.classify.outputs.full_gate }} | |
| docs_ci_only: ${{ steps.classify.outputs.docs_ci_only }} | |
| changed_count: ${{ steps.classify.outputs.changed_count }} | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@v4 | |
| with: | |
| fetch-depth: 0 | |
| - name: Classify PR change scope | |
| id: classify | |
| run: | | |
| git diff --name-only "${{ github.event.pull_request.base.sha }}" "${{ github.event.pull_request.head.sha }}" > changed_files.txt | |
| python3 - <<'PY' | |
| import fnmatch | |
| import os | |
| from pathlib import Path | |
| files = [line.strip() for line in Path("changed_files.txt").read_text(encoding="utf-8").splitlines() if line.strip()] | |
| fast_patterns = [ | |
| "docs/**", | |
| ".github/workflows/**", | |
| "ci/**", | |
| "README.md", | |
| "SECURITY.md", | |
| "CONTRIBUTING.md", | |
| "CODE_OF_CONDUCT.md", | |
| "CHANGELOG.md", | |
| "QUICKSTART.md", | |
| "scripts/README.md", | |
| "scripts/validate-root-allowlist.sh", | |
| ] | |
| docs_ci_only = bool(files) and all(any(fnmatch.fnmatch(f, p) for p in fast_patterns) for f in files) | |
| full_gate = not docs_ci_only | |
| with open(os.environ["GITHUB_OUTPUT"], "a", encoding="utf-8") as out: | |
| out.write(f"changed_count={len(files)}\n") | |
| out.write(f"docs_ci_only={'true' if docs_ci_only else 'false'}\n") | |
| out.write(f"full_gate={'true' if full_gate else 'false'}\n") | |
| print(f"changed_count={len(files)}") | |
| print(f"docs_ci_only={docs_ci_only}") | |
| print(f"full_gate={full_gate}") | |
| PY | |
| build-validation: | |
| needs: [scope-classifier] | |
| if: needs.scope-classifier.outputs.full_gate == 'true' | |
| uses: ./.github/workflows/_go-ci-job.yml | |
| with: | |
| job-name: Build Validation | |
| timeout-minutes: 10 | |
| run-command: make -f Makefile.ci ci-ultra-fast | |
| config-tests: | |
| needs: [scope-classifier] | |
| if: needs.scope-classifier.outputs.full_gate == 'true' | |
| uses: ./.github/workflows/_go-ci-job.yml | |
| with: | |
| job-name: Config Tests | |
| timeout-minutes: 10 | |
| run-command: | | |
| NPROC="$(nproc)" | |
| go test -short -timeout=2m -p "$NPROC" ./pkg/config/... | |
| auth-core-tests: | |
| needs: [scope-classifier] | |
| if: needs.scope-classifier.outputs.full_gate == 'true' | |
| uses: ./.github/workflows/_go-ci-job.yml | |
| with: | |
| job-name: Auth Core Tests | |
| timeout-minutes: 12 | |
| run-command: | | |
| NPROC="$(nproc)" | |
| go test -short -timeout=2m -p "$NPROC" ./pkg/auth | |
| auth-provider-tests: | |
| needs: [scope-classifier] | |
| if: needs.scope-classifier.outputs.full_gate == 'true' | |
| uses: ./.github/workflows/_go-ci-job.yml | |
| with: | |
| job-name: Auth Provider Tests | |
| timeout-minutes: 10 | |
| run-command: | | |
| NPROC="$(nproc)" | |
| go test -short -timeout=2m -p "$NPROC" ./pkg/auth/providers ./pkg/auth/docker | |
| security-tests: | |
| needs: [scope-classifier] | |
| if: needs.scope-classifier.outputs.full_gate == 'true' | |
| uses: ./.github/workflows/_go-ci-job.yml | |
| with: | |
| job-name: Security Tests | |
| timeout-minutes: 10 | |
| run-command: | | |
| NPROC="$(nproc)" | |
| go test -short -timeout=2m -p "$NPROC" ./internal/security/... | |
| docs-link-integrity: | |
| name: Docs Link Integrity | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@v4 | |
| - name: Scan markdown relative links | |
| run: | | |
| python3 - <<'PY' | |
| from pathlib import Path | |
| import re | |
| from collections import Counter | |
| files = sorted(set(list(Path("docs").rglob("*.md")) + [Path("README.md"), Path("SECURITY.md")])) | |
| pattern = re.compile(r'\[[^\]]+\]\(([^)]+)\)') | |
| ignored_prefixes = ("http://", "https://", "mailto:", "tel:", "javascript:", "#") | |
| missing = [] | |
| for f in files: | |
| text = f.read_text(encoding="utf-8", errors="ignore") | |
| for raw in pattern.findall(text): | |
| u = raw.strip().strip("<>").split()[0] | |
| if not u or u.startswith(ignored_prefixes) or u.startswith("`") or u.startswith("$" + "{{"): | |
| continue | |
| u = u.split("#", 1)[0].split("?", 1)[0] | |
| if not u: | |
| continue | |
| p = (f.parent / u).resolve() if not u.startswith("/") else Path(u) | |
| if p.exists(): | |
| continue | |
| if u.endswith("/") and p.is_dir() and ((p / "index.md").exists() or (p / "README.md").exists()): | |
| continue | |
| missing.append((str(f), u)) | |
| if not missing: | |
| print("No missing relative markdown links found.") | |
| else: | |
| print(f"::error::Found {len(missing)} missing relative markdown links.") | |
| counts = Counter(src for src, _ in missing) | |
| for src, n in counts.most_common(15): | |
| print(f"{n:3d} {src}") | |
| raise SystemExit(1) | |
| PY | |
| root-allowlist: | |
| name: Root Allowlist | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@v4 | |
| - name: Validate root allowlist | |
| run: ./scripts/validate-root-allowlist.sh | |
| basic-validation: | |
| name: Basic Validation | |
| runs-on: ubuntu-latest | |
| needs: [scope-classifier, build-validation, config-tests, auth-core-tests, auth-provider-tests, security-tests, docs-link-integrity, root-allowlist] | |
| if: always() | |
| steps: | |
| - name: Enforce required status outcome | |
| run: | | |
| echo "Scope: docs_ci_only=${{ needs.scope-classifier.outputs.docs_ci_only }}, full_gate=${{ needs.scope-classifier.outputs.full_gate }}, changed_count=${{ needs.scope-classifier.outputs.changed_count }}" | |
| if [ "${{ needs.docs-link-integrity.result }}" != "success" ] || \ | |
| [ "${{ needs.root-allowlist.result }}" != "success" ]; then | |
| echo "Basic Validation: FAIL" | |
| exit 1 | |
| fi | |
| if [ "${{ needs.scope-classifier.outputs.full_gate }}" = "true" ]; then | |
| if [ "${{ needs.build-validation.result }}" != "success" ] || \ | |
| [ "${{ needs.config-tests.result }}" != "success" ] || \ | |
| [ "${{ needs.auth-core-tests.result }}" != "success" ] || \ | |
| [ "${{ needs.auth-provider-tests.result }}" != "success" ] || \ | |
| [ "${{ needs.security-tests.result }}" != "success" ]; then | |
| echo "Basic Validation: FAIL" | |
| exit 1 | |
| fi | |
| fi | |
| echo "Basic Validation: PASS" |