Skip to content

Commit 8f13bbb

Browse files
authored
Merge pull request #27 from cakephp/doc-workflows
Introduce reusable docs workflow
2 parents 904acb8 + fca7cce commit 8f13bbb

File tree

6 files changed

+1117
-0
lines changed

6 files changed

+1117
-0
lines changed
Lines changed: 249 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,249 @@
1+
name: Reusable Documentation Validation
2+
3+
on:
4+
workflow_call:
5+
inputs:
6+
docs-path:
7+
description: 'Path to the docs directory (e.g. "docs")'
8+
required: false
9+
type: string
10+
default: 'docs'
11+
vitepress-path:
12+
description: 'Path to the .vitepress directory (e.g. ".vitepress" or "docs/.vitepress")'
13+
required: false
14+
type: string
15+
default: '.vitepress'
16+
enable-toc-check:
17+
description: 'Enable TOC link validation (requires .vitepress/toc_*.json)'
18+
required: false
19+
type: boolean
20+
default: false
21+
enable-config-js-check:
22+
description: 'Enable .vitepress/config.js syntax check'
23+
required: false
24+
type: boolean
25+
default: false
26+
enable-json-lint:
27+
description: 'Enable TOC JSON file validation'
28+
required: false
29+
type: boolean
30+
default: false
31+
enable-spell-check:
32+
description: 'Enable spell checking'
33+
required: false
34+
type: boolean
35+
default: true
36+
enable-markdown-lint:
37+
description: 'Enable markdown linting'
38+
required: false
39+
type: boolean
40+
default: true
41+
enable-link-check:
42+
description: 'Enable internal link checking'
43+
required: false
44+
type: boolean
45+
default: true
46+
cspell-config:
47+
description: 'Path to cspell config file (relative to caller repo). Leave empty to use shared default.'
48+
required: false
49+
type: string
50+
default: ''
51+
markdownlint-config:
52+
description: 'Path to markdownlint config file (relative to caller repo). Leave empty to use shared default.'
53+
required: false
54+
type: string
55+
default: ''
56+
linkchecker-baseline:
57+
description: 'Path to link checker baseline JSON (relative to caller repo). Leave empty for no baseline.'
58+
required: false
59+
type: string
60+
default: ''
61+
tools-ref:
62+
description: 'Branch/tag of cakephp/.github to use for shared validation tools and default configs'
63+
required: false
64+
type: string
65+
default: 'main'
66+
67+
jobs:
68+
js-lint:
69+
name: Validate config.js
70+
runs-on: ubuntu-latest
71+
if: ${{ inputs.enable-config-js-check }}
72+
steps:
73+
- name: Checkout code
74+
uses: actions/checkout@v6
75+
76+
- name: Validate config.js syntax
77+
run: node --check "${{ inputs.vitepress-path }}/config.js"
78+
79+
json-lint:
80+
name: Validate JSON Files
81+
runs-on: ubuntu-latest
82+
if: ${{ inputs.enable-json-lint }}
83+
steps:
84+
- name: Checkout code
85+
uses: actions/checkout@v6
86+
87+
- name: Validate JSON syntax
88+
run: |
89+
shopt -s nullglob
90+
files=("${{ inputs.vitepress-path }}"/toc_*.json)
91+
if [ ${#files[@]} -eq 0 ]; then
92+
echo "No ${{ inputs.vitepress-path }}/toc_*.json files found"
93+
exit 1
94+
fi
95+
for file in "${files[@]}"; do
96+
if ! jq empty "$file" 2>/dev/null; then
97+
echo "Invalid JSON: $file"
98+
exit 1
99+
fi
100+
echo "Valid: $file"
101+
done
102+
103+
toc-link-check:
104+
name: Validate TOC Links
105+
runs-on: ubuntu-latest
106+
if: ${{ inputs.enable-toc-check }}
107+
steps:
108+
- name: Checkout code
109+
uses: actions/checkout@v6
110+
111+
- name: Checkout shared validation tools
112+
uses: actions/checkout@v6
113+
with:
114+
repository: cakephp/.github
115+
ref: ${{ inputs.tools-ref }}
116+
path: .docs-tools
117+
sparse-checkout: |
118+
docs-validation/check-toc-links.cjs
119+
120+
- name: Check TOC links exist
121+
run: node .docs-tools/docs-validation/check-toc-links.cjs --vitepress-path "${{ inputs.vitepress-path }}" --docs-path "${{ inputs.docs-path }}"
122+
123+
markdown-lint:
124+
name: Lint Markdown
125+
runs-on: ubuntu-latest
126+
if: ${{ inputs.enable-markdown-lint }}
127+
steps:
128+
- name: Checkout code
129+
uses: actions/checkout@v6
130+
131+
- name: Checkout shared validation tools
132+
uses: actions/checkout@v6
133+
with:
134+
repository: cakephp/.github
135+
ref: ${{ inputs.tools-ref }}
136+
path: .docs-tools
137+
sparse-checkout: |
138+
docs-validation/.markdownlint-cli2.jsonc
139+
docs-validation/markdownlint-rules
140+
141+
- name: Determine config path
142+
id: config
143+
run: |
144+
if [ -n "${{ inputs.markdownlint-config }}" ]; then
145+
if [ -f "${{ inputs.markdownlint-config }}" ]; then
146+
echo "path=${{ inputs.markdownlint-config }}" >> $GITHUB_OUTPUT
147+
else
148+
echo "Error: markdownlint config '${{ inputs.markdownlint-config }}' does not exist." >&2
149+
exit 1
150+
fi
151+
else
152+
echo "path=.docs-tools/docs-validation/.markdownlint-cli2.jsonc" >> $GITHUB_OUTPUT
153+
fi
154+
155+
- name: Lint markdown files
156+
uses: DavidAnson/markdownlint-cli2-action@v23
157+
with:
158+
config: ${{ steps.config.outputs.path }}
159+
globs: '${{ inputs.docs-path }}/**/*.md'
160+
161+
spell-check:
162+
name: Spell Check
163+
runs-on: ubuntu-latest
164+
if: ${{ inputs.enable-spell-check }}
165+
steps:
166+
- name: Checkout code
167+
uses: actions/checkout@v6
168+
169+
- name: Checkout shared validation tools
170+
uses: actions/checkout@v6
171+
with:
172+
repository: cakephp/.github
173+
ref: ${{ inputs.tools-ref }}
174+
path: .docs-tools
175+
sparse-checkout: |
176+
docs-validation/cspell.json
177+
178+
- name: Determine config path
179+
id: config
180+
run: |
181+
if [ -n "${{ inputs.cspell-config }}" ]; then
182+
if [ -f "${{ inputs.cspell-config }}" ]; then
183+
echo "path=${{ inputs.cspell-config }}" >> $GITHUB_OUTPUT
184+
else
185+
echo "Error: cspell config '${{ inputs.cspell-config }}' does not exist." >&2
186+
exit 1
187+
fi
188+
else
189+
echo "path=.docs-tools/docs-validation/cspell.json" >> $GITHUB_OUTPUT
190+
fi
191+
192+
- name: Check spelling
193+
uses: streetsidesoftware/cspell-action@v8
194+
with:
195+
files: '${{ inputs.docs-path }}/**/*.md'
196+
config: ${{ steps.config.outputs.path }}
197+
incremental_files_only: true
198+
199+
link-check:
200+
name: Check Internal Links
201+
runs-on: ubuntu-latest
202+
if: ${{ inputs.enable-link-check }}
203+
steps:
204+
- name: Checkout code
205+
uses: actions/checkout@v6
206+
with:
207+
fetch-depth: 0
208+
209+
- name: Checkout shared validation tools
210+
uses: actions/checkout@v6
211+
with:
212+
repository: cakephp/.github
213+
ref: ${{ inputs.tools-ref }}
214+
path: .docs-tools
215+
sparse-checkout: |
216+
docs-validation/check-links.cjs
217+
218+
- name: Get changed markdown files
219+
id: changed-files
220+
run: |
221+
DOCS_PATH="${{ inputs.docs-path }}"
222+
if [ "${{ github.event_name }}" == "pull_request" ]; then
223+
BASE_SHA="${{ github.event.pull_request.base.sha }}"
224+
if [ -z "$BASE_SHA" ]; then
225+
git fetch origin "${{ github.base_ref }}" --depth=1 2>/dev/null || true
226+
BASE_SHA="origin/${{ github.base_ref }}"
227+
fi
228+
FILES=$(git diff --name-only --diff-filter=d "${BASE_SHA}"...HEAD | grep "^${DOCS_PATH}/.*\.md$" || true)
229+
if [ -z "$FILES" ]; then
230+
echo "No markdown files changed in ${DOCS_PATH}/"
231+
echo "files=" >> $GITHUB_OUTPUT
232+
else
233+
echo "files=$(echo $FILES | tr '\n' ' ')" >> $GITHUB_OUTPUT
234+
echo "Checking files:"
235+
echo "$FILES"
236+
fi
237+
else
238+
echo "files=${DOCS_PATH}/**/*.md" >> $GITHUB_OUTPUT
239+
echo "Checking all files: ${DOCS_PATH}/**/*.md"
240+
fi
241+
242+
- name: Check internal links
243+
if: steps.changed-files.outputs.files != ''
244+
run: |
245+
BASELINE_ARG=""
246+
if [ -n "${{ inputs.linkchecker-baseline }}" ] && [ -f "${{ inputs.linkchecker-baseline }}" ]; then
247+
BASELINE_ARG="--baseline ${{ inputs.linkchecker-baseline }}"
248+
fi
249+
node .docs-tools/docs-validation/check-links.cjs $BASELINE_ARG ${{ steps.changed-files.outputs.files }}
Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
{
2+
"config": {
3+
"default": true,
4+
"heading-increment": true,
5+
"no-hard-tabs": true,
6+
"no-multiple-blanks": true,
7+
"line-length": false,
8+
"commands-show-output": true,
9+
"blanks-around-headings": true,
10+
"heading-start-left": true,
11+
"no-duplicate-heading": false,
12+
"single-h1": false,
13+
"no-trailing-punctuation": false,
14+
"no-blanks-blockquote": false,
15+
"list-marker-space": true,
16+
"blanks-around-fences": true,
17+
"blanks-around-lists": true,
18+
"no-inline-html": {
19+
"allowed_elements": [
20+
"Badge",
21+
"div",
22+
"span",
23+
"br",
24+
"style",
25+
"details",
26+
"summary",
27+
"table",
28+
"thead",
29+
"tbody",
30+
"tr",
31+
"th",
32+
"td",
33+
"img",
34+
"a",
35+
"svg",
36+
"path",
37+
"figure",
38+
"p",
39+
"colgroup",
40+
"col",
41+
"strong",
42+
"sup",
43+
"section",
44+
"hr",
45+
"ol",
46+
"ul",
47+
"li",
48+
"em",
49+
"code"
50+
]
51+
},
52+
"no-bare-urls": true,
53+
"fenced-code-language": true,
54+
"first-line-heading": false,
55+
"code-block-style": false,
56+
"code-fence-style": {
57+
"style": "backtick"
58+
},
59+
"emphasis-style": {
60+
"style": "asterisk"
61+
},
62+
"strong-style": {
63+
"style": "asterisk"
64+
},
65+
"spaces-after-emphasis-marker": true,
66+
"spaces-after-code-fence-info": true,
67+
"spaces-inside-emphasis-markers": true,
68+
"spaces-inside-code-span-elements": true,
69+
"single-trailing-newline": true,
70+
"link-fragments": false,
71+
"table-pipe-style": "leading_and_trailing",
72+
"table-column-count": false,
73+
"table-column-style": false,
74+
"descriptive-link-text": false,
75+
"no-emphasis-as-heading": false
76+
},
77+
"customRules": [
78+
"./markdownlint-rules/no-space-after-fence.cjs"
79+
],
80+
"ignores": [
81+
"node_modules/**"
82+
]
83+
}

0 commit comments

Comments
 (0)