Skip to content

ci: add link check and changelog sync, harden Mintlify workflow - #2

Merged
AdamXweb merged 4 commits into
mainfrom
fix/linkcheck-changelog-sync
Aug 9, 2026
Merged

ci: add link check and changelog sync, harden Mintlify workflow#2
AdamXweb merged 4 commits into
mainfrom
fix/linkcheck-changelog-sync

Conversation

@adamXbot

@adamXbot adamXbot commented Aug 6, 2026

Copy link
Copy Markdown
Collaborator

Root cause

This docs repo was missing the two CI workflows its siblings share: no link checking beyond mint broken-links on PRs (so external-link rot went unnoticed between PRs), and no changelog sync (so the docs never surfaced product releases at all — there was no changelog page). The intended canonical source, privacykey/docs-privacytracker, turned out to be an empty repo (zero refs), so the workflows were taken from the other sibling, privacykey/docs-privacysentinel, which carries the same canonical versions.

What changed

New: .github/workflows/linkcheck.yml — same shape as the sibling: npm run check (navigation, internal links, anchors, assets, frontmatter) then cached lychee for external links, on PR/push/weekly cron/manual dispatch, and the scheduled run auto-files an issue on breakage via peter-evans/create-issue-from-file.

One deviation from the sibling's args, found when this PR's first CI run failed: the canonical file passes --base ., which current lychee releases reject outright (Base must either be a full URL (with scheme) or an absolute local path) — the siblings' scheduled runs are hitting the same error. Since internal links and anchors are already covered by npm run check, lychee here is scoped to external links only (--scheme https --scheme http), with --root-dir ${{ github.workspace }} so root-relative links like /updating resolve instead of erroring before the scheme filter excludes them. Verified against lychee 0.24.2 locally (34 external links OK, 0 errors) and green in this PR's CI. The siblings should pick up the same fix.

New: .github/workflows/sync-changelog.yml — daily 12:00 UTC cron (same as sibling): check → regenerate changelog.mdx → re-check → peter-evans/create-pull-request opens a PR only when the file moved.

New: scripts/check-docs.mjs — ported from the sibling with three generic adaptations:

  • nav page slugs resolve to .md as well as .mdx (this repo's pages are mostly .md);
  • navigation.groups (this repo's docs.json shape, incl. group root) is walked in addition to the sibling's navigation.tabs[].groups[];
  • inline code spans are excluded from link scanning — this repo's format-spec tables contain ![](URL) / <img src="..."> syntax examples that false-positived otherwise.

New: scripts/sync-changelog.mjs — the sibling reads its product repo's releases.json via a raw.githubusercontent.com URL. Mantis has no releases.json — its release manifest is GitHub Releases on privacykey/mantis (cli-v* tags = CLI, plain v* tags = server, exactly as /updating documents), so the script reads the Releases API instead, keeping the sibling's MANIFEST_URL / MANIFEST_FILE override mechanism. Tag prefix becomes the component label, published date the date line, and the first prose paragraph of the release body the summary.

New: changelog.mdx + docs.json nav entry (Reference group, after Updating) — generated by running the script, committed now so the nav check passes from the first run. Regeneration is idempotent (verified: second run reports "already up to date").

Hardened: .github/workflows/mintlify.yml — top-level permissions: contents: read, concurrency group with cancel-in-progress, timeout-minutes: 15, persist-credentials: false on the checkout. The two new workflows carry the same baseline (top-level read-only permissions with job-level elevation where needed, timeouts, persist-credentials: false on the non-pushing linkcheck checkout).

Required setup: none. The sibling's sync needs no secret (public raw fetch) and neither does this one — the workflow passes the built-in GITHUB_TOKEN to the Releases API call purely to avoid runner-IP rate limits. Note: GITHUB_TOKEN-created PRs don't trigger other GITHUB_TOKEN-driven workflows, so checks won't auto-run on the sync bot's PRs; if the org later wants that, a PAT in the create-pull-request token input is the standard upgrade — same caveat applies to the siblings.

How to verify

  • CI on this PR: both checks are green — the Mintlify workflow (mint validate + mint broken-links on node 22, validating the new changelog.mdx and nav entry) and the new Link check workflow (npm run check + lychee external sweep).
  • Locally: npm run check (passes: 32 linked files), then GITHUB_TOKEN=$(gh auth token) npm run sync-changelog twice — first run writes changelog.mdx with the 6 published CLI releases, second reports no change.
  • After merge: Actions → "Sync changelog" → Run workflow; it should end with "already up to date" and open no PR. Actions → "Link check" → Run workflow for a full external-link sweep.

🤖 Generated with Claude Code

adamXbot and others added 4 commits August 6, 2026 22:37
Bring docs-mantis up to parity with docs-privacysentinel (the surviving
canonical copy — docs-privacytracker is an empty repo):

- linkcheck.yml: npm run check (nav/internal links/anchors/frontmatter)
  plus cached lychee external-link check on PR/push/weekly schedule,
  with an auto-filed issue when the scheduled run finds breakage.
- sync-changelog.yml: daily cron regenerates changelog.mdx and opens a
  PR via peter-evans/create-pull-request when it moved.
- scripts/check-docs.mjs: ported from the sibling; nav pages may be
  .md or .mdx, navigation.groups (this repo's shape) is walked in
  addition to tabs[].groups[], and inline code spans are excluded from
  link scanning so syntax examples in tables don't false-positive.
- scripts/sync-changelog.mjs: mantis has no releases.json — its release
  manifest is GitHub Releases (cli-v* = CLI, v* = server), so the
  script reads the Releases API with the workflow's built-in token,
  keeping the sibling's MANIFEST_URL/MANIFEST_FILE overrides.
- changelog.mdx: initial generated page, added to docs.json nav so the
  nav check passes from the first run.
- mintlify.yml hygiene: top-level contents: read, concurrency with
  cancel-in-progress, timeout-minutes, persist-credentials: false.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The sibling's canonical args pass --base ., which lychee now rejects
(base must be a full URL or an absolute path). Internal links, anchors
and nav are already covered by npm run check, so restrict lychee to
http/https schemes — external links only, as the step name says.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The scheme filter excludes local files from checking, but lychee still
resolves root-relative links first and errors without a root dir.
Verified locally with lychee 0.24.2: 34 external links OK, 0 errors.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@AdamXweb
AdamXweb merged commit 7c76b87 into main Aug 9, 2026
2 checks passed
@AdamXweb
AdamXweb deleted the fix/linkcheck-changelog-sync branch August 9, 2026 08:30
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants