Skip to content

Commit 79d9549

Browse files
authored
Add docs preview deploys (#8289)
1 parent fe6e198 commit 79d9549

File tree

2 files changed

+187
-0
lines changed

2 files changed

+187
-0
lines changed
Lines changed: 166 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,166 @@
1+
module.exports = async ({ github, context }) => {
2+
const { VERCEL_TOKEN, VERCEL_TEAM_ID } = process.env;
3+
4+
if (!VERCEL_TOKEN || !VERCEL_TEAM_ID) {
5+
throw new Error(
6+
`cannot run docs preview deploy workflow, ` +
7+
`VERCEL_TOKEN or VERCEL_TEAM_ID secrets are missing`
8+
);
9+
}
10+
11+
const prBranch = context.payload.pull_request.head.ref;
12+
const commitSHA = context.payload.pull_request.head.sha;
13+
const shortCommitSHA = commitSHA.slice(0, 8);
14+
15+
const existingComments = (
16+
await github.rest.issues.listComments({
17+
owner: context.repo.owner,
18+
repo: context.repo.repo,
19+
issue_number: context.issue.number,
20+
})
21+
).data;
22+
23+
const commentHeader = `### Docs preview deploy\n`;
24+
let commentMessage = commentHeader;
25+
26+
let updateComment = existingComments.find(
27+
(c) =>
28+
c.performed_via_github_app?.slug === "github-actions" &&
29+
c.body?.startsWith(commentHeader)
30+
);
31+
32+
let deployment;
33+
try {
34+
deployment = await vercelFetch("https://api.vercel.com/v13/deployments", {
35+
name: "edgedb-docs",
36+
gitSource: {
37+
type: "github",
38+
org: "edgedb",
39+
repo: "edgedb.com",
40+
ref: "docs-preview",
41+
},
42+
projectSettings: {
43+
buildCommand: `EDGEDB_REPO_BRANCH=${prBranch} EDGEDB_REPO_SHA=${commitSHA} yarn vercel-build`,
44+
},
45+
});
46+
47+
commentMessage += `\n🔄 Deploying docs preview for commit ${shortCommitSHA}:\n\n<https://${deployment.url}>`;
48+
} catch (e) {
49+
commentMessage += `\n❌ Failed to deploy docs preview for commit ${shortCommitSHA}:\n\n\`\`\`\n${e.message}\n\`\`\``;
50+
}
51+
52+
commentMessage += `\n\n(Last updated: ${formatDatetime(new Date())})`;
53+
54+
if (updateComment) {
55+
await github.rest.issues.updateComment({
56+
owner: context.repo.owner,
57+
repo: context.repo.repo,
58+
comment_id: updateComment.id,
59+
body: commentMessage,
60+
});
61+
} else {
62+
updateComment = (
63+
await github.rest.issues.createComment({
64+
owner: context.repo.owner,
65+
repo: context.repo.repo,
66+
issue_number: context.issue.number,
67+
body: commentMessage,
68+
})
69+
).data;
70+
}
71+
72+
let i = 0;
73+
while (i < 40) {
74+
await sleep(15_000);
75+
i++;
76+
77+
const status = (
78+
await vercelFetch(
79+
`https://api.vercel.com/v13/deployments/${deployment.id}`
80+
)
81+
).status;
82+
83+
const latestComment = await github.rest.issues.getComment({
84+
owner: context.repo.owner,
85+
repo: context.repo.repo,
86+
comment_id: updateComment.id,
87+
});
88+
89+
if (!latestComment.data.body.includes(shortCommitSHA)) {
90+
console.log("Skipping further updates, new deployment has started");
91+
return;
92+
}
93+
94+
if (status === "READY" || status === "ERROR" || status === "CANCELED") {
95+
await github.rest.issues.updateComment({
96+
owner: context.repo.owner,
97+
repo: context.repo.repo,
98+
comment_id: updateComment.id,
99+
body: `${commentHeader}${
100+
status === "READY"
101+
? `\n✅ Successfully deployed docs preview for commit ${shortCommitSHA}:`
102+
: `\n❌ Docs preview deployment ${
103+
status === "CANCELED" ? "failed" : "was canceled"
104+
} for commit ${shortCommitSHA}:`
105+
}\n\n<https://${deployment.url}>\n\n(Last updated: ${formatDatetime(
106+
new Date()
107+
)})`,
108+
});
109+
return;
110+
}
111+
}
112+
throw new Error("timed out waiting for deployment status to succeed or fail");
113+
};
114+
115+
async function vercelFetch(url, body) {
116+
const { VERCEL_TOKEN, VERCEL_TEAM_ID } = process.env;
117+
const _url = new URL(url);
118+
url = `${_url.origin}${_url.pathname}?${new URLSearchParams({
119+
teamId: VERCEL_TEAM_ID,
120+
})}`;
121+
122+
let res;
123+
try {
124+
res = await fetch(url, {
125+
body: body ? JSON.stringify(body) : undefined,
126+
headers: {
127+
Authorization: `Bearer ${VERCEL_TOKEN}`,
128+
"Content-Type": body ? "application/json" : undefined,
129+
},
130+
method: body ? "post" : "get",
131+
});
132+
} catch (e) {
133+
throw new Error(`vercel api request failed: ${e}`);
134+
}
135+
136+
if (res.ok) {
137+
return await res.json();
138+
} else {
139+
let body;
140+
try {
141+
body = await res.text();
142+
} catch (e) {
143+
// ignore
144+
}
145+
throw new Error(
146+
`vercel api request failed: ${res.status} ${res.statusText}, ${body}`
147+
);
148+
}
149+
}
150+
151+
function formatDatetime(date) {
152+
return date.toLocaleString("en-US", {
153+
year: "numeric",
154+
month: "short",
155+
day: "numeric",
156+
hour: "numeric",
157+
minute: "numeric",
158+
second: "numeric",
159+
hourCycle: "h24",
160+
timeZoneName: "short",
161+
});
162+
}
163+
164+
function sleep(milliseconds) {
165+
return new Promise((resolve) => setTimeout(resolve, milliseconds));
166+
}

.github/workflows/docs-preview-deploy.yml

Lines changed: 21 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)