Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
75 changes: 75 additions & 0 deletions .github/workflows/schema-sync-watchdog.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
name: Schema Sync Watchdog
permissions: read-all

# The Mergify JSON schemas are pushed here by an external workflow, as a pull
# request from a bot fork. It normally merges itself within ten minutes, so
# nobody watches it — which is how a spec change that needed a docs-side edit
# (the retired `badges` tag, whose sidebar entry had to go with it) left the
# sync red and unnoticed for three days, with every schema change piling onto
# the same blocked branch.
#
# CI already catches the breakage; what was missing is anyone being told. A
# failing scheduled run is that signal: it shows red in the Actions tab and
# GitHub emails whoever last touched this file. Fixing the sync clears it.

on:
schedule:
- cron: "23 */3 * * *"
workflow_dispatch:

jobs:
stale-sync:
timeout-minutes: 5
runs-on: ubuntu-24.04
steps:
- name: Report a schema sync that has not landed
env:
GH_TOKEN: ${{ github.token }}
GH_REPO: ${{ github.repository }}
SYNC_AUTHOR: mergify-ci-bot
# The bot pushes every sync onto this one branch, and files other
# kinds of pull request under the same account, so match the branch
# rather than the author alone.
SYNC_BRANCH: json-schema-types-sync
# Ten times the usual time to merge, so an ordinary sync never trips it.
MAX_AGE_MINUTES: "180"
run: |
set -euo pipefail

cutoff=$(date -u -d "${MAX_AGE_MINUTES} minutes ago" +%Y-%m-%dT%H:%M:%SZ)

stale=$(gh pr list \
--author "${SYNC_AUTHOR}" \
--head "${SYNC_BRANCH}" \
--state open \
--limit 20 \
--json number,url,title,createdAt,statusCheckRollup \
| jq -r --arg cutoff "${cutoff}" '
map(select(.createdAt < $cutoff))
| .[]
| " \(.url) — \(.title)\n opened \(.createdAt), failing: \(
[.statusCheckRollup[]? | select(.conclusion == "FAILURE") | .name]
| if length == 0 then "no check, so it is waiting on something else" else join(", ") end
)"
')

if [ -z "${stale}" ]; then
echo "No schema sync pull request older than ${MAX_AGE_MINUTES} minutes."
exit 0
fi

{
echo "## The Mergify schema sync has not landed"
echo
echo "Open for more than ${MAX_AGE_MINUTES} minutes:"
echo
echo '```'
echo "${stale}"
echo '```'
echo
echo "The docs site is serving a stale API and configuration reference until this merges."
} >> "${GITHUB_STEP_SUMMARY}"

echo "::error::The Mergify schema sync has not landed; the docs site is serving a stale reference."
echo "${stale}"
exit 1
15 changes: 8 additions & 7 deletions integrations/validate-api-nav-paths.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,11 @@ import { danglingApiNavPaths } from '../src/util/apiNavPaths';
* `activity_log` rename left `/api/eventlogs` 404ing from every page on the
* site.
*
* This has to run at build time rather than only in the link check: the spec
* arrives by bot sync pushed straight to main, which opens no pull request,
* and CI runs on `pull_request` only. The deploy build is the sole gate a
* sync passes through. apiNavPaths.test.ts runs the same check in pull
* request CI for earlier feedback on docs-side edits.
* apiNavPaths.test.ts runs the same check in pull request CI, which is where
* the schema sync is caught — it arrives as a bot pull request, not a push.
* This copy runs on the deploy build because the two sides of the check land
* in separate pull requests: a sync that retires a tag and an unrelated edit
* that links it are each green alone and broken once both are on main.
*/
export function validateApiNavPaths(): AstroIntegration {
return {
Expand All @@ -29,8 +29,9 @@ export function validateApiNavPaths(): AstroIntegration {
throw new Error(
`src/content/navItems.tsx links to ${dangling.join(', ')}, which no longer ` +
`exist. Every /api/* route comes from a tag in public/api-schemas.json or a ` +
`page in src/content/docs/api/ — point the entry at the tag's current slug ` +
`(and add a redirect in public/_redirects, since the old URL was published).`
`page in src/content/docs/api/. If the tag was renamed upstream, point the ` +
`entry at its current slug; if it was retired, drop the entry. Either way ` +
`add a redirect in public/_redirects, since the old URL was published.`
);
}
},
Expand Down