-
Notifications
You must be signed in to change notification settings - Fork 0
210 lines (194 loc) · 9.94 KB
/
Copy pathrefresh-api-docs.yml
File metadata and controls
210 lines (194 loc) · 9.94 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
name: Refresh API reference
# Regenerates the generated API reference from the PUBLISHED npm tarballs and commits
# the result to master — which deploys the site.
#
# Why this exists: `npm run build-docs` was a step in the release habit, and skipping
# it fails silently. Nothing breaks, no page 404s, the site just keeps advertising the
# previous version's reference — `core` and `rpc` sat four days stale that way, and
# only a hand comparison of src/_data/apiVersions.json against npm caught it. With 16
# documented packages a habit is not a mechanism.
#
# Three triggers, in descending order of reliability:
#
# schedule the safety net, and the one that matters. Asks npm what is
# published, rebuilds only the packages that moved. It needs
# nothing in the package repos, so it cannot be forgotten
# when a repo is added or a release is cut by hand.
# repository_dispatch the fast path — a package repo pings this after `npm publish`
# so /api/ is current in minutes instead of by tomorrow. Wiring
# it is optional per repo; see the snippet at the bottom.
# workflow_dispatch by hand, optionally naming packages.
#
# Cost when nothing shipped: a checkout, `npm ci`, and 16 `npm view` calls (~17s). A
# one-package rebuild reads one tarball and takes ~4s, because a partial build MERGES
# into the shared outputs instead of rewriting them.
on:
schedule:
# 04:17 UTC. Off the hour on purpose — GitHub delays cron under load, and the
# top of the hour is where every scheduled job in the world queues up.
- cron: '17 4 * * *'
repository_dispatch:
types: [package-released]
workflow_dispatch:
inputs:
packages:
description: "Packages to rebuild (space-separated, no @imqueue/ scope). Empty = whatever npm says is stale."
default: ""
# Never let two refreshes race on a push to master.
concurrency:
group: refresh-api-docs
cancel-in-progress: false
permissions:
contents: write
jobs:
refresh:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v7
with:
# REQUIRED for the `npm test` step: check:dates reads git history
# (`git log --follow --diff-filter=A`) to verify every page's publication
# date. The default shallow fetch has one commit, so every file looks as
# though that commit added it and the check fails on every run.
fetch-depth: 0
- uses: actions/setup-node@v7
with:
node-version: 22
cache: npm
- run: npm ci
- name: Decide what to rebuild
id: pkgs
env:
# A dispatching repo names itself; a human may name several.
REQUESTED: ${{ github.event.inputs.packages || github.event.client_payload.package || '' }}
run: |
if [ -n "$REQUESTED" ]; then
list="$REQUESTED"
echo "Requested explicitly: $list"
else
# --list prints names and nothing else, and THROWS if npm is
# unreachable — a registry failure must fail this job rather than
# resolve to an empty list, which would look exactly like success.
list="$(node scripts/check-api-versions.js --list)"
echo "Stale per npm: ${list:-none}"
fi
# One line, single-spaced, no trailing space. --list emits one name per
# line, and a stray trailing space would later be read as part of a
# package name when the commit message looks its version up.
echo "list=$(echo $list | xargs)" >> "$GITHUB_OUTPUT"
- name: Regenerate
if: steps.pkgs.outputs.list != ''
env:
PKGS: ${{ steps.pkgs.outputs.list }}
run: |
# These names can arrive in a dispatch payload, so validate the shape
# before a shell expands them. build-docs rejects unknown packages too,
# but only after the string has already been through the shell.
case "$PKGS" in
*[!a-z0-9\ -]*) echo "Refusing suspicious package list: $PKGS"; exit 1 ;;
esac
# Unquoted on purpose: one word per package. (Safe in bash; note zsh does
# NOT word-split unquoted variables, so this line would break locally.)
#
# No --strict-prose: the summary floor stays warn-only, so a package that
# releases with a doc-block regression still gets its version published
# here rather than having the refresh blocked. API-DOCS-PLAN.md §3 item 9.
npm run build-docs -- $PKGS
- name: Verify — redirects, dates, links, sitemap
if: steps.pkgs.outputs.list != ''
# This is not belt-and-braces. A push made with GITHUB_TOKEN does not trigger
# other workflows, so checks.yml will NOT run for the commit this job creates
# — the gate has to run here or not at all. Cloudflare Pages deploys from the
# git push itself, so an unverified push would ship straight to production.
run: npm test
- name: Commit & push if changed
id: commit
if: steps.pkgs.outputs.list != ''
env:
PKGS: ${{ steps.pkgs.outputs.list }}
run: |
# An explicit path list, not `git add -A`: the working tree of this repo
# also holds untracked local-only material (promotion/, the *-PLAN.md
# notes) that must never be committed by a bot or anyone else.
paths="src/org/api src/org/_redirects src/_data/apiVersions.json \
lib/api-versions.js lib/api-renames.js lib/api-renamed.js \
functions/api"
if [ -z "$(git status --porcelain -- $paths)" ]; then
echo "Nothing changed — the reference already matches npm."
exit 0
fi
# A version-only release is a 2-6 line diff (the version a page advertises
# lives in apiVersions.json, not in the page), so name it in the message —
# that number is the whole reason the commit exists.
#
# set -- word-splits, so $1 is a package name and never a name plus
# whitespace. (Again bash-only: zsh does not split unquoted variables and
# would leave every positional empty.)
set -- $PKGS
if [ "$#" = 1 ]; then
ver=$(node -p "require('./src/_data/apiVersions.json')['$1'].latest")
msg="docs(api): resync $1 with npm — $ver"
else
msg="docs(api): resync $# packages with npm — $*"
fi
git config user.name "imqueue-bot"
git config user.email "bot@imqueue.com"
git add -- $paths
git commit -m "$msg"
git push
echo "Pushed: $msg"
echo "sha=$(git rev-parse HEAD)" >> "$GITHUB_OUTPUT"
# Diff-scoped IndexNow, not a whole-sitemap submission.
#
# This job pinged nothing at all, because `npm run indexnow:org` passes
# --exclude=/api/. That exclusion is right for a whole-sitemap ping — 423 URLs of
# which two changed is a poor use of a daily quota, and the sitemap's per-page
# lastmod already carries the change — but it meant a genuine release reached the
# Bing-backed engines only on the next crawl, for the largest body of unique
# content on the site.
#
# scripts/changed-urls.js resolves the commit's diff to URLs and intersects them
# with the built sitemap, so a mapping mistake drops the URL and says so instead
# of submitting something that does not exist. `|| true` because a failed
# submission must never fail a job that has already pushed correct content — the
# sitemap remains the reliable path.
- name: IndexNow — only the /api/ URLs this commit changed
if: steps.commit.outputs.sha != ''
run: |
urls=$(node scripts/changed-urls.js org "${{ steps.commit.outputs.sha }}^..${{ steps.commit.outputs.sha }}" --prefix=/api/)
if [ -z "$urls" ]; then
echo "No /api/ page URLs changed — nothing to submit."
exit 0
fi
# Unquoted on purpose: one word per URL.
node scripts/indexnow-ping.js org $urls || true
# ---------------------------------------------------------------------------
# The schedule alone keeps /api/ correct within a day. To make a release show up
# within minutes instead, add a step to a package repo's release workflow AFTER the
# successful `npm publish`:
#
# - name: Notify imqueue.com to refresh the API reference
# run: |
# curl -sSf -X POST \
# -H "Authorization: Bearer ${{ secrets.SITE_DISPATCH_TOKEN }}" \
# -H "Accept: application/vnd.github+json" \
# https://api.github.com/repos/imqueue/imqueue.com/dispatches \
# -d '{"event_type":"package-released","client_payload":{"package":"pg-pubsub"}}'
#
# `package` is the /api/ segment — the npm name without the @imqueue/ scope. Three
# packages were renamed on 2026-08-01, so send the CURRENT name: `opentelemetry`,
# `datadog`, `pg-sequelize`. Omit client_payload entirely and this rebuilds whatever
# npm says is stale, which is also correct and needs no per-repo edit.
#
# SITE_DISPATCH_TOKEN is a fine-grained PAT (or a classic PAT with `repo` scope) that
# may send dispatches to imqueue/imqueue.com, stored as a secret in the package repo.
# It is the same credential sync-cli-guide.yml documents, and the only one to create
# by hand. Without it, the schedule still covers every package.
#
# IndexNow: a WHOLE-SITEMAP ping is still not made from here — indexnow-ping.js's
# --exclude=/api/ stands, and API pages reach search engines through the sitemap. What
# this job does now is submit exactly the /api/ URLs its own commit changed, which is
# usually two and never 423. See the step above; supersedes API-DOCS-PLAN.md §5
# decision 2, which read the exclusion as "never ping /api/" when the reason for it
# was only ever the volume.
# ---------------------------------------------------------------------------