Documentation validation #2
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: Documentation validation | |
| on: | |
| pull_request: | |
| push: | |
| branches: [mainline] | |
| schedule: | |
| - cron: "17 8 * * 2" | |
| workflow_dispatch: | |
| permissions: {} | |
| concurrency: | |
| group: documentation-validation-${{ github.event.pull_request.number || github.ref }} | |
| cancel-in-progress: true | |
| jobs: | |
| static: | |
| name: Unit and static checks | |
| if: github.event_name == 'pull_request' || github.event_name == 'push' | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 10 | |
| permissions: | |
| contents: read | |
| steps: | |
| - name: Check out repository | |
| uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 | |
| with: | |
| persist-credentials: false | |
| - name: Run repository validation | |
| run: python3 scripts/validate_repository.py | |
| # On pull requests, only the Markdown files the PR changed have their live external | |
| # links checked. This keeps the required PR signal fast and resilient to unrelated | |
| # third-party outages. The whole repository is swept on the weekly schedule below. | |
| changed-external-links: | |
| name: Live external links (changed files) | |
| if: github.event_name == 'pull_request' | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 30 | |
| permissions: | |
| contents: read | |
| steps: | |
| - name: Check out repository | |
| uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 | |
| with: | |
| fetch-depth: 0 | |
| persist-credentials: false | |
| - name: Check changed Markdown external links | |
| env: | |
| BASE_SHA: ${{ github.event.pull_request.base.sha }} | |
| HEAD_SHA: ${{ github.event.pull_request.head.sha }} | |
| run: | | |
| set -euo pipefail | |
| # NUL-delimited to stay correct for renamed or unusually named files. | |
| changed=() | |
| while IFS= read -r -d '' file; do | |
| changed+=("$file") | |
| done < <(git diff -z --name-only --diff-filter=ACMRT "$BASE_SHA" "$HEAD_SHA" -- '*.md') | |
| if [ ${#changed[@]} -eq 0 ]; then | |
| echo "No Markdown files changed; nothing to check." | |
| exit 0 | |
| fi | |
| echo "Checking changed Markdown files:" | |
| printf ' %s\n' "${changed[@]}" | |
| python3 scripts/check_external_links.py "${changed[@]}" | |
| # On the weekly schedule and manual runs, every tracked Markdown file is checked. | |
| # A failure opens (or updates) a tracking issue so link rot gets triaged instead of | |
| # silently failing a scheduled run nobody is watching. | |
| all-external-links: | |
| name: Live external links (full sweep) | |
| if: github.event_name == 'schedule' || github.event_name == 'workflow_dispatch' | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 30 | |
| permissions: | |
| contents: read | |
| issues: write | |
| steps: | |
| - name: Check out repository | |
| uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 | |
| with: | |
| persist-credentials: false | |
| - name: Check all external Markdown links | |
| id: check | |
| run: | | |
| set +e | |
| python3 scripts/check_external_links.py 2>&1 | tee link-report.txt | |
| echo "exit_code=${PIPESTATUS[0]}" >> "$GITHUB_OUTPUT" | |
| - name: Open or update link-rot issue on failure | |
| if: steps.check.outputs.exit_code != '0' | |
| env: | |
| GH_TOKEN: ${{ github.token }} | |
| RUN_URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }} | |
| run: | | |
| label="link-rot" | |
| title="Broken external documentation links detected" | |
| # The label is required for de-duplication; ignore the error if it exists. | |
| gh label create "$label" --color B60205 --description "Automated documentation link-rot tracking" 2>/dev/null || true | |
| # Cap the embedded report so the issue body stays well under GitHub's limit. | |
| report="$(head -c 50000 link-report.txt)" | |
| body="$(printf 'The scheduled documentation link check failed.\n\nWorkflow run: %s\n\n```\n%s\n```\n' "$RUN_URL" "$report")" | |
| existing="$(gh issue list --state open --label "$label" --json number --jq '.[0].number')" | |
| if [ -n "$existing" ]; then | |
| echo "Updating existing issue #$existing" | |
| gh issue comment "$existing" --body "$body" | |
| else | |
| echo "Opening new tracking issue" | |
| gh issue create --title "$title" --label "$label" --body "$body" | |
| fi | |
| - name: Fail if links are broken | |
| if: steps.check.outputs.exit_code != '0' | |
| run: | | |
| echo "External link check failed; see the tracking issue." >&2 | |
| exit 1 |