265 lines
9.2 KiB
YAML
265 lines
9.2 KiB
YAML
name: Doc Review
|
|
|
|
on:
|
|
pull_request:
|
|
types: [opened, synchronize, ready_for_review]
|
|
paths:
|
|
- 'content/**'
|
|
- 'layouts/**'
|
|
- 'assets/**'
|
|
- 'data/**'
|
|
workflow_dispatch:
|
|
inputs:
|
|
pr_number:
|
|
description: 'PR number to review'
|
|
required: true
|
|
type: number
|
|
|
|
permissions: {}
|
|
|
|
concurrency:
|
|
group: doc-review-${{ github.event.number || inputs.pr_number }}
|
|
cancel-in-progress: true
|
|
|
|
jobs:
|
|
# -----------------------------------------------------------------
|
|
# Job 1: Resolve preview URLs from changed content files
|
|
# -----------------------------------------------------------------
|
|
resolve-urls:
|
|
runs-on: ubuntu-latest
|
|
permissions:
|
|
contents: read
|
|
pull-requests: read
|
|
if: |
|
|
github.event_name == 'workflow_dispatch' ||
|
|
(!github.event.pull_request.draft &&
|
|
github.event.pull_request.head.repo.full_name == github.repository &&
|
|
!contains(github.event.pull_request.labels.*.name, 'skip-review'))
|
|
outputs:
|
|
urls: ${{ steps.detect.outputs.urls }}
|
|
url-count: ${{ steps.detect.outputs.url-count }}
|
|
steps:
|
|
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1
|
|
with:
|
|
persist-credentials: false
|
|
fetch-depth: 0
|
|
sparse-checkout: |
|
|
content
|
|
data/products.yml
|
|
scripts/lib/content-utils.js
|
|
.github/scripts/resolve-review-urls.js
|
|
package.json
|
|
sparse-checkout-cone-mode: false
|
|
|
|
- uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0
|
|
with:
|
|
node-version: 22
|
|
|
|
- name: Resolve base ref
|
|
id: base
|
|
env:
|
|
GH_TOKEN: ${{ github.token }}
|
|
PR_NUMBER: ${{ github.event.pull_request.number || inputs.pr_number }}
|
|
run: |
|
|
if [ -n "${{ github.base_ref }}" ]; then
|
|
echo "ref=origin/${{ github.base_ref }}" >> "$GITHUB_OUTPUT"
|
|
else
|
|
BASE=$(gh pr view "$PR_NUMBER" --repo "${{ github.repository }}" --json baseRefName -q .baseRefName)
|
|
git fetch origin "$BASE"
|
|
echo "ref=origin/$BASE" >> "$GITHUB_OUTPUT"
|
|
fi
|
|
|
|
- name: Detect changed pages
|
|
id: detect
|
|
env:
|
|
BASE_REF: ${{ steps.base.outputs.ref }}
|
|
run: node .github/scripts/resolve-review-urls.js
|
|
|
|
# -----------------------------------------------------------------
|
|
# Job 2: Copilot code review (runs in parallel with Job 1)
|
|
# -----------------------------------------------------------------
|
|
copilot-review:
|
|
runs-on: ubuntu-latest
|
|
permissions:
|
|
pull-requests: write
|
|
if: |
|
|
github.event_name == 'workflow_dispatch' ||
|
|
(!github.event.pull_request.draft &&
|
|
github.event.pull_request.head.repo.full_name == github.repository &&
|
|
!contains(github.event.pull_request.labels.*.name, 'skip-review'))
|
|
steps:
|
|
- name: Request Copilot review
|
|
env:
|
|
GH_TOKEN: ${{ github.token }}
|
|
PR_NUMBER: ${{ github.event.pull_request.number || inputs.pr_number }}
|
|
REPO: ${{ github.repository }}
|
|
run: gh pr edit "$PR_NUMBER" --repo "$REPO" --add-reviewer "copilot-reviews"
|
|
|
|
# -----------------------------------------------------------------
|
|
# Job 3: Copilot visual review (depends on Job 1 for URLs)
|
|
# -----------------------------------------------------------------
|
|
copilot-visual-review:
|
|
runs-on: ubuntu-latest
|
|
permissions:
|
|
contents: read
|
|
pull-requests: write
|
|
needs: resolve-urls
|
|
if: needs.resolve-urls.result == 'success' && fromJson(needs.resolve-urls.outputs.url-count) > 0
|
|
steps:
|
|
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1
|
|
with:
|
|
persist-credentials: false
|
|
sparse-checkout: .github/prompts/copilot-visual-review.md
|
|
sparse-checkout-cone-mode: false
|
|
|
|
- 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
|
|
|
|
echo "Waiting for preview at ${PREVIEW_URL}"
|
|
|
|
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
|
|
|
|
echo "Preview deployment timed out after ${TIMEOUT}s"
|
|
echo "available=false" >> "$GITHUB_OUTPUT"
|
|
|
|
- name: Post visual review request
|
|
if: steps.wait.outputs.available == 'true'
|
|
uses: actions/github-script@f28e40c7f34bde8b3046d885e986cb6290c5673b # v7.1.0
|
|
env:
|
|
PREVIEW_URLS: ${{ needs.resolve-urls.outputs.urls }}
|
|
PR_NUMBER: ${{ github.event.pull_request.number || inputs.pr_number }}
|
|
with:
|
|
script: |
|
|
const fs = require('fs');
|
|
|
|
let urls;
|
|
try {
|
|
urls = JSON.parse(process.env.PREVIEW_URLS);
|
|
} catch (e) {
|
|
core.warning(`Failed to parse PREVIEW_URLS: ${e.message}`);
|
|
return;
|
|
}
|
|
|
|
const prNumber = context.issue.number || Number(process.env.PR_NUMBER);
|
|
const previewBase = `https://influxdata.github.io/docs-v2/pr-preview/pr-${prNumber}`;
|
|
|
|
// Build preview URL list
|
|
const urlList = urls
|
|
.map(u => `- [${u}](${previewBase}${u})`)
|
|
.join('\n');
|
|
|
|
// Read the Copilot visual review template
|
|
const template = fs.readFileSync(
|
|
'.github/prompts/copilot-visual-review.md',
|
|
'utf8'
|
|
);
|
|
|
|
const marker = '<!-- doc-review-visual -->';
|
|
const body = [
|
|
marker,
|
|
'## Preview Pages for Review',
|
|
'',
|
|
`${urls.length} page(s) changed in this PR:`,
|
|
'',
|
|
'<details>',
|
|
'<summary>Preview URLs</summary>',
|
|
'',
|
|
urlList,
|
|
'',
|
|
'</details>',
|
|
'',
|
|
'---',
|
|
'',
|
|
`@copilot please review the preview pages listed above using the template below:`,
|
|
'',
|
|
template.trim(),
|
|
'',
|
|
urlList,
|
|
].join('\n');
|
|
|
|
// Update existing comment or create new one
|
|
const { data: comments } = await github.rest.issues.listComments({
|
|
owner: context.repo.owner,
|
|
repo: context.repo.repo,
|
|
issue_number: prNumber,
|
|
});
|
|
const existing = comments.find(c => c.body.includes(marker));
|
|
|
|
if (existing) {
|
|
await github.rest.issues.updateComment({
|
|
owner: context.repo.owner,
|
|
repo: context.repo.repo,
|
|
comment_id: existing.id,
|
|
body,
|
|
});
|
|
} else {
|
|
await github.rest.issues.createComment({
|
|
owner: context.repo.owner,
|
|
repo: context.repo.repo,
|
|
issue_number: prNumber,
|
|
body,
|
|
});
|
|
}
|
|
|
|
core.info(`Posted visual review request with ${urls.length} URLs`);
|
|
|
|
- name: Post timeout notice
|
|
if: steps.wait.outputs.available == 'false'
|
|
uses: actions/github-script@f28e40c7f34bde8b3046d885e986cb6290c5673b # v7.1.0
|
|
env:
|
|
PR_NUMBER: ${{ github.event.pull_request.number || inputs.pr_number }}
|
|
with:
|
|
script: |
|
|
const prNumber = context.issue.number || Number(process.env.PR_NUMBER);
|
|
const marker = '<!-- doc-review-visual-timeout -->';
|
|
const body = [
|
|
marker,
|
|
'## Visual Review Skipped',
|
|
'',
|
|
'The PR preview deployment did not become available within 10 minutes.',
|
|
'Visual review was skipped. The Copilot code review (Job 2) still ran.',
|
|
'',
|
|
'To trigger visual review manually, re-run this workflow after the',
|
|
'preview is deployed.',
|
|
].join('\n');
|
|
|
|
const { data: comments } = await github.rest.issues.listComments({
|
|
owner: context.repo.owner,
|
|
repo: context.repo.repo,
|
|
issue_number: prNumber,
|
|
});
|
|
const existing = comments.find(c => c.body.includes(marker));
|
|
|
|
if (existing) {
|
|
await github.rest.issues.updateComment({
|
|
owner: context.repo.owner,
|
|
repo: context.repo.repo,
|
|
comment_id: existing.id,
|
|
body,
|
|
});
|
|
} else {
|
|
await github.rest.issues.createComment({
|
|
owner: context.repo.owner,
|
|
repo: context.repo.repo,
|
|
issue_number: prNumber,
|
|
body,
|
|
});
|
|
}
|