cloudflare-pages-preview: add comment-mode=repost, extract scripts
New comment-mode input: - 'sticky' (default, backwards-compat): update the existing marker comment in place — same behavior as before - 'repost': minimize all prior marker comments as OUTDATED (GitHub's native hide-comment UI via GraphQL minimizeComment mutation) and post a fresh comment at the bottom of the conversation Useful for /stageblog where each staging should produce a visible new comment while keeping history collapsible rather than lost. Both deploy and cleanup accept the input and must match. cleanup in repost mode minimizes all prior comments and posts a final cleanup note. Also: - Extract both comment scripts to sibling comment.js files (same pattern as slash-commands/main.js) — the inline YAML scripts were getting long - Paginate listComments (was only fetching the first 30)
This commit is contained in:
parent
8e0308e4dd
commit
e6b64f4192
5 changed files with 154 additions and 65 deletions
|
|
@ -11,7 +11,9 @@ and cleaning them up when the PR closes.
|
|||
previews aren't crawled by search engines (optional, on by default)
|
||||
2. Deploys to Cloudflare Pages under a per-PR branch alias
|
||||
(`pr-<number>` by default) giving a stable URL across force-pushes
|
||||
3. Posts or updates a sticky PR comment with the preview URLs
|
||||
3. Posts a PR comment with the preview URLs — either updating a sticky
|
||||
comment in place (`comment-mode: sticky`, default) or minimizing prior
|
||||
preview comments as OUTDATED and reposting fresh (`comment-mode: repost`)
|
||||
|
||||
- **`cleanup`** — On PR close:
|
||||
1. Deletes all Cloudflare Pages deployments for the PR's branch alias
|
||||
|
|
@ -137,6 +139,7 @@ Cloudflare API and GitHub API.
|
|||
| `branch` | | `pr-<PR number>` | CF Pages branch alias |
|
||||
| `inject-noindex` | | `'true'` | Inject `_headers` + `<meta>` noindex |
|
||||
| `comment-marker` | | `<!-- cf-pages-preview -->` | Sticky-comment identifier |
|
||||
| `comment-mode` | | `sticky` | `sticky` updates the existing marker comment in place. `repost` minimizes all prior marker comments as **OUTDATED** (GitHub's native hide) and posts a fresh one. |
|
||||
| `comment-title` | | `Preview Deployed` | Heading in PR comment |
|
||||
| `github-token` | | `${{ github.token }}` | Token for PR commenting |
|
||||
| `pr-number` | | `${{ github.event.pull_request.number }}` | PR number to comment on — override when running on `workflow_dispatch` or other triggers without `payload.pull_request` |
|
||||
|
|
@ -151,6 +154,7 @@ Cloudflare API and GitHub API.
|
|||
| `account-id` | ✅ | — | Cloudflare account ID |
|
||||
| `branch` | | `pr-<PR number>` | CF Pages branch alias to delete |
|
||||
| `comment-marker` | | `<!-- cf-pages-preview -->` | Sticky-comment identifier |
|
||||
| `comment-mode` | | `sticky` | Must match `deploy`'s `comment-mode`. In `repost` mode, minimizes all marker comments and posts a final cleanup comment. |
|
||||
| `github-token` | | `${{ github.token }}` | Token for PR commenting |
|
||||
| `pr-number` | | `${{ github.event.pull_request.number }}` | PR number to update the sticky comment on — override when running on `workflow_dispatch` or other triggers without `payload.pull_request` |
|
||||
|
||||
|
|
|
|||
|
|
@ -22,6 +22,13 @@ inputs:
|
|||
description: HTML comment marker used to locate the sticky PR comment
|
||||
required: false
|
||||
default: '<!-- cf-pages-preview -->'
|
||||
comment-mode:
|
||||
description: >-
|
||||
Must match the deploy action's comment-mode. 'sticky' (default) updates
|
||||
the single marker comment in place. 'repost' minimizes all marker
|
||||
comments as OUTDATED and posts a final cleanup comment.
|
||||
required: false
|
||||
default: sticky
|
||||
github-token:
|
||||
description: GitHub token for updating the PR comment
|
||||
required: false
|
||||
|
|
@ -72,28 +79,10 @@ runs:
|
|||
uses: actions/github-script@v8
|
||||
env:
|
||||
COMMENT_MARKER: ${{ inputs.comment-marker }}
|
||||
COMMENT_MODE: ${{ inputs.comment-mode }}
|
||||
PR_NUMBER: ${{ inputs.pr-number }}
|
||||
with:
|
||||
github-token: ${{ inputs.github-token }}
|
||||
script: |
|
||||
const { owner, repo } = context.repo;
|
||||
const prNumber = Number(process.env.PR_NUMBER);
|
||||
if (!prNumber) {
|
||||
core.info('No PR number available — skipping comment update.');
|
||||
return;
|
||||
}
|
||||
const marker = process.env.COMMENT_MARKER;
|
||||
|
||||
const { data: comments } = await github.rest.issues.listComments({
|
||||
owner, repo, issue_number: prNumber
|
||||
});
|
||||
const existing = comments.find(c =>
|
||||
c.user.type === 'Bot' && c.body.includes(marker)
|
||||
);
|
||||
|
||||
if (existing) {
|
||||
await github.rest.issues.updateComment({
|
||||
owner, repo, comment_id: existing.id,
|
||||
body: `${marker}\n## Preview\n\n_Preview deployments for this PR have been cleaned up._`
|
||||
});
|
||||
}
|
||||
const main = require(process.env.GITHUB_ACTION_PATH + '/comment.js');
|
||||
await main({ github, context, core });
|
||||
|
|
|
|||
51
cloudflare-pages-preview/cleanup/comment.js
Normal file
51
cloudflare-pages-preview/cleanup/comment.js
Normal file
|
|
@ -0,0 +1,51 @@
|
|||
// Updates the PR preview comment after deployments are deleted. Called by
|
||||
// actions/github-script via `require(GITHUB_ACTION_PATH + '/comment.js')`.
|
||||
|
||||
module.exports = async ({ github, context, core }) => {
|
||||
const { owner, repo } = context.repo;
|
||||
const prNumber = Number(process.env.PR_NUMBER);
|
||||
if (!prNumber) {
|
||||
core.info('No PR number available — skipping comment update.');
|
||||
return;
|
||||
}
|
||||
const marker = process.env.COMMENT_MARKER;
|
||||
const mode = process.env.COMMENT_MODE;
|
||||
|
||||
const comments = await github.paginate(github.rest.issues.listComments, {
|
||||
owner, repo, issue_number: prNumber, per_page: 100,
|
||||
});
|
||||
const prior = comments.filter(c =>
|
||||
c.user.type === 'Bot' && c.body && c.body.includes(marker)
|
||||
);
|
||||
|
||||
const cleanupBody = `${marker}\n## Preview\n\n_Preview deployments for this PR have been cleaned up._`;
|
||||
|
||||
if (mode === 'repost') {
|
||||
for (const c of prior) {
|
||||
try {
|
||||
await github.graphql(
|
||||
`mutation($id: ID!) {
|
||||
minimizeComment(input: {subjectId: $id, classifier: OUTDATED}) {
|
||||
minimizedComment { isMinimized }
|
||||
}
|
||||
}`,
|
||||
{ id: c.node_id },
|
||||
);
|
||||
} catch (e) {
|
||||
core.warning(`Could not minimize comment ${c.id}: ${e.message}`);
|
||||
}
|
||||
}
|
||||
if (prior.length) {
|
||||
await github.rest.issues.createComment({
|
||||
owner, repo, issue_number: prNumber, body: cleanupBody,
|
||||
});
|
||||
}
|
||||
} else {
|
||||
const existing = prior[0];
|
||||
if (existing) {
|
||||
await github.rest.issues.updateComment({
|
||||
owner, repo, comment_id: existing.id, body: cleanupBody,
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
@ -36,6 +36,15 @@ inputs:
|
|||
description: Heading shown in the sticky PR comment
|
||||
required: false
|
||||
default: 'Preview Deployed'
|
||||
comment-mode:
|
||||
description: >-
|
||||
How to handle prior preview comments. 'sticky' (default) updates the
|
||||
existing marker comment in place. 'repost' minimizes all prior marker
|
||||
comments as OUTDATED (GitHub's native hide-comment UI) and posts a fresh
|
||||
comment at the bottom of the conversation — preserving history while
|
||||
surfacing the latest links prominently.
|
||||
required: false
|
||||
default: sticky
|
||||
github-token:
|
||||
description: GitHub token for posting/updating the PR comment
|
||||
required: false
|
||||
|
|
@ -106,52 +115,12 @@ runs:
|
|||
ALIAS_URL: ${{ steps.deploy.outputs.pages-deployment-alias-url }}
|
||||
COMMENT_MARKER: ${{ inputs.comment-marker }}
|
||||
COMMENT_TITLE: ${{ inputs.comment-title }}
|
||||
COMMENT_MODE: ${{ inputs.comment-mode }}
|
||||
INJECT_NOINDEX: ${{ inputs.inject-noindex }}
|
||||
PR_NUMBER: ${{ inputs.pr-number }}
|
||||
COMMIT_SHA: ${{ inputs.commit-sha }}
|
||||
with:
|
||||
github-token: ${{ inputs.github-token }}
|
||||
script: |
|
||||
const { owner, repo } = context.repo;
|
||||
const prNumber = Number(process.env.PR_NUMBER);
|
||||
if (!prNumber) {
|
||||
core.info('No PR number available — skipping comment.');
|
||||
return;
|
||||
}
|
||||
const deployUrl = process.env.DEPLOY_URL;
|
||||
const aliasUrl = process.env.ALIAS_URL || deployUrl;
|
||||
const marker = process.env.COMMENT_MARKER;
|
||||
const title = process.env.COMMENT_TITLE;
|
||||
const noindex = process.env.INJECT_NOINDEX === 'true';
|
||||
|
||||
const noindexNote = noindex
|
||||
? ' All pages served with `noindex, nofollow` — search engines will not crawl this preview.'
|
||||
: '';
|
||||
|
||||
const body = `${marker}
|
||||
## ${title}
|
||||
|
||||
| | |
|
||||
|---|---|
|
||||
| **Preview (stable)** | ${aliasUrl} |
|
||||
| **This commit** | ${deployUrl} |
|
||||
| **Commit** | \`${process.env.COMMIT_SHA.slice(0, 7)}\` |
|
||||
|
||||
_Includes drafts and future-dated posts.${noindexNote}_`;
|
||||
|
||||
const { data: comments } = await github.rest.issues.listComments({
|
||||
owner, repo, issue_number: prNumber
|
||||
});
|
||||
const existing = comments.find(c =>
|
||||
c.user.type === 'Bot' && c.body.includes(marker)
|
||||
);
|
||||
|
||||
if (existing) {
|
||||
await github.rest.issues.updateComment({
|
||||
owner, repo, comment_id: existing.id, body
|
||||
});
|
||||
} else {
|
||||
await github.rest.issues.createComment({
|
||||
owner, repo, issue_number: prNumber, body
|
||||
});
|
||||
}
|
||||
const main = require(process.env.GITHUB_ACTION_PATH + '/comment.js');
|
||||
await main({ github, context, core });
|
||||
|
|
|
|||
76
cloudflare-pages-preview/deploy/comment.js
Normal file
76
cloudflare-pages-preview/deploy/comment.js
Normal file
|
|
@ -0,0 +1,76 @@
|
|||
// Posts or updates the PR preview-URL comment. Called by actions/github-script
|
||||
// via `require(GITHUB_ACTION_PATH + '/comment.js')({ github, context, core })`.
|
||||
// All inputs are passed via env vars (see action.yml).
|
||||
|
||||
module.exports = async ({ github, context, core }) => {
|
||||
const { owner, repo } = context.repo;
|
||||
const prNumber = Number(process.env.PR_NUMBER);
|
||||
if (!prNumber) {
|
||||
core.info('No PR number available — skipping comment.');
|
||||
return;
|
||||
}
|
||||
const deployUrl = process.env.DEPLOY_URL;
|
||||
const aliasUrl = process.env.ALIAS_URL || deployUrl;
|
||||
const marker = process.env.COMMENT_MARKER;
|
||||
const title = process.env.COMMENT_TITLE;
|
||||
const mode = process.env.COMMENT_MODE;
|
||||
const noindex = process.env.INJECT_NOINDEX === 'true';
|
||||
const commitSha = process.env.COMMIT_SHA;
|
||||
|
||||
const noindexNote = noindex
|
||||
? ' All pages served with `noindex, nofollow` — search engines will not crawl this preview.'
|
||||
: '';
|
||||
|
||||
const body = [
|
||||
marker,
|
||||
`## ${title}`,
|
||||
'',
|
||||
'| | |',
|
||||
'|---|---|',
|
||||
`| **Preview (stable)** | ${aliasUrl} |`,
|
||||
`| **This commit** | ${deployUrl} |`,
|
||||
`| **Commit** | \`${commitSha.slice(0, 7)}\` |`,
|
||||
'',
|
||||
`_Includes drafts and future-dated posts.${noindexNote}_`,
|
||||
].join('\n');
|
||||
|
||||
const comments = await github.paginate(github.rest.issues.listComments, {
|
||||
owner, repo, issue_number: prNumber, per_page: 100,
|
||||
});
|
||||
const prior = comments.filter(c =>
|
||||
c.user.type === 'Bot' && c.body && c.body.includes(marker)
|
||||
);
|
||||
|
||||
if (mode === 'repost') {
|
||||
for (const c of prior) {
|
||||
try {
|
||||
await github.graphql(
|
||||
`mutation($id: ID!) {
|
||||
minimizeComment(input: {subjectId: $id, classifier: OUTDATED}) {
|
||||
minimizedComment { isMinimized }
|
||||
}
|
||||
}`,
|
||||
{ id: c.node_id },
|
||||
);
|
||||
core.info(`Minimized prior comment ${c.id} as OUTDATED`);
|
||||
} catch (e) {
|
||||
core.warning(`Could not minimize comment ${c.id}: ${e.message}`);
|
||||
}
|
||||
}
|
||||
await github.rest.issues.createComment({
|
||||
owner, repo, issue_number: prNumber, body,
|
||||
});
|
||||
} else {
|
||||
// sticky: update the first prior comment in place, or create one
|
||||
const existing = prior[0];
|
||||
if (existing) {
|
||||
await github.rest.issues.updateComment({
|
||||
owner, repo, comment_id: existing.id, body,
|
||||
});
|
||||
} else {
|
||||
await github.rest.issues.createComment({
|
||||
owner, repo, issue_number: prNumber, body,
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
Loading…
Reference in a new issue