|
1 | | -name: Code Quality |
2 | | - |
3 | | -permissions: |
4 | | - contents: read |
| 1 | +name: Docs Quality |
5 | 2 |
|
6 | 3 | on: |
7 | | - push: |
8 | | - branches: [main] |
9 | 4 | pull_request: |
10 | | - branches: [main] |
| 5 | + workflow_dispatch: |
| 6 | + inputs: |
| 7 | + allow_failure: |
| 8 | + type: boolean |
| 9 | + default: false |
| 10 | + |
| 11 | +env: |
| 12 | + ALLOW_FAILURE: ${{ github.event_name == 'workflow_dispatch' && inputs.allow_failure }} |
11 | 13 |
|
12 | 14 | jobs: |
13 | | - code-quality: |
14 | | - name: Code Quality |
| 15 | + spelling: |
15 | 16 | runs-on: ubuntu-latest |
16 | | - |
17 | 17 | steps: |
18 | | - - uses: actions/checkout@v7 |
19 | | - |
20 | | - - name: Setup Node.js |
21 | | - uses: actions/setup-node@v6 |
| 18 | + - uses: actions/checkout@v6 |
| 19 | + - uses: actions/setup-node@v4 |
22 | 20 | with: |
23 | | - node-version: latest |
24 | | - |
25 | | - - name: Install pnpm |
26 | | - uses: pnpm/action-setup@v6 |
| 21 | + node-version: "20" |
| 22 | + - uses: actions/cache@v4 |
27 | 23 | with: |
28 | | - version: latest |
| 24 | + path: ~/.npm |
| 25 | + key: ${{ runner.os }}-npm-cspell |
| 26 | + restore-keys: ${{ runner.os }}-npm-cspell- |
| 27 | + - run: | |
| 28 | + npx --yes -p cspell@9 -p @cspell/cspell-json-reporter cspell lint \ |
| 29 | + "docs/**/*.{md,mdx}" \ |
| 30 | + "src/pages/**/*.{md,mdx}" \ |
| 31 | + --config cspell.json \ |
| 32 | + --no-progress \ |
| 33 | + --reporter "@cspell/cspell-json-reporter" \ |
| 34 | + > cspell-report.json || true |
| 35 | + - run: | |
| 36 | + python - <<'PY' |
| 37 | + import json |
| 38 | + import os |
| 39 | + import sys |
29 | 40 |
|
30 | | - - name: Setup pnpm config |
31 | | - run: | |
32 | | - pnpm config set store-dir ~/.pnpm-store |
| 41 | + try: |
| 42 | + with open("cspell-report.json", encoding="utf-8") as f: |
| 43 | + content = f.read().strip() |
| 44 | + except FileNotFoundError: |
| 45 | + content = "" |
33 | 46 |
|
34 | | - - uses: actions/cache@v6 |
35 | | - name: Setup pnpm cache |
36 | | - with: |
37 | | - path: ~/.pnpm-store |
38 | | - key: ${{ runner.os }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }} |
39 | | - restore-keys: | |
40 | | - ${{ runner.os }}-pnpm-store- |
| 47 | + if not content: |
| 48 | + print("::error::cspell-report.json is empty. Check the previous step's log for the actual cspell error (e.g. missing cspell.json or project-words.txt).") |
| 49 | + sys.exit(1) |
| 50 | +
|
| 51 | + try: |
| 52 | + data = json.loads(content) |
| 53 | + except json.JSONDecodeError: |
| 54 | + print("::error::cspell-report.json is not valid JSON. Raw output was:") |
| 55 | + print(content[:2000]) |
| 56 | + sys.exit(1) |
| 57 | +
|
| 58 | + issues = data.get("issues", []) |
| 59 | + for issue in issues: |
| 60 | + file = issue.get("uri") |
| 61 | + line = issue.get("row") |
| 62 | + message = issue.get("message") or f"Unknown word: {issue.get('text')!r}" |
| 63 | + print(f"::error file={file},line={line}::{message}") |
41 | 64 |
|
42 | | - - name: Install dependencies |
43 | | - run: pnpm install |
| 65 | + print(f"{len(issues)} spelling issue(s) found.") |
44 | 66 |
|
45 | | - - name: Check Prettier formatting |
46 | | - run: pnpm format --check |
| 67 | + allow_failure = os.environ.get("ALLOW_FAILURE") == "true" |
| 68 | + sys.exit(1 if issues and not allow_failure else 0) |
| 69 | + PY |
47 | 70 |
|
48 | | - - name: Run ESLint and Stylelint |
49 | | - run: pnpm lint |
| 71 | + heading-case: |
| 72 | + runs-on: ubuntu-latest |
| 73 | + steps: |
| 74 | + - uses: actions/checkout@v6 |
| 75 | + - run: | |
| 76 | + python check_heading_case.py docs src/pages || { |
| 77 | + if [ "$ALLOW_FAILURE" = "true" ]; then |
| 78 | + exit 0 |
| 79 | + fi |
| 80 | + exit 1 |
| 81 | + } |
0 commit comments