Skip to content

CI - Structured data validation #11

CI - Structured data validation

CI - Structured data validation #11

name: CI - Structured data validation
on:
workflow_call: {}
# Allow nightly runs on `main` so regressions in already-merged content
# don't go undetected for a full release cycle.
schedule:
- cron: '0 8 * * *'
permissions:
contents: read
pull-requests: write # required to post / update the sticky PR comment
concurrency:
group: structured-data-${{ github.event.pull_request.number || github.ref }}
cancel-in-progress: true
# Opt into Node 24 for bundled-JS actions ahead of GitHub's June 16, 2026 cutoff.
# https://github.blog/changelog/2025-09-19-deprecation-of-node-20-on-github-actions-runners/
env:
FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: 'true'
jobs:
validate:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
with:
# The PR-incremental mode needs git history to diff against origin/main.
fetch-depth: 0
- name: Setup Node.js
uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0
with:
cache: npm
- name: Docusaurus Cache
uses: actions/cache@5a3ec84eff668545956fd18022155c47e93e2684 # v4.2.3
with:
path: node_modules/.cache
key: ${{ runner.os }}-docusaurus-${{ hashFiles('**/package-lock.json') }}-${{ github.sha }}
restore-keys: |
${{ runner.os }}-docusaurus-${{ hashFiles('**/package-lock.json') }}-
${{ runner.os }}-docusaurus-
- name: Install
run: npm install
- name: Build
run: npm run build
- name: Validate structured data (PR incremental)
if: github.event_name == 'pull_request'
run: |
node scripts/validate-structured-data.mjs \
--pr origin/${{ github.event.pull_request.base.ref }} \
--json-summary /tmp/structured-data-summary.json
- name: Validate structured data (full sweep)
if: github.event_name != 'pull_request'
run: |
node scripts/validate-structured-data.mjs \
--json-summary /tmp/structured-data-summary.json
# Sticky PR comment summarizing errors + warnings, edited in place
# on every push so the PR thread doesn't bloat. Skipped on non-PR runs.
- name: Compose PR comment body
if: github.event_name == 'pull_request' && always()
id: compose
run: |
node - <<'NODE'
const fs = require('fs');
const path = '/tmp/structured-data-summary.json';
const out = '/tmp/comment-body.md';
if (!fs.existsSync(path)) {
fs.writeFileSync(out, '⚠️ Structured-data validator did not run. The build may have failed before validation started — check the workflow logs.\n');
process.exit(0);
}
const s = JSON.parse(fs.readFileSync(path, 'utf8'));
const mode = s.mode === 'pr' ? `PR-incremental (base: \`${s.base_ref}\`)` : 'full sweep';
let body = `### 🔎 Structured data validation\n\n`;
body += `- **Mode:** ${mode}\n`;
body += `- **Files checked:** ${s.files_checked}\n`;
body += `- **JSON-LD payloads:** ${s.payloads_checked}\n`;
body += `- **Errors:** ${s.error_count}\n`;
body += `- **Warnings:** ${s.warning_count}\n\n`;
if (s.error_count > 0) {
body += `#### ❌ Errors by kind\n\n`;
body += `| Kind | Count |\n|---|---:|\n`;
for (const e of s.errors_by_kind.slice(0, 15)) {
body += `| \`${e.kind.replace(/\|/g, '\\|')}\` | ${e.count} |\n`;
}
if (s.sample_errors.length > 0) {
body += `\n<details><summary>Sample errors (up to 20)</summary>\n\n`;
for (const e of s.sample_errors) body += `- \`${e}\`\n`;
body += `\n</details>\n\n`;
}
}
if (s.warning_count > 0) {
body += `#### ⚠️ Warnings by kind\n\n`;
body += `| Kind | Count |\n|---|---:|\n`;
for (const w of s.warnings_by_kind.slice(0, 15)) {
body += `| \`${w.kind.replace(/\|/g, '\\|')}\` | ${w.count} |\n`;
}
body += `\n_Warnings don't fail the build — they surface authoring gaps that should be backfilled when convenient (typically missing M12 \`about\`/\`mentions\` entity refs)._\n\n`;
}
if (s.error_count === 0 && s.warning_count === 0) {
body += `✅ All checks pass and no authoring warnings to backfill.\n`;
}
body += `\n<sub>⚙️ Generated by [\`ci_structured_data.yml\`](https://github.com/wasmCloud/wasmcloud.com/blob/main/.github/workflows/ci_structured_data.yml) • [structured-data spike](https://github.com/wasmCloud/community-meetings/blob/main/2026-6-wasmcloud.com-structured-data-spike.md)</sub>\n`;
fs.writeFileSync(out, body);
NODE
- name: Post / update sticky PR comment
# Skip on fork-originated PRs: GitHub issues a read-only GITHUB_TOKEN
# for fork-PR workflows, so marocchino/sticky-pull-request-comment
# fails with "Resource not accessible by integration" — which would
# then red-X the structured-data check even when validation itself
# passed. Same-repo PRs continue to post and edit the sticky comment.
if: |
always()
&& github.event_name == 'pull_request'
&& github.event.pull_request.head.repo.full_name == github.repository
uses: marocchino/sticky-pull-request-comment@52423e01640425a022ef5fd42c6fb5f633a02728 # v2.9.1
with:
header: structured-data-validation
path: /tmp/comment-body.md