Skip to content
Merged
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
76 changes: 65 additions & 11 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -62,23 +62,77 @@ jobs:
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
script: |
const marker = "<!-- display-list-explorer-cloudflare-preview -->";
const historyPattern = /<!-- display-list-explorer-preview-history:([A-Za-z0-9+/=]+) -->/;
const sha = process.env.COMMIT_SHA;
const snapshotUrl = process.env.SNAPSHOT_URL;
const stableUrl = process.env.STABLE_URL;
const shortSha = sha.slice(0, 7);
const commitUrl = `${process.env.GITHUB_SERVER_URL}/${context.repo.owner}/${context.repo.repo}/commit/${sha}`;
const issue = {
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: context.issue.number,
};

const comments = await github.paginate(
github.rest.issues.listComments,
{ ...issue, per_page: 100 },
);
const existingComment = comments.find(
(comment) =>
comment.user?.login === "github-actions[bot]" &&
comment.body?.includes(marker),
);

let history = [];
const historyMatch = existingComment?.body?.match(historyPattern);
if (historyMatch) {
try {
history = JSON.parse(
Buffer.from(historyMatch[1], "base64").toString("utf8"),
);
} catch (error) {
core.warning(`Could not decode preview history: ${error.message}`);
}
}

const currentEntry = { sha, url: snapshotUrl };
const currentIndex = history.findIndex((entry) => entry.sha === sha);
if (currentIndex === -1) {
history.push(currentEntry);
} else {
history[currentIndex] = currentEntry;
}

const encodedHistory = Buffer.from(
JSON.stringify(history),
"utf8",
).toString("base64");
const commitBaseUrl = `${process.env.GITHUB_SERVER_URL}/${context.repo.owner}/${context.repo.repo}/commit`;
const historyRows = history.map(
(entry) =>
`| [\`${entry.sha.slice(0, 7)}\`](${commitBaseUrl}/${entry.sha}) | [Open snapshot](${entry.url}) |`,
);
const body = [
marker,
`<!-- display-list-explorer-preview-history:${encodedHistory} -->`,
"## Cloudflare Pages preview",
"",
`- **Latest PR preview:** [${stableUrl}](${stableUrl})`,
`- **Snapshot for [\`${shortSha}\`](${commitUrl}):** [${snapshotUrl}](${snapshotUrl})`,
`**Latest PR preview:** [${stableUrl}](${stableUrl})`,
"",
"| Commit | Immutable snapshot |",
"| --- | --- |",
...historyRows,
"",
"The PR URL always points to the latest deployment; the commit snapshot is immutable.",
"The PR URL always points to the latest deployment. Each commit snapshot is immutable.",
].join("\n");

await github.rest.issues.createComment({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: context.issue.number,
body,
});
if (existingComment) {
await github.rest.issues.updateComment({
owner: issue.owner,
repo: issue.repo,
comment_id: existingComment.id,
body,
});
} else {
await github.rest.issues.createComment({ ...issue, body });
}
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ The Pages workflow deploys every push to `main` and can also be run manually fro

## Pull request previews

Pull requests opened from branches in this repository are deployed to an isolated Cloudflare Pages preview after CI succeeds. Each pull request receives a stable branch alias such as `https://pr-42.display-list-explorer.pages.dev`, while every update also creates an immutable deployment URL. GitHub attaches the resulting URL to the pull request as a deployment and posts both URLs in a commit-specific PR comment, preserving access to earlier snapshots as new commits are pushed.
Pull requests opened from branches in this repository are deployed to an isolated Cloudflare Pages preview after CI succeeds. Each pull request receives a stable branch alias such as `https://pr-42.display-list-explorer.pages.dev`, while every update also creates an immutable deployment URL. GitHub attaches the resulting URL to the pull request as a deployment and maintains a single bot comment containing the stable URL and a commit-by-commit table of immutable snapshots.

The workflow expects a `CLOUDFLARE_API_TOKEN` repository secret with Cloudflare Pages edit access and a `CLOUDFLARE_ACCOUNT_ID` repository variable. Pull requests from forks still run the converter and site build, but skip deployment because repository secrets are not exposed to fork workflows.

Expand Down
Loading