fix(ci): replace HTTP polling with commit status signaling for preview coordination

pr-preview.yml now emits a `preview/deploy` commit status (pending/success/failure)
so doc-review.yml can detect failures instantly instead of polling an HTTP URL for
10 minutes. Also centralizes the api-docs TypeScript build command in package.json
and adds a lefthook pre-commit hook for api-docs script changes.
clean-squash
Jason Stirnaman 2026-03-13 23:09:12 -05:00
parent 064e0248f4
commit a809dc5313
6 changed files with 119 additions and 28 deletions

View File

@ -28,7 +28,7 @@ jobs:
command: cd api-docs && yarn install
- run:
name: Build API documentation scripts
command: npx tsc --project api-docs/scripts/tsconfig.json
command: yarn build:api-docs:scripts
- run:
name: Generate API documentation
command: cd api-docs && bash generate-api-docs.sh

View File

@ -122,7 +122,9 @@ function detectApiPages(apiDocFiles) {
pages.add(urlPath);
}
} catch (err) {
console.log(` ⚠️ Could not read or parse ${configPath}: ${err.message}`);
console.log(
` ⚠️ Could not read or parse ${configPath}: ${err.message}`
);
}
}
@ -187,10 +189,14 @@ function main() {
// Strategy 2: API doc changes - auto-detect affected API pages
if (changes.apiDocs.length > 0) {
console.log('📋 API doc changes detected, auto-detecting affected pages...');
console.log(
'📋 API doc changes detected, auto-detecting affected pages...'
);
const apiPages = detectApiPages(changes.apiDocs);
if (apiPages.length > 0) {
console.log(` Found ${apiPages.length} affected API page(s): ${apiPages.join(', ')}`);
console.log(
` Found ${apiPages.length} affected API page(s): ${apiPages.join(', ')}`
);
pagesToDeploy = [...new Set([...pagesToDeploy, ...apiPages])];
}
}

View File

@ -119,6 +119,7 @@ jobs:
permissions:
contents: read
pull-requests: write
statuses: read
needs: resolve-urls
if: needs.resolve-urls.result == 'success' && fromJson(needs.resolve-urls.outputs.url-count) > 0
steps:
@ -130,30 +131,48 @@ jobs:
- name: Wait for preview deployment
id: wait
env:
PR_NUMBER: ${{ github.event.pull_request.number || inputs.pr_number }}
run: |
PREVIEW_URL="https://influxdata.github.io/docs-v2/pr-preview/pr-${PR_NUMBER}/"
TIMEOUT=600 # 10 minutes
INTERVAL=15
ELAPSED=0
uses: actions/github-script@f28e40c7f34bde8b3046d885e986cb6290c5673b # v7.1.0
with:
script: |
const TIMEOUT_MS = 180_000; // 3 minutes
const INTERVAL_MS = 15_000; // 15 seconds
const CONTEXT = 'preview/deploy';
const sha = context.sha;
const start = Date.now();
echo "Waiting for preview at ${PREVIEW_URL}"
while (Date.now() - start < TIMEOUT_MS) {
const { data: statuses } = await github.rest.repos.listCommitStatusesForRef({
owner: context.repo.owner,
repo: context.repo.repo,
ref: sha,
});
while [ "$ELAPSED" -lt "$TIMEOUT" ]; do
STATUS=$(curl -s -o /dev/null -L -w "%{http_code}" "$PREVIEW_URL" || echo "000")
if [ "$STATUS" = "200" ]; then
echo "Preview is live"
echo "available=true" >> "$GITHUB_OUTPUT"
exit 0
fi
echo "Status: ${STATUS} (${ELAPSED}s / ${TIMEOUT}s)"
sleep "$INTERVAL"
ELAPSED=$((ELAPSED + INTERVAL))
done
const status = statuses.find(s => s.context === CONTEXT);
echo "Preview deployment timed out after ${TIMEOUT}s"
echo "available=false" >> "$GITHUB_OUTPUT"
if (status) {
if (status.state === 'success') {
core.info(`Preview deployed: ${status.target_url}`);
core.setOutput('available', 'true');
core.setOutput('preview-url', status.target_url);
return;
}
if (status.state === 'failure' || status.state === 'error') {
core.info(`Preview failed: ${status.description}`);
core.setOutput('available', 'false');
core.setOutput('reason', status.description);
return;
}
core.info(`Preview building... (${Math.round((Date.now() - start) / 1000)}s)`);
} else {
core.info(`No preview status yet (${Math.round((Date.now() - start) / 1000)}s)`);
}
await new Promise(r => setTimeout(r, INTERVAL_MS));
}
core.info('Preview status check timed out');
core.setOutput('available', 'false');
core.setOutput('reason', 'Timed out waiting for preview status');
- name: Post visual review request
if: steps.wait.outputs.available == 'true'
@ -244,12 +263,14 @@ jobs:
with:
script: |
const prNumber = context.issue.number || Number(process.env.PR_NUMBER);
const reason = '${{ steps.wait.outputs.reason }}' || 'Unknown';
const marker = '<!-- doc-review-visual-timeout -->';
const body = [
marker,
'## Visual Review Skipped',
'',
'The PR preview deployment did not become available within 10 minutes.',
`Reason: ${reason}`,
'',
'Visual review was skipped. The Copilot code review (Job 2) still ran.',
'',
'To trigger visual review manually, re-run this workflow after the',

View File

@ -14,6 +14,7 @@ on:
permissions:
contents: write
pull-requests: write
statuses: write
concurrency:
group: pr-preview-${{ github.event.number }}
@ -90,12 +91,33 @@ jobs:
- name: Install dependencies
run: yarn install --frozen-lockfile
- name: Set preview status (pending)
uses: actions/github-script@v7
with:
script: |
await github.rest.repos.createCommitStatus({
owner: context.repo.owner,
repo: context.repo.repo,
sha: context.sha,
state: 'pending',
context: 'preview/deploy',
description: 'Building preview...',
});
- name: Detect preview pages
id: detect
env:
PR_BODY: ${{ github.event.pull_request.body }}
BASE_REF: origin/${{ github.base_ref }}
run: node .github/scripts/detect-preview-pages.js
run: |
if ! node .github/scripts/detect-preview-pages.js; then
echo "::warning::detect-preview-pages.js failed — skipping preview."
echo "pages-to-deploy=[]" >> "$GITHUB_OUTPUT"
echo "has-api-doc-changes=false" >> "$GITHUB_OUTPUT"
echo "has-layout-changes=false" >> "$GITHUB_OUTPUT"
echo "needs-author-input=false" >> "$GITHUB_OUTPUT"
echo "change-summary=Detection failed (possible merge conflicts)" >> "$GITHUB_OUTPUT"
fi
- name: Post pending comment (needs input)
if: steps.detect.outputs.needs-author-input == 'true'
@ -117,7 +139,7 @@ jobs:
- name: Build API documentation scripts
if: steps.detect.outputs.has-api-doc-changes == 'true' && steps.detect.outputs.pages-to-deploy != '[]'
run: npx tsc --project api-docs/scripts/tsconfig.json
run: yarn build:api-docs:scripts
- name: Build API docs
if: steps.detect.outputs.has-api-doc-changes == 'true' && steps.detect.outputs.pages-to-deploy != '[]'
@ -175,6 +197,44 @@ jobs:
echo "status=ok" >> "$GITHUB_OUTPUT"
- name: Set preview status (success)
if: steps.validate-deploy.outputs.status == 'ok'
uses: actions/github-script@v7
with:
script: |
const previewUrl = `https://influxdata.github.io/docs-v2/pr-preview/pr-${context.issue.number}/`;
await github.rest.repos.createCommitStatus({
owner: context.repo.owner,
repo: context.repo.repo,
sha: context.sha,
state: 'success',
context: 'preview/deploy',
description: 'Preview deployed',
target_url: previewUrl,
});
- name: Set preview status (skipped/failed)
if: >-
always() &&
steps.detect.outcome == 'success' &&
(steps.validate-deploy.outputs.status != 'ok' ||
steps.detect.outputs.pages-to-deploy == '[]')
uses: actions/github-script@v7
with:
script: |
const description =
'${{ steps.detect.outputs.pages-to-deploy }}' === '[]'
? 'No pages to preview'
: 'Preview deployment failed';
await github.rest.repos.createCommitStatus({
owner: context.repo.owner,
repo: context.repo.repo,
sha: context.sha,
state: 'failure',
context: 'preview/deploy',
description,
});
- name: Post success comment
if: steps.detect.outputs.pages-to-deploy != '[]' && steps.validate-deploy.outputs.status == 'ok'
uses: actions/github-script@v7

View File

@ -123,6 +123,9 @@ pre-commit:
glob: "assets/js/*.ts"
run: yarn build:ts
stage_fixed: true
build-api-docs-scripts:
glob: "api-docs/scripts/**/*.ts"
run: yarn build:api-docs:scripts
prettier:
tags: [frontend, style]
glob: '*.{css,js,ts,jsx,tsx}'

View File

@ -73,6 +73,7 @@
"docs:audit": "node scripts/docs-cli/docs-cli.js audit",
"docs:release-notes": "node scripts/docs-cli/docs-cli.js release-notes",
"build:api-docs": "cd api-docs && sh generate-api-docs.sh",
"build:api-docs:scripts": "tsc --project api-docs/scripts/tsconfig.json",
"build:pytest:image": "docker build -t influxdata/docs-pytest:latest -f Dockerfile.pytest .",
"build:agent:instructions": "node ./helper-scripts/build-agent-instructions.js",
"build:ts": "tsc --project tsconfig.json --outDir dist",