Skip to content

Commit 95f2439

Browse files
authored
ci: add github previews (#206)
h/t developmentseed/how#423
1 parent b5e2928 commit 95f2439

File tree

4 files changed

+272
-0
lines changed

4 files changed

+272
-0
lines changed
Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
const PR_MARKER = '<!-- action-pr-marker -->';
2+
3+
async function findComment({ github, context, core }) {
4+
const comments = await github.rest.issues.listComments({
5+
owner: context.repo.owner,
6+
repo: context.repo.repo,
7+
issue_number: context.payload.pull_request.number
8+
});
9+
const existingComment = comments.data.find((comment) =>
10+
comment.body.includes(PR_MARKER)
11+
);
12+
13+
return existingComment?.id;
14+
}
15+
16+
async function setComment({ github, context, commentId, body }) {
17+
if (commentId) {
18+
await github.rest.issues.updateComment({
19+
owner: context.repo.owner,
20+
repo: context.repo.repo,
21+
comment_id: commentId,
22+
body
23+
});
24+
} else {
25+
await github.rest.issues.createComment({
26+
owner: context.repo.owner,
27+
repo: context.repo.repo,
28+
issue_number: context.payload.pull_request.number,
29+
body
30+
});
31+
}
32+
}
33+
34+
async function createDeployingComment({ github, context, core }) {
35+
const commentId = await findComment({ github, context, core });
36+
37+
const comment = `
38+
${PR_MARKER}
39+
### <span aria-hidden="true">⚙️</span> Website deploying to S3!
40+
41+
| Name | Link |
42+
|:-:|------------------------|
43+
|<span aria-hidden="true">🔨</span> Latest commit | ${context.payload.pull_request.head.sha} |
44+
`;
45+
46+
await setComment({ github, context, commentId, body: comment });
47+
}
48+
49+
async function createFailedComment({ github, context, core }) {
50+
const commentId = await findComment({ github, context, core });
51+
52+
const comment = `
53+
${PR_MARKER}
54+
### <span aria-hidden="true">❌</span> Deployment failed!
55+
56+
_Check the action logs for more information._
57+
58+
| Name | Link |
59+
|:-:|------------------------|
60+
|<span aria-hidden="true">🔨</span> Latest commit | ${context.payload.pull_request.head.sha} |
61+
`;
62+
63+
await setComment({ github, context, commentId, body: comment });
64+
}
65+
66+
async function createSuccessComment({ github, context, core }) {
67+
const commentId = await findComment({ github, context, core });
68+
69+
const websiteUrl = `http://${process.env.BUCKET_NAME}.s3-website-${process.env.AWS_REGION}.amazonaws.com/`;
70+
const comment = `
71+
${PR_MARKER}
72+
### <span aria-hidden="true">✅</span> Deploy Preview ready!
73+
74+
75+
| Name | Link |
76+
|:-:|------------------------|
77+
|<span aria-hidden="true">🔨</span> Latest commit | ${context.payload.pull_request.head.sha} |
78+
|<span aria-hidden="true">😎</span> Deploy Preview | ${websiteUrl} |
79+
`;
80+
81+
await setComment({ github, context, commentId, body: comment });
82+
}
83+
84+
async function deleteComment({ github, context, core }) {
85+
const commentId = await findComment({ github, context, core });
86+
87+
if (commentId) {
88+
await github.rest.issues.deleteComment({
89+
owner: context.repo.owner,
90+
repo: context.repo.repo,
91+
comment_id: commentId
92+
});
93+
}
94+
}
95+
96+
module.exports = {
97+
createDeployingComment,
98+
createFailedComment,
99+
createSuccessComment,
100+
deleteComment
101+
};
Lines changed: 119 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,119 @@
1+
name: Preview
2+
3+
on:
4+
pull_request:
5+
branches:
6+
- "*"
7+
8+
permissions:
9+
id-token: write
10+
contents: read
11+
issues: write
12+
pull-requests: write
13+
14+
env:
15+
BUCKET_NAME: ds-preview-stac-map-${{ github.event.number }}
16+
AWS_ROLE_ARN: arn:aws:iam::552819999234:role/stac-map-gh-preview
17+
AWS_REGION: us-west-2
18+
DIST_DIRECTORY: dist
19+
20+
jobs:
21+
build:
22+
runs-on: ubuntu-latest
23+
steps:
24+
- uses: actions/checkout@v4
25+
- uses: actions/setup-node@v4
26+
with:
27+
node-version-file: ".node-version"
28+
cache: "yarn"
29+
- name: Post building comment
30+
uses: actions/github-script@v6
31+
with:
32+
script: |
33+
const { createDeployingComment } = require('./.github/workflows/github-pr-update.cjs')
34+
await createDeployingComment({ github, context, core })
35+
- name: Install
36+
run: yarn install --ignore-engines
37+
- name: Build
38+
run: yarn build-preview
39+
- name: Post error comment
40+
uses: actions/github-script@v6
41+
if: failure()
42+
with:
43+
script: |
44+
const { createFailedComment } = require('./.github/workflows/github-pr-update.cjs')
45+
await createFailedComment({ github, context, core })
46+
- uses: actions/upload-artifact@v4
47+
with:
48+
path: ${{ env.DIST_DIRECTORY }}
49+
deploy:
50+
runs-on: ubuntu-latest
51+
needs: build
52+
steps:
53+
- uses: actions/checkout@v4
54+
- uses: aws-actions/configure-aws-credentials@v4
55+
with:
56+
role-to-assume: ${{ env.AWS_ROLE_ARN }}
57+
aws-region: ${{ env.AWS_REGION }}
58+
- uses: actions/download-artifact@v5
59+
with:
60+
path: ${{ env.DIST_DIRECTORY }}
61+
- name: Check if bucket exists
62+
id: check_bucket
63+
run: |
64+
if aws s3 ls "s3://${{ env.BUCKET_NAME }}" 2>&1 | grep -q 'NoSuchBucket'; then
65+
echo "Bucket does not exist."
66+
echo "exists=false" >> "$GITHUB_OUTPUT"
67+
else
68+
echo "Bucket exists."
69+
echo "exists=true" >> "$GITHUB_OUTPUT"
70+
fi
71+
- name: Create S3 bucket
72+
if: steps.check_bucket.outputs.exists == 'false'
73+
run: |
74+
aws s3 mb s3://${{ env.BUCKET_NAME }}
75+
- name: Enable static website hosting
76+
if: steps.check_bucket.outputs.exists == 'false'
77+
run: |
78+
aws s3 website \
79+
s3://${{ env.BUCKET_NAME }} \
80+
--index-document index.html \
81+
--error-document index.html
82+
- name: Sync files
83+
run: |
84+
aws s3 sync \
85+
./${{env.DIST_DIRECTORY}} s3://${{ env.BUCKET_NAME }} \
86+
--delete \
87+
--quiet
88+
- name: Make bucket public access
89+
if: steps.check_bucket.outputs.exists == 'false'
90+
run: |
91+
aws s3api delete-public-access-block --bucket ${{ env.BUCKET_NAME }}
92+
- name: Add bucket policy for public access
93+
if: steps.check_bucket.outputs.exists == 'false'
94+
run: |
95+
echo '{
96+
"Version": "2012-10-17",
97+
"Statement": [{
98+
"Sid": "PublicReadGetObject",
99+
"Effect": "Allow",
100+
"Principal": "*",
101+
"Action": "s3:GetObject",
102+
"Resource": "arn:aws:s3:::${{ env.BUCKET_NAME }}/*"
103+
}]
104+
}' > bucket-policy.json
105+
aws s3api put-bucket-policy --bucket ${{ env.BUCKET_NAME }} --policy file://bucket-policy.json
106+
- name: Post comment with preview URL
107+
uses: actions/github-script@v6
108+
if: success()
109+
with:
110+
script: |
111+
const { createSuccessComment } = require('./.github/workflows/github-pr-update.cjs')
112+
await createSuccessComment({ github, context, core })
113+
- name: Post error comment
114+
uses: actions/github-script@v6
115+
if: failure()
116+
with:
117+
script: |
118+
const { createFailedComment } = require('./.github/workflows/github-pr-update.cjs')
119+
await createFailedComment({ github, context, core })
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
name: Remove preview
2+
3+
on:
4+
pull_request_target:
5+
types: [ closed ]
6+
7+
env:
8+
BUCKET_NAME: ds-preview-stac-map-${{ github.event.number }}
9+
AWS_ROLE_ARN: arn:aws:iam::552819999234:role/stac-map-gh-preview
10+
AWS_REGION: us-west-2
11+
12+
permissions:
13+
id-token: write
14+
contents: read
15+
issues: write
16+
pull-requests: write
17+
18+
jobs:
19+
remove:
20+
runs-on: ubuntu-latest
21+
steps:
22+
- uses: actions/checkout@v4
23+
- uses: aws-actions/configure-aws-credentials@v4
24+
with:
25+
role-to-assume: ${{ env.AWS_ROLE_ARN }}
26+
aws-region: ${{ env.AWS_REGION }}
27+
- name: Check if bucket exists
28+
id: check_bucket
29+
run: |
30+
if aws s3 ls "s3://${{ env.BUCKET_NAME }}" 2>&1 | grep -q 'NoSuchBucket'; then
31+
echo "Bucket does not exist."
32+
echo "exists=false" >> "$GITHUB_OUTPUT"
33+
else
34+
echo "Bucket exists."
35+
echo "exists=true" >> "$GITHUB_OUTPUT"
36+
fi
37+
- name: Empty the bucket
38+
if: steps.check_bucket.outputs.exists == 'true'
39+
run: |
40+
aws s3 rm s3://$BUCKET_NAME --recursive --quiet
41+
- name: Remove the bucket
42+
if: steps.check_bucket.outputs.exists == 'true'
43+
run: |
44+
aws s3 rb s3://$BUCKET_NAME
45+
- name: Remove PR comment
46+
uses: actions/github-script@v6
47+
if: success()
48+
with:
49+
script: |
50+
const { deleteComment } = require('./.github/workflows/github-pr-update.cjs')
51+
await deleteComment({ github, context, core })

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
"scripts": {
2626
"dev": "vite",
2727
"build": "tsc -b && vite build",
28+
"build-preview": "tsc -b && vite build --base=/",
2829
"lint": "eslint .",
2930
"format": "prettier . --write",
3031
"format:check": "prettier . --check",

0 commit comments

Comments
 (0)