11name : Docs Quality
2+
23on :
34 pull_request :
4- workflow_dispatch :
5+ paths :
6+ - " docs/**/*.md"
7+ - " docs/**/*.mdx"
8+ - " _typos.toml"
9+ - " .github/workflows/docs-quality.yml"
10+ push :
11+ branches : [main]
12+ workflow_dispatch : {}
13+
14+ permissions :
15+ contents : read
16+
517jobs :
618 typos :
719 name : Spelling (typos-cli)
820 runs-on : ubuntu-latest
921 steps :
10- - name : Checkout
11- uses : actions/checkout@v6
22+ - uses : actions/checkout@v4
1223 - uses : crate-ci/typos@master
1324
1425 harper :
15- name : Grammar and Style Check
26+ name : Grammar & headings (Harper)
1627 runs-on : ubuntu-latest
1728 continue-on-error : true
1829 steps :
19- - name : Checkout
20- uses : actions/checkout@v6
21- - name : Restore Harper CLI cache
30+ - uses : actions/checkout@v4
31+
32+ - name : Cache harper-cli binary
2233 id : cache-harper
23- uses : actions/cache/restore @v4
34+ uses : actions/cache@v4
2435 with :
25- path : |
26- ~/.cargo/bin/harper-cli
27- ~/.cargo/registry
28- ~/.cargo/git
29- key : ${{ runner.os }}-harper-cli
36+ path : ~/.cargo/bin/harper-cli
37+ key : harper-cli-${{ runner.os }}-v1
3038 restore-keys : |
31- ${{ runner.os }}-harper-cli
39+ harper-cli- ${{ runner.os }}-
3240 - name : Report cache status
3341 run : |
3442 echo "cache-hit output: '${{ steps.cache-harper.outputs.cache-hit }}'"
35- ls -la ~/.cargo/bin/ 2>&1 || echo "~/.cargo/bin does not exist"
36- if [ -x ~/.cargo/bin/harper-cli ]; then
37- echo "RESULT: harper-cli binary present and executable"
38- ~/.cargo/bin/harper-cli --version || true
43+ if [ -f ~/.cargo/bin/harper-cli ]; then
44+ echo "harper-cli binary present at ~/.cargo/bin/harper-cli"
3945 else
40- echo "RESULT: harper-cli binary NOT present -- full reinstall will run "
46+ echo "harper-cli binary NOT present -- will build from source "
4147 fi
42- - name : Install Harper CLI
48+ - name : Install harper-cli
4349 if : steps.cache-harper.outputs.cache-hit != 'true'
4450 run : cargo install --locked --git https://github.com/Automattic/harper.git harper-cli
45- - name : Lint docs with Harper
46- run : |
47- set -uo pipefail
48- ONLY_RULES=(
49- UseTitleCase
50- RepeatedWords
51- )
52- ONLY_ARG="--only $(IFS=,; echo "${ONLY_RULES[*]}")"
53- out="$(mktemp)"
54- total=0
55- bad=0
56- while IFS= read -r -d '' file; do
57- total=$((total+1))
58- echo "::group::$file"
59- if harper_out="$(harper-cli lint $ONLY_ARG "$file" 2>&1)"; then
60- echo "no issues"
61- else
62- bad=$((bad+1))
63- echo "$harper_out"
64- echo "$harper_out" >> "$out"
65- fi
66- echo "::endgroup::"
67- done < <(
68- find docs src/pages \
69- -type f \( -name "*.md" -o -name "*.mdx" \) \
70- -print0 2>/dev/null
71- )
72- {
73- echo "### Harper summary"
74- echo "- Files scanned: $total"
75- echo "- Files with issues: $bad"
76- echo ""
77- echo "### Violations by rule"
78- echo '```'
79- grep -oE '\[[A-Za-z]+::[A-Za-z]+\]' "$out" | sort | uniq -c | sort -rn || true
80- echo '```'
81- } >> "$GITHUB_STEP_SUMMARY"
8251
83- echo "== Harper: $bad/$total files with issues =="
84- [ "$bad" -eq 0 ]
85-
86- - name : Annotate PR with Harper warnings
87- if : always()
52+ - name : Lint docs with Harper
8853 run : |
8954 set -uo pipefail
90- ONLY_RULES=(
91- UseTitleCase
92- RepeatedWords
93- )
94- ONLY_ARG="--only $(IFS=,; echo "${ONLY_RULES[*]}")"
95- while IFS= read -r -d '' file; do
96- if json_out="$(harper-cli lint $ONLY_ARG --format json "$file" 2>/dev/null)"; then
97- :
98- else
99- printf '%s' "$json_out" | python3 -c "import json,sys;d=json.load(sys.stdin);esc=lambda s: s.replace('%','%25').replace('\r','%0D').replace('\n','%0A');[print('::warning file='+esc(f.get('file',''))+',line='+str(l.get('line',1))+',col='+str(l.get('column',1))+',title='+esc(l.get('rule','?'))+'::'+esc(l.get('message',''))) for f in d for l in f.get('lints',[])]" || true
100- fi
101- done < <(
102- find docs src/pages \
103- -type f \( -name "*.md" -o -name "*.mdx" \) \
104- -print0 2>/dev/null
105- )
106-
107- - name : Save Harper CLI cache
108- if : always() && steps.cache-harper.outputs.cache-hit != 'true'
109- uses : actions/cache/save@v4
110- with :
111- path : |
112- ~/.cargo/bin/harper-cli
113- ~/.cargo/registry
114- ~/.cargo/git
115- key : ${{ runner.os }}-harper-cli CompaniesProductsAndTrademarks
55+ IGNORED_RULES=(
56+ SpellCheck
57+ OrthographicConsistency
58+ ProperNouns
59+ CompaniesProductsAndTrademarks
11660 GoogleNames MicrosoftNames AmazonNames AzureNames MetaNames
11761 LongSentences Hedging FillerWords
11862 ExpandStandardInputAndOutput ExpandTimeShorthands ExpandMemoryShorthands
12266 )
12367 IGNORE_ARGS=()
12468 for r in "${IGNORED_RULES[@]}"; do IGNORE_ARGS+=(--ignore "$r"); done
125-
12669 out="$(mktemp)"
12770 total=0
12871 bad=0
13679 fi
13780 echo "::endgroup::"
13881 done < <(find docs \( -name '*.md' -o -name '*.mdx' \) -print0)
139-
14082 titlecase=$(grep -c 'Capitalization::UseTitleCase' "$out" || true)
14183 {
14284 echo "### Harper summary"
@@ -150,89 +92,4 @@ jobs:
15092 echo '```'
15193 } >> "$GITHUB_STEP_SUMMARY"
15294 echo "== Harper: $bad/$total files with issues; $titlecase UseTitleCase violations =="
153- [ "$bad" -eq 0 ] else
154- bad=$((bad+1))
155- fi
156- echo "::endgroup::"
157- done < <(
158- find docs src/pages \
159- -type f \( -name "*.md" -o -name "*.mdx" \) \
160- -print0 2>/dev/null
161- )
162- titlecase=$(grep -c 'Capitalization::UseTitleCase' "$out" || true)
163- {
164- echo "### Harper summary"
165- echo "- Files scanned : $total"
166- echo "- Files with issues : $bad"
167- echo "- Heading title case violations : $titlecase"
168- echo ""
169- echo "### Violations by rule"
170- echo '```'
171- grep -oE '\[[A-Za-z]+::[A-Za-z]+\]' "$out" | sort | uniq -c | sort -rn || true
172- echo '```'
173- } >> "$GITHUB_STEP_SUMMARY"
174- echo "== Harper : $bad/$total files with issues; $titlecase UseTitleCase violations =="
175- [ "$bad" -eq 0 ] ExpandMemoryShorthands
176- ExpandDirectory
177- AnA
178- NoFrenchSpaces
179- InflectedVerbAfterTo
180- CapitalizePersonalPronouns
181- Dashes
182- )
183- IGNORE_ARGS=()
184- for rule in "${IGNORED_RULES[@]}"; do
185- IGNORE_ARGS+=(--ignore "$rule")
186- done
187- out="$(mktemp)"
188- total=0
189- bad=0
190- while IFS= read -r -d '' file; do
191- total=$((total+1))
192- echo "::group::$file"
193- if harper-cli lint "${IGNORE_ARGS[@]}" "$file" 2>&1 | tee -a "$out"; then
194- :
195- else
196- bad=$((bad+1))
197- fi
198- echo "::endgroup::"
199- done < <(
200- find docs src/pages \
201- -type f \( -name "*.md" -o -name "*.mdx" \) \
202- -print0 2>/dev/null
203- )
204- titlecase=$(grep -c 'Capitalization::UseTitleCase' "$out" || true)
205- {
206- echo "### Harper summary"
207- echo "- Files scanned : $total"
208- echo "- Files with issues : $bad"
209- echo "- Heading title case violations : $titlecase"
210- echo ""
211- echo "### Violations by rule"
212- echo '```'
213- grep -oE '\[[A-Za-z]+::[A-Za-z]+\]' "$out" | sort | uniq -c | sort -rn || true
214- echo '```'
215- } >> "$GITHUB_STEP_SUMMARY"
216- echo "== Harper : $bad/$total files with issues; $titlecase UseTitleCase violations =="
21795 [ "$bad" -eq 0 ]
218-
219- - name : Annotate PR with Harper warnings
220- if : always()
221- run : |
222- set -uo pipefail
223- ONLY_RULES=(
224- UseTitleCase
225- RepeatedWords
226- )
227- ONLY_ARG="--only $(IFS=,; echo "${ONLY_RULES[*]}")"
228- while IFS= read -r -d '' file; do
229- if json_out="$(harper-cli lint $ONLY_ARG --format json "$file" 2>/dev/null)"; then
230- :
231- else
232- printf '%s' "$json_out" | python3 -c "import json,sys;d=json.load(sys.stdin);esc=lambda s: s.replace('%','%25').replace('\r','%0D').replace('\n','%0A');[print('::warning file='+esc(f.get('file',''))+',line='+str(l.get('line',1))+',col='+str(l.get('column',1))+',title='+esc(l.get('rule','?'))+'::'+esc(l.get('message',''))) for f in d for l in f.get('lints',[])]" || true
233- fi
234- done < <(
235- find docs src/pages \
236- -type f \( -name "*.md" -o -name "*.mdx" \) \
237- -print0 2>/dev/null
238- )
0 commit comments