@@ -82,10 +82,43 @@ jobs:
8282 with :
8383 ruby-version : ' 3.1'
8484
85+ - name : Set up Java for docToolchain
86+ uses : actions/setup-java@v4
87+ with :
88+ distribution : temurin
89+ java-version : ' 21'
90+
8591 - name : Install Asciidoctor tooling
8692 run : |
8793 gem install --no-document asciidoctor asciidoctor-pdf
8894
95+ - name : Download docToolchain
96+ run : |
97+ set -euo pipefail
98+ DT_VERSION="3.4.2"
99+ DT_ROOT="${RUNNER_TEMP}/doctoolchain"
100+ mkdir -p "$DT_ROOT"
101+ curl -fsSL -o "$DT_ROOT/doctoolchain.zip" "https://github.com/docToolchain/docToolchain/releases/download/v${DT_VERSION}/docToolchain-${DT_VERSION}.zip"
102+ unzip -q "$DT_ROOT/doctoolchain.zip" -d "$DT_ROOT"
103+ DOC_TOOLCHAIN_HOME="$DT_ROOT/docToolchain-${DT_VERSION}"
104+ echo "DOC_TOOLCHAIN_HOME=$DOC_TOOLCHAIN_HOME" >> "$GITHUB_ENV"
105+
106+ - name : Run docToolchain AsciiDoc linter
107+ run : |
108+ set -euo pipefail
109+ REPORT_DIR="build/developer-guide/reports"
110+ REPORT_FILE="${REPORT_DIR}/asciidoc-lint-report.txt"
111+ mkdir -p "$REPORT_DIR"
112+ set +e
113+ "$DOC_TOOLCHAIN_HOME/bin/doctoolchain" docs/developer-guide asciidocLint | tee "$REPORT_FILE"
114+ STATUS=${PIPESTATUS[0]}
115+ set -e
116+ echo "ASCII_DOC_LINT_REPORT=$REPORT_FILE" >> "$GITHUB_ENV"
117+ echo "ASCII_DOC_LINT_STATUS=$STATUS" >> "$GITHUB_ENV"
118+ if [ "$STATUS" -ne 0 ]; then
119+ echo "docToolchain AsciiDoc linter exited with status $STATUS" >&2
120+ fi
121+
89122 - name : Build Developer Guide HTML and PDF
90123 run : |
91124 set -euo pipefail
@@ -135,6 +168,65 @@ jobs:
135168 rm -f "$GENERATED_COVER_SVG"
136169 fi
137170
171+ - name : Install Vale
172+ run : |
173+ set -euo pipefail
174+ VALE_VERSION="3.13.0"
175+ VALE_ARCHIVE="vale_${VALE_VERSION}_Linux_64-bit.tar.gz"
176+ curl -fsSL -o "$VALE_ARCHIVE" "https://github.com/errata-ai/vale/releases/download/v${VALE_VERSION}/${VALE_ARCHIVE}"
177+ tar -xzf "$VALE_ARCHIVE"
178+ sudo mv vale /usr/local/bin/vale
179+ rm -f "$VALE_ARCHIVE"
180+
181+ - name : Sync Vale styles
182+ run : |
183+ set -euo pipefail
184+ vale sync --config docs/developer-guide/.vale.ini
185+
186+ - name : Run Vale style linter
187+ run : |
188+ set -euo pipefail
189+ REPORT_DIR="build/developer-guide/reports"
190+ REPORT_FILE="${REPORT_DIR}/vale-report.json"
191+ mkdir -p "$REPORT_DIR"
192+ vale --config docs/developer-guide/.vale.ini --output=JSON docs/developer-guide > "$REPORT_FILE"
193+ echo "VALE_REPORT=$REPORT_FILE" >> "$GITHUB_ENV"
194+
195+ - name : Check for unused developer guide images
196+ run : |
197+ set -euo pipefail
198+ REPORT_DIR="build/developer-guide/reports"
199+ JSON_REPORT="${REPORT_DIR}/unused-images.json"
200+ TEXT_REPORT="${REPORT_DIR}/unused-images.txt"
201+ mkdir -p "$REPORT_DIR"
202+ python3 scripts/developer-guide/find_unused_images.py docs/developer-guide --output "$JSON_REPORT" | tee "$TEXT_REPORT"
203+ echo "UNUSED_IMAGES_JSON=$JSON_REPORT" >> "$GITHUB_ENV"
204+ echo "UNUSED_IMAGES_TEXT=$TEXT_REPORT" >> "$GITHUB_ENV"
205+
206+ - name : Summarize AsciiDoc linter findings
207+ id : summarize_asciidoc_lint
208+ run : |
209+ python3 scripts/developer-guide/summarize_reports.py ascii \
210+ --report "${ASCII_DOC_LINT_REPORT}" \
211+ --status "${ASCII_DOC_LINT_STATUS:-0}" \
212+ --output "${GITHUB_OUTPUT}"
213+
214+ - name : Summarize Vale findings
215+ id : summarize_vale
216+ run : |
217+ python3 scripts/developer-guide/summarize_reports.py vale \
218+ --report "${VALE_REPORT}" \
219+ --output "${GITHUB_OUTPUT}"
220+
221+ - name : Summarize unused image findings
222+ id : summarize_unused_images
223+ run : |
224+ python3 scripts/developer-guide/summarize_reports.py unused-images \
225+ --report "${UNUSED_IMAGES_JSON}" \
226+ --output "${GITHUB_OUTPUT}" \
227+ --details-key details \
228+ --preview-limit 10
229+
138230 - name : Upload HTML artifact
139231 uses : actions/upload-artifact@v4
140232 with :
@@ -149,9 +241,37 @@ jobs:
149241 path : build/developer-guide/pdf/developer-guide.pdf
150242 if-no-files-found : error
151243
244+ - name : Upload AsciiDoc linter report
245+ uses : actions/upload-artifact@v4
246+ with :
247+ name : developer-guide-asciidoc-lint
248+ path : ${{ env.ASCII_DOC_LINT_REPORT }}
249+ if-no-files-found : warn
250+
251+ - name : Upload Vale report
252+ uses : actions/upload-artifact@v4
253+ with :
254+ name : developer-guide-vale-report
255+ path : ${{ env.VALE_REPORT }}
256+ if-no-files-found : warn
257+
258+ - name : Upload unused image report
259+ uses : actions/upload-artifact@v4
260+ with :
261+ name : developer-guide-unused-images
262+ path : |
263+ ${{ env.UNUSED_IMAGES_JSON }}
264+ ${{ env.UNUSED_IMAGES_TEXT }}
265+ if-no-files-found : warn
266+
152267 - name : Comment with artifact download links
153268 if : ${{ github.event_name == 'pull_request' && !github.event.pull_request.head.repo.fork }}
154269 uses : actions/github-script@v7
270+ env :
271+ ASCII_SUMMARY : ${{ steps.summarize_asciidoc_lint.outputs.summary }}
272+ VALE_SUMMARY : ${{ steps.summarize_vale.outputs.summary }}
273+ UNUSED_SUMMARY : ${{ steps.summarize_unused_images.outputs.summary }}
274+ UNUSED_DETAILS : ${{ steps.summarize_unused_images.outputs.details }}
155275 with :
156276 github-token : ${{ secrets.GITHUB_TOKEN }}
157277 script : |
@@ -183,22 +303,76 @@ jobs:
183303 per_page: 100
184304 });
185305
186- const links = [] ;
306+ const artifactLinks = new Map() ;
187307 for (const artifact of artifacts.data.artifacts) {
188- if (artifact.name === 'developer-guide-html') {
189- links.push(`- [Developer Guide HTML package](https://github.com/${owner}/${repo}/actions/runs/${runId}/artifacts/${artifact.id})`);
190- }
191- if (artifact.name === 'developer-guide-pdf') {
192- links.push(`- [Developer Guide PDF](https://github.com/${owner}/${repo}/actions/runs/${runId}/artifacts/${artifact.id})`);
193- }
308+ artifactLinks.set(
309+ artifact.name,
310+ `https://github.com/${owner}/${repo}/actions/runs/${runId}/artifacts/${artifact.id}`
311+ );
312+ }
313+
314+ const links = [];
315+ if (artifactLinks.has('developer-guide-html')) {
316+ links.push(`- [Developer Guide HTML package](${artifactLinks.get('developer-guide-html')})`);
317+ }
318+ if (artifactLinks.has('developer-guide-pdf')) {
319+ links.push(`- [Developer Guide PDF](${artifactLinks.get('developer-guide-pdf')})`);
320+ }
321+ if (artifactLinks.has('developer-guide-asciidoc-lint')) {
322+ links.push(`- [AsciiDoc linter report](${artifactLinks.get('developer-guide-asciidoc-lint')})`);
323+ }
324+ if (artifactLinks.has('developer-guide-vale-report')) {
325+ links.push(`- [Vale report](${artifactLinks.get('developer-guide-vale-report')})`);
326+ }
327+ if (artifactLinks.has('developer-guide-unused-images')) {
328+ links.push(`- [Unused image report](${artifactLinks.get('developer-guide-unused-images')})`);
194329 }
195330
196331 if (!links.length) {
197332 console.log('No artifacts found to report.');
198333 return;
199334 }
200335
201- const body = `${marker}\nDeveloper Guide build artifacts are available for download from this workflow run:\n\n${links.join('\n')}\n`;
336+ const qualityLines = [];
337+ const asciiSummary = process.env.ASCII_SUMMARY?.trim();
338+ const valeSummary = process.env.VALE_SUMMARY?.trim();
339+ const unusedSummary = process.env.UNUSED_SUMMARY?.trim();
340+ const asciiLink = artifactLinks.get('developer-guide-asciidoc-lint');
341+ const valeLink = artifactLinks.get('developer-guide-vale-report');
342+ const unusedLink = artifactLinks.get('developer-guide-unused-images');
343+
344+ if (asciiSummary) {
345+ qualityLines.push(`- AsciiDoc linter: ${asciiSummary}${asciiLink ? ` ([report](${asciiLink}))` : ''}`);
346+ }
347+ if (valeSummary) {
348+ qualityLines.push(`- Vale: ${valeSummary}${valeLink ? ` ([report](${valeLink}))` : ''}`);
349+ }
350+ if (unusedSummary) {
351+ qualityLines.push(`- Image references: ${unusedSummary}${unusedLink ? ` ([report](${unusedLink}))` : ''}`);
352+ }
353+
354+ let unusedDetails = process.env.UNUSED_DETAILS ? process.env.UNUSED_DETAILS.split('\n') : [];
355+ unusedDetails = unusedDetails.filter(Boolean);
356+ const detailsSection = unusedDetails.length
357+ ? `\nUnused image preview:\n\n${unusedDetails.map(line => ` ${line}`).join('\n')}\n`
358+ : '';
359+
360+ const sections = [
361+ `${marker}`,
362+ 'Developer Guide build artifacts are available for download from this workflow run:',
363+ '',
364+ links.join('\n')
365+ ];
366+
367+ if (qualityLines.length) {
368+ sections.push('', 'Developer Guide quality checks:', '', qualityLines.join('\n'));
369+ }
370+
371+ if (detailsSection) {
372+ sections.push(detailsSection.trimEnd());
373+ }
374+
375+ const body = sections.join('\n') + '\n';
202376 const comments = await github.rest.issues.listComments({
203377 owner,
204378 repo,
0 commit comments