From e19a74811b29c20ce2718af96a86745e96e5ce87 Mon Sep 17 00:00:00 2001 From: Pete Gadomski Date: Tue, 2 Dec 2025 08:57:48 -0700 Subject: [PATCH 1/6] ci: add github previews h/t https://github.com/developmentseed/how/issues/423 --- .github/workflows/github-pr-update.js | 101 ++++++++++++++++++++++ .github/workflows/preview-deploy.yaml | 118 ++++++++++++++++++++++++++ .github/workflows/preview-remove.yml | 51 +++++++++++ 3 files changed, 270 insertions(+) create mode 100644 .github/workflows/github-pr-update.js create mode 100644 .github/workflows/preview-deploy.yaml create mode 100644 .github/workflows/preview-remove.yml diff --git a/.github/workflows/github-pr-update.js b/.github/workflows/github-pr-update.js new file mode 100644 index 0000000..bd61aa7 --- /dev/null +++ b/.github/workflows/github-pr-update.js @@ -0,0 +1,101 @@ +const PR_MARKER = ''; + +async function findComment({ github, context, core }) { + const comments = await github.rest.issues.listComments({ + owner: context.repo.owner, + repo: context.repo.repo, + issue_number: context.payload.pull_request.number + }); + const existingComment = comments.data.find((comment) => + comment.body.includes(PR_MARKER) + ); + + return existingComment?.id; +} + +async function setComment({ github, context, commentId, body }) { + if (commentId) { + await github.rest.issues.updateComment({ + owner: context.repo.owner, + repo: context.repo.repo, + comment_id: commentId, + body + }); + } else { + await github.rest.issues.createComment({ + owner: context.repo.owner, + repo: context.repo.repo, + issue_number: context.payload.pull_request.number, + body + }); + } +} + +async function createDeployingComment({ github, context, core }) { + const commentId = await findComment({ github, context, core }); + + const comment = ` +${PR_MARKER} +### Website deploying to S3! + +| Name | Link | +|:-:|------------------------| +| Latest commit | ${context.payload.pull_request.head.sha} | +`; + + await setComment({ github, context, commentId, body: comment }); +} + +async function createFailedComment({ github, context, core }) { + const commentId = await findComment({ github, context, core }); + + const comment = ` +${PR_MARKER} +### Deployment failed! + +_Check the action logs for more information._ + +| Name | Link | +|:-:|------------------------| +| Latest commit | ${context.payload.pull_request.head.sha} | +`; + + await setComment({ github, context, commentId, body: comment }); +} + +async function createSuccessComment({ github, context, core }) { + const commentId = await findComment({ github, context, core }); + + const websiteUrl = `http://${process.env.BUCKET_NAME}.s3-website-${process.env.AWS_REGION}.amazonaws.com/`; + const comment = ` +${PR_MARKER} +### Deploy Preview ready! + + +| Name | Link | +|:-:|------------------------| +| Latest commit | ${context.payload.pull_request.head.sha} | +| Deploy Preview | ${websiteUrl} | +`; + + await setComment({ github, context, commentId, body: comment }); +} + +async function deleteComment({ github, context, core }) { + const commentId = await findComment({ github, context, core }); + + if (commentId) { + await github.rest.issues.deleteComment({ + owner: context.repo.owner, + repo: context.repo.repo, + comment_id: commentId + }); + } +} + +module.exports = { + createDeployingComment, + createFailedComment, + createSuccessComment, + deleteComment +}; diff --git a/.github/workflows/preview-deploy.yaml b/.github/workflows/preview-deploy.yaml new file mode 100644 index 0000000..76282f7 --- /dev/null +++ b/.github/workflows/preview-deploy.yaml @@ -0,0 +1,118 @@ +name: Preview + +on: + pull_request: + branches: + - "*" + +permissions: + id-token: write + contents: read + issues: write + pull-requests: write + +env: + BUCKET_NAME: ds-preview-stac-map-${{ github.event.number }} + AWS_ROLE_ARN: arn:aws:iam::552819999234:role/stac-map-gh-preview + AWS_REGION: us-west-2 + DIST_DIRECTORY: dist + +jobs: + build: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-node@v4 + with: + node-version-file: ".node-version" + cache: "yarn" + - name: Post building comment + uses: actions/github-script@v6 + with: + script: | + const { createDeployingComment } = require('./.github/workflows/github-pr-update.js') + await createDeployingComment({ github, context, core }) + - name: Install + run: yarn install --ignore-engines + - name: Build + run: yarn build + - name: Post error comment + uses: actions/github-script@v6 + if: failure() + with: + script: | + const { createFailedComment } = require('./.github/workflows/github-pr-update.js') + await createFailedComment({ github, context, core }) + - uses: actions/upload-artifact@v4 + with: + path: ${{ env.DIST_DIRECTORY }} + deploy: + runs-on: ubuntu-latest + needs: build + steps: + - uses: aws-actions/configure-aws-credentials@v4 + with: + role-to-assume: ${{ env.AWS_ROLE_ARN }} + aws-region: ${{ env.AWS_REGION }} + - uses: actions/download-artifact@v5 + with: + path: ${{ env.DIST_DIRECTORY }} + - name: Check if bucket exists + id: check_bucket + run: | + if aws s3 ls "s3://${{ env.BUCKET_NAME }}" 2>&1 | grep -q 'NoSuchBucket'; then + echo "Bucket does not exist." + echo "exists=false" >> "$GITHUB_OUTPUT" + else + echo "Bucket exists." + echo "exists=true" >> "$GITHUB_OUTPUT" + fi + - name: Create S3 bucket + if: steps.check_bucket.outputs.exists == 'false' + run: | + aws s3 mb s3://${{ env.BUCKET_NAME }} + - name: Enable static website hosting + if: steps.check_bucket.outputs.exists == 'false' + run: | + aws s3 website \ + s3://${{ env.BUCKET_NAME }} \ + --index-document index.html \ + --error-document index.html + - name: Sync files + run: | + aws s3 sync \ + ./${{env.DIST_DIRECTORY}} s3://${{ env.BUCKET_NAME }} \ + --delete \ + --quiet + - name: Make bucket public access + if: steps.check_bucket.outputs.exists == 'false' + run: | + aws s3api delete-public-access-block --bucket ${{ env.BUCKET_NAME }} + - name: Add bucket policy for public access + if: steps.check_bucket.outputs.exists == 'false' + run: | + echo '{ + "Version": "2012-10-17", + "Statement": [{ + "Sid": "PublicReadGetObject", + "Effect": "Allow", + "Principal": "*", + "Action": "s3:GetObject", + "Resource": "arn:aws:s3:::${{ env.BUCKET_NAME }}/*" + }] + }' > bucket-policy.json + aws s3api put-bucket-policy --bucket ${{ env.BUCKET_NAME }} --policy file://bucket-policy.json + - name: Post error comment + uses: actions/github-script@v6 + if: success() + with: + script: | + const { createSuccessComment } = require('./.github/workflows/github-pr-update.js') + await createSuccessComment({ github, context, core }) + - name: Post comment with preview URL + uses: actions/github-script@v6 + if: failure() + with: + script: | + const { createFailedComment } = require('./.github/workflows/github-pr-update.js') + await createFailedComment({ github, context, core }) diff --git a/.github/workflows/preview-remove.yml b/.github/workflows/preview-remove.yml new file mode 100644 index 0000000..f9431d1 --- /dev/null +++ b/.github/workflows/preview-remove.yml @@ -0,0 +1,51 @@ +name: Remove preview + +on: + pull_request_target: + types: [ closed ] + +env: + BUCKET_NAME: ds-preview-stac-map-${{ github.event.number }} + AWS_ROLE_ARN: arn:aws:iam::552819999234:role/stac-map-gh-preview + AWS_REGION: us-west-2 + +permissions: + id-token: write + contents: read + issues: write + pull-requests: write + +jobs: + remove: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: aws-actions/configure-aws-credentials@v4 + with: + role-to-assume: ${{ env.AWS_ROLE_ARN }} + aws-region: ${{ env.AWS_REGION }} + - name: Check if bucket exists + id: check_bucket + run: | + if aws s3 ls "s3://${{ env.BUCKET_NAME }}" 2>&1 | grep -q 'NoSuchBucket'; then + echo "Bucket does not exist." + echo "exists=false" >> "$GITHUB_OUTPUT" + else + echo "Bucket exists." + echo "exists=true" >> "$GITHUB_OUTPUT" + fi + - name: Empty the bucket + if: steps.check_bucket.outputs.exists == 'true' + run: | + aws s3 rm s3://$BUCKET_NAME --recursive --quiet + - name: Remove the bucket + if: steps.check_bucket.outputs.exists == 'true' + run: | + aws s3 rb s3://$BUCKET_NAME + - name: Remove PR comment + uses: actions/github-script@v6 + if: success() + with: + script: | + const { deleteComment } = require('./.github/workflows/github-pr-update.js') + await deleteComment({ github, context, core }) From b8058b15adb7bb76276fa82cc7626097c34a1828 Mon Sep 17 00:00:00 2001 From: Pete Gadomski Date: Tue, 2 Dec 2025 08:59:36 -0700 Subject: [PATCH 2/6] fix: try cjs --- .github/workflows/{github-pr-update.js => github-pr-update.cjs} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename .github/workflows/{github-pr-update.js => github-pr-update.cjs} (100%) diff --git a/.github/workflows/github-pr-update.js b/.github/workflows/github-pr-update.cjs similarity index 100% rename from .github/workflows/github-pr-update.js rename to .github/workflows/github-pr-update.cjs From bb971ee402c71a887c5dee371dd27952f89fdd06 Mon Sep 17 00:00:00 2001 From: Pete Gadomski Date: Tue, 2 Dec 2025 09:01:09 -0700 Subject: [PATCH 3/6] fix: file name --- .github/workflows/preview-deploy.yaml | 8 ++++---- .github/workflows/preview-remove.yml | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/.github/workflows/preview-deploy.yaml b/.github/workflows/preview-deploy.yaml index 76282f7..6df8f8b 100644 --- a/.github/workflows/preview-deploy.yaml +++ b/.github/workflows/preview-deploy.yaml @@ -30,7 +30,7 @@ jobs: uses: actions/github-script@v6 with: script: | - const { createDeployingComment } = require('./.github/workflows/github-pr-update.js') + const { createDeployingComment } = require('./.github/workflows/github-pr-update.cjs') await createDeployingComment({ github, context, core }) - name: Install run: yarn install --ignore-engines @@ -41,7 +41,7 @@ jobs: if: failure() with: script: | - const { createFailedComment } = require('./.github/workflows/github-pr-update.js') + const { createFailedComment } = require('./.github/workflows/github-pr-update.cjs') await createFailedComment({ github, context, core }) - uses: actions/upload-artifact@v4 with: @@ -107,12 +107,12 @@ jobs: if: success() with: script: | - const { createSuccessComment } = require('./.github/workflows/github-pr-update.js') + const { createSuccessComment } = require('./.github/workflows/github-pr-update.cjs') await createSuccessComment({ github, context, core }) - name: Post comment with preview URL uses: actions/github-script@v6 if: failure() with: script: | - const { createFailedComment } = require('./.github/workflows/github-pr-update.js') + const { createFailedComment } = require('./.github/workflows/github-pr-update.cjs') await createFailedComment({ github, context, core }) diff --git a/.github/workflows/preview-remove.yml b/.github/workflows/preview-remove.yml index f9431d1..429b6eb 100644 --- a/.github/workflows/preview-remove.yml +++ b/.github/workflows/preview-remove.yml @@ -47,5 +47,5 @@ jobs: if: success() with: script: | - const { deleteComment } = require('./.github/workflows/github-pr-update.js') + const { deleteComment } = require('./.github/workflows/github-pr-update.cjs') await deleteComment({ github, context, core }) From 27dfb36efb919ab750189933b913279937b77276 Mon Sep 17 00:00:00 2001 From: Pete Gadomski Date: Tue, 2 Dec 2025 09:04:32 -0700 Subject: [PATCH 4/6] fix: add checkout to deploy --- .github/workflows/preview-deploy.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/preview-deploy.yaml b/.github/workflows/preview-deploy.yaml index 6df8f8b..9ec8b59 100644 --- a/.github/workflows/preview-deploy.yaml +++ b/.github/workflows/preview-deploy.yaml @@ -50,6 +50,7 @@ jobs: runs-on: ubuntu-latest needs: build steps: + - uses: actions/checkout@v4 - uses: aws-actions/configure-aws-credentials@v4 with: role-to-assume: ${{ env.AWS_ROLE_ARN }} From ebed5320363cfcc46ca6de9e062eb2aa2e30a421 Mon Sep 17 00:00:00 2001 From: Pete Gadomski Date: Tue, 2 Dec 2025 09:07:00 -0700 Subject: [PATCH 5/6] fix: name of steps --- .github/workflows/preview-deploy.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/preview-deploy.yaml b/.github/workflows/preview-deploy.yaml index 9ec8b59..87a70a1 100644 --- a/.github/workflows/preview-deploy.yaml +++ b/.github/workflows/preview-deploy.yaml @@ -103,14 +103,14 @@ jobs: }] }' > bucket-policy.json aws s3api put-bucket-policy --bucket ${{ env.BUCKET_NAME }} --policy file://bucket-policy.json - - name: Post error comment + - name: Post comment with preview URL uses: actions/github-script@v6 if: success() with: script: | const { createSuccessComment } = require('./.github/workflows/github-pr-update.cjs') await createSuccessComment({ github, context, core }) - - name: Post comment with preview URL + - name: Post error comment uses: actions/github-script@v6 if: failure() with: From 82ec58d34afe8f3f7267f616ddae03178ad3a017 Mon Sep 17 00:00:00 2001 From: Pete Gadomski Date: Tue, 2 Dec 2025 09:11:03 -0700 Subject: [PATCH 6/6] fix: build with / base --- .github/workflows/preview-deploy.yaml | 2 +- package.json | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/preview-deploy.yaml b/.github/workflows/preview-deploy.yaml index 87a70a1..fbe541f 100644 --- a/.github/workflows/preview-deploy.yaml +++ b/.github/workflows/preview-deploy.yaml @@ -35,7 +35,7 @@ jobs: - name: Install run: yarn install --ignore-engines - name: Build - run: yarn build + run: yarn build-preview - name: Post error comment uses: actions/github-script@v6 if: failure() diff --git a/package.json b/package.json index d354237..4a345df 100644 --- a/package.json +++ b/package.json @@ -25,6 +25,7 @@ "scripts": { "dev": "vite", "build": "tsc -b && vite build", + "build-preview": "tsc -b && vite build --base=/", "lint": "eslint .", "format": "prettier . --write", "format:check": "prettier . --check",