Switch initializr JavaScript build to local ParparVM target #321
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: Blog Prose Checks | |
| # Diff-scoped, net-new prose gate for the Hugo blog, plus a non-blocking | |
| # weekly whole-corpus report. This is the blog counterpart of | |
| # "Build Developer Guide Docs", but unlike the guide it does NOT gate the whole | |
| # corpus: the blog is 854 mostly-historical posts, so the gate fails only on | |
| # findings a PR INTRODUCES (scripts/website/blog_prose_gate.py diffs each | |
| # changed post against its merge-base version). The backlog stays grandfathered; | |
| # the weekly report job tracks it without blocking anyone. | |
| on: | |
| # Runs on EVERY pull request (no path filter) so the gate can be registered as | |
| # a required status check on the base branch without the "required check never | |
| # reports" deadlock that path-filtered workflows cause. The job itself detects | |
| # whether any blog content changed and fast-skips (passing) when none did, so | |
| # non-blog PRs stay cheap. | |
| pull_request: | |
| schedule: | |
| # Weekly whole-corpus backlog report (Mondays 06:00 UTC). Non-blocking. | |
| - cron: '0 6 * * 1' | |
| workflow_dispatch: | |
| permissions: | |
| contents: read | |
| pull-requests: write | |
| env: | |
| VALE_VERSION: '3.13.0' | |
| jobs: | |
| # --------------------------------------------------------------------------- # | |
| # PR gate — fails only on net-new findings in changed posts. | |
| # --------------------------------------------------------------------------- # | |
| gate: | |
| name: Blog prose gate | |
| if: github.event_name == 'pull_request' | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Check out repository | |
| uses: actions/checkout@v6 | |
| with: | |
| # Full history so the gate can compute the merge-base and read the | |
| # base version of each changed post. | |
| fetch-depth: 0 | |
| - name: Detect changed blog posts | |
| id: detect | |
| run: | | |
| set -euo pipefail | |
| base="origin/${GITHUB_BASE_REF}" | |
| mb="$(git merge-base "$base" HEAD 2>/dev/null || true)" | |
| if [ -z "$mb" ]; then | |
| count=0 | |
| else | |
| count="$(git diff --name-only --diff-filter=ACMR "$mb" HEAD -- 'docs/website/content/blog/*.md' | wc -l | tr -d ' ')" | |
| fi | |
| echo "Changed blog posts: $count" | |
| if [ "$count" -gt 0 ]; then | |
| echo "has_posts=true" >> "$GITHUB_OUTPUT" | |
| else | |
| echo "has_posts=false" >> "$GITHUB_OUTPUT" | |
| echo "No blog content changed — prose gate skips its heavy steps and passes." | |
| fi | |
| - name: Set up Python 3 | |
| if: steps.detect.outputs.has_posts == 'true' | |
| uses: actions/setup-python@v6 | |
| with: | |
| python-version: '3.12' | |
| - name: Install python-markdown | |
| if: steps.detect.outputs.has_posts == 'true' | |
| run: pip install --user 'markdown==3.7' | |
| - name: Install Vale | |
| if: steps.detect.outputs.has_posts == 'true' | |
| run: | | |
| set -euo pipefail | |
| ARCHIVE="vale_${VALE_VERSION}_Linux_64-bit.tar.gz" | |
| curl -fsSL -o "$ARCHIVE" "https://github.com/errata-ai/vale/releases/download/v${VALE_VERSION}/${ARCHIVE}" | |
| tar -xzf "$ARCHIVE" | |
| sudo mv vale /usr/local/bin/vale | |
| rm -f "$ARCHIVE" | |
| - name: Sync Vale styles | |
| if: steps.detect.outputs.has_posts == 'true' | |
| run: vale sync --config docs/website/.vale.ini | |
| - name: Set up Java 17 for LanguageTool | |
| if: steps.detect.outputs.has_posts == 'true' | |
| uses: actions/setup-java@v5 | |
| with: | |
| distribution: temurin | |
| java-version: '17' | |
| - name: Install language-tool-python | |
| if: steps.detect.outputs.has_posts == 'true' | |
| run: pip install --user language-tool-python==2.9.4 | |
| - name: Run net-new prose gate | |
| id: gate | |
| if: steps.detect.outputs.has_posts == 'true' | |
| run: | | |
| set -euo pipefail | |
| mkdir -p build/blog-prose | |
| set +e | |
| python3 scripts/website/blog_prose_gate.py \ | |
| --base-ref "origin/${GITHUB_BASE_REF}" \ | |
| --report build/blog-prose/net-new.json | |
| echo "status=$?" >> "$GITHUB_OUTPUT" | |
| set -e | |
| - name: Upload net-new findings report | |
| if: ${{ always() && steps.detect.outputs.has_posts == 'true' }} | |
| uses: actions/upload-artifact@v7 | |
| with: | |
| name: blog-prose-net-new | |
| path: build/blog-prose/net-new.json | |
| if-no-files-found: warn | |
| - name: Comment net-new findings on PR | |
| if: ${{ always() && steps.detect.outputs.has_posts == 'true' && !github.event.pull_request.head.repo.fork }} | |
| uses: actions/github-script@v9 | |
| with: | |
| github-token: ${{ secrets.GITHUB_TOKEN }} | |
| script: | | |
| const fs = require('fs'); | |
| const marker = '<!-- blog-prose-gate -->'; | |
| let report = { total: 0, findings: [] }; | |
| try { report = JSON.parse(fs.readFileSync('build/blog-prose/net-new.json', 'utf8')); } catch (e) {} | |
| const lines = [marker, '## Blog prose gate', '']; | |
| if (report.total === 0) { | |
| lines.push('✅ No net-new prose findings introduced by this PR.'); | |
| } else { | |
| lines.push(`❌ ${report.total} net-new prose finding(s) introduced by this PR. Pre-existing issues in the same posts are ignored.`, ''); | |
| for (const f of report.findings.slice(0, 50)) { | |
| lines.push(`- \`${f.file}:${f.line}\` — ${f.message}`); | |
| } | |
| if (report.findings.length > 50) lines.push(`- …and ${report.findings.length - 50} more (see the blog-prose-net-new artifact).`); | |
| lines.push('', 'Fix the prose, add a term to `scripts/website/languagetool-accept-blog.txt` or the CodenameOne Vale vocab, or add a `<!-- vale-skip: rule: reason -->` comment.'); | |
| } | |
| const body = lines.join('\n'); | |
| const { owner, repo } = context.repo; | |
| const issue_number = context.issue.number; | |
| const comments = await github.paginate(github.rest.issues.listComments, { owner, repo, issue_number, per_page: 100 }); | |
| const existing = comments.find(c => c.body && c.body.includes(marker)); | |
| if (existing) { | |
| await github.rest.issues.updateComment({ owner, repo, comment_id: existing.id, body }); | |
| } else { | |
| await github.rest.issues.createComment({ owner, repo, issue_number, body }); | |
| } | |
| - name: Fail on net-new findings | |
| if: always() | |
| run: | | |
| status="${{ steps.gate.outputs.status }}" | |
| if [ "${{ steps.detect.outputs.has_posts }}" != "true" ]; then | |
| echo "No blog content changed — prose gate passes." | |
| exit 0 | |
| fi | |
| if [ -n "$status" ] && [ "$status" != "0" ]; then | |
| echo "Blog prose gate found net-new findings. See the log and the blog-prose-net-new artifact." >&2 | |
| exit 1 | |
| fi | |
| echo "Blog prose gate passed." | |
| # --------------------------------------------------------------------------- # | |
| # Weekly / on-demand whole-corpus backlog report. NEVER fails the build. | |
| # --------------------------------------------------------------------------- # | |
| report: | |
| if: github.event_name == 'schedule' || github.event_name == 'workflow_dispatch' | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Check out repository | |
| uses: actions/checkout@v6 | |
| - name: Set up Python 3 | |
| uses: actions/setup-python@v6 | |
| with: | |
| python-version: '3.12' | |
| - name: Install Vale | |
| run: | | |
| set -euo pipefail | |
| ARCHIVE="vale_${VALE_VERSION}_Linux_64-bit.tar.gz" | |
| curl -fsSL -o "$ARCHIVE" "https://github.com/errata-ai/vale/releases/download/v${VALE_VERSION}/${ARCHIVE}" | |
| tar -xzf "$ARCHIVE" | |
| sudo mv vale /usr/local/bin/vale | |
| rm -f "$ARCHIVE" | |
| - name: Sync Vale styles | |
| run: vale sync --config docs/website/.vale.ini | |
| - name: Whole-corpus Vale + capitalization report | |
| run: | | |
| set -euo pipefail | |
| mkdir -p build/blog-prose | |
| vale --config docs/website/.vale.ini --minAlertLevel=suggestion --output=JSON \ | |
| docs/website/content/blog > build/blog-prose/vale-corpus.json 2>/dev/null || true | |
| python3 scripts/website/check_paragraph_capitalization.py \ | |
| --output build/blog-prose/capitalization-corpus.json \ | |
| docs/website/content/blog || true | |
| python3 - <<'PY' >> "$GITHUB_STEP_SUMMARY" | |
| import json, collections | |
| d = json.load(open('build/blog-prose/vale-corpus.json')) | |
| by_rule = collections.Counter() | |
| files = set() | |
| for f, items in d.items(): | |
| for it in items: | |
| by_rule[it['Check']] += 1; files.add(f) | |
| cap = json.load(open('build/blog-prose/capitalization-corpus.json')) | |
| print('## Blog prose backlog report\n') | |
| print(f'Vale: **{sum(by_rule.values())}** findings across **{len(files)}** posts.\n') | |
| print('| Rule | Count |\n|---|---|') | |
| for r, n in by_rule.most_common(25): | |
| print(f'| {r} | {n} |') | |
| print(f'\nParagraph capitalization: **{cap["total"]}** findings.') | |
| PY | |
| - name: Upload backlog report | |
| uses: actions/upload-artifact@v7 | |
| with: | |
| name: blog-prose-backlog-report | |
| path: build/blog-prose/ | |
| if-no-files-found: warn |