Skip to content

Commit e94a195

Browse files
committed
Add doc previews (v2)
1 parent d51a0f0 commit e94a195

File tree

2 files changed

+229
-0
lines changed

2 files changed

+229
-0
lines changed
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
name: Build Docs Preview
2+
3+
on:
4+
pull_request:
5+
types: [opened, reopened, synchronize]
6+
branches:
7+
# TODO once we merge to main, adjust this
8+
- 'workstream/cms-migration'
9+
10+
concurrency:
11+
group: preview-build-${{ github.event.pull_request.number }}
12+
cancel-in-progress: true
13+
14+
jobs:
15+
build:
16+
runs-on: ubuntu-latest
17+
permissions:
18+
contents: read
19+
20+
steps:
21+
- uses: actions/checkout@v4
22+
23+
- name: Set up Node.js
24+
uses: actions/setup-node@v6
25+
with:
26+
node-version: '20'
27+
28+
- name: Build CMS
29+
run: npm run cms:build
30+
31+
- name: Upload build artifact
32+
uses: actions/upload-artifact@v4
33+
with:
34+
name: docs-preview-${{ github.event.pull_request.number }}
35+
path: dist/
36+
retention-days: 1
37+
38+
- name: Save PR metadata
39+
run: |
40+
mkdir -p pr-metadata
41+
echo "${{ github.event.pull_request.number }}" > pr-metadata/pr_number
42+
echo "${{ github.event.pull_request.head.sha }}" > pr-metadata/pr_sha
43+
44+
- name: Upload PR metadata
45+
uses: actions/upload-artifact@v4
46+
with:
47+
name: pr-metadata-${{ github.event.pull_request.number }}
48+
path: pr-metadata/
49+
retention-days: 1
Lines changed: 180 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,180 @@
1+
name: Deploy Docs Preview
2+
3+
on:
4+
workflow_run:
5+
workflows: ["Build Docs Preview"]
6+
types:
7+
- completed
8+
9+
jobs:
10+
authorization-check:
11+
if: github.event.workflow_run.conclusion == 'success'
12+
permissions:
13+
contents: read
14+
actions: read
15+
runs-on: ubuntu-latest
16+
outputs:
17+
approval-env: ${{ steps.auth.outputs.result }}
18+
pr_number: ${{ steps.get-pr.outputs.pr_number }}
19+
pr_sha: ${{ steps.get-pr.outputs.pr_sha }}
20+
steps:
21+
- name: Download PR metadata
22+
uses: actions/download-artifact@v4
23+
with:
24+
name: pr-metadata-${{ github.event.workflow_run.pull_requests[0].number }}
25+
path: pr-metadata
26+
run-id: ${{ github.event.workflow_run.id }}
27+
github-token: ${{ secrets.GITHUB_TOKEN }}
28+
29+
- name: Get PR info
30+
id: get-pr
31+
run: |
32+
echo "pr_number=$(cat pr-metadata/pr_number)" >> $GITHUB_OUTPUT
33+
echo "pr_sha=$(cat pr-metadata/pr_sha)" >> $GITHUB_OUTPUT
34+
35+
- name: Get PR author
36+
id: get-author
37+
uses: actions/github-script@v8
38+
with:
39+
result-encoding: string
40+
script: |
41+
const { data: pr } = await github.rest.pulls.get({
42+
owner: context.repo.owner,
43+
repo: context.repo.repo,
44+
pull_number: ${{ steps.get-pr.outputs.pr_number }},
45+
});
46+
return pr.user.login;
47+
48+
- name: Check Authorization
49+
id: auth
50+
uses: strands-agents/devtools/authorization-check@main
51+
with:
52+
username: ${{ steps.get-author.outputs.result }}
53+
allowed-roles: 'write,maintain,admin'
54+
55+
approval-gate:
56+
runs-on: ubuntu-latest
57+
needs: [authorization-check]
58+
if: always() && needs.authorization-check.result == 'success'
59+
environment: ${{ needs.authorization-check.outputs.approval-env }}
60+
steps:
61+
- run: echo "Deployment approved"
62+
63+
deploy:
64+
runs-on: ubuntu-latest
65+
needs: [authorization-check, approval-gate]
66+
if: always() && needs.approval-gate.result == 'success'
67+
68+
permissions:
69+
contents: read
70+
issues: write
71+
pull-requests: write
72+
id-token: write
73+
actions: read
74+
75+
env:
76+
PR_NUMBER: ${{ needs.authorization-check.outputs.pr_number }}
77+
PR_HEAD_SHA: ${{ needs.authorization-check.outputs.pr_sha }}
78+
RUN_ID: ${{ github.run_id }}
79+
AWS_DEPLOY_ROLE: ${{ secrets.STRANDS_DOCS_DEPLOY_ROLE }}
80+
S3_BUCKET: ${{ secrets.STRANDS_DOCS_BUCKET }}
81+
CLOUDFRONT_DISTRIBUTION_ID: ${{ vars.CLOUDFRONT_DISTRIBUTION_ID }}
82+
CLOUDFRONT_DOMAIN: ${{ vars.CLOUDFRONT_DOMAIN }}
83+
84+
steps:
85+
- name: Download build artifact
86+
uses: actions/download-artifact@v4
87+
with:
88+
name: docs-preview-${{ env.PR_NUMBER }}
89+
path: dist
90+
run-id: ${{ github.event.workflow_run.id }}
91+
github-token: ${{ secrets.GITHUB_TOKEN }}
92+
93+
- name: Configure AWS credentials
94+
uses: aws-actions/configure-aws-credentials@v5
95+
with:
96+
role-to-assume: ${{ env.AWS_DEPLOY_ROLE }}
97+
role-session-name: GitHubActions-Docs-${{ env.RUN_ID }}
98+
aws-region: us-east-1
99+
mask-aws-account-id: true
100+
101+
- name: Deploy to S3
102+
run: |
103+
aws s3 sync dist/ s3://${{ env.S3_BUCKET }}/pr-local-cms-${{ env.PR_NUMBER }}/ \
104+
--cache-control "public, max-age=3600"
105+
106+
- name: Invalidate CloudFront cache for PR preview
107+
run: |
108+
aws cloudfront create-invalidation \
109+
--distribution-id ${{ env.CLOUDFRONT_DISTRIBUTION_ID }} \
110+
--invalidation-batch '{"Paths":{"Quantity":1,"Items":["/pr-local-cms-${{ env.PR_NUMBER }}/*"]},"CallerReference":"'$(date +%s)'"}'
111+
112+
- name: Comment on PR (success)
113+
if: success()
114+
uses: actions/github-script@v8
115+
env:
116+
PREVIEW_URL: https://${{ vars.CLOUDFRONT_DOMAIN }}/pr-local-cms-${{ needs.authorization-check.outputs.pr_number }}/
117+
with:
118+
script: |
119+
const prNumber = ${{ env.PR_NUMBER }};
120+
const previewUrl = process.env.PREVIEW_URL;
121+
122+
const comments = await github.rest.issues.listComments({
123+
owner: context.repo.owner,
124+
repo: context.repo.repo,
125+
issue_number: prNumber,
126+
});
127+
128+
const botComment = comments.data.find(comment =>
129+
comment.user.type === 'Bot' &&
130+
comment.body.includes('Documentation Preview')
131+
);
132+
133+
const body = [
134+
'## Documentation Preview Ready',
135+
'',
136+
'Your documentation preview has been successfully deployed!',
137+
'',
138+
`**Preview URL**: ${previewUrl}`,
139+
'',
140+
`_Updated at: ${new Date().toISOString()}_`
141+
].join('\n');
142+
143+
if (botComment) {
144+
await github.rest.issues.updateComment({
145+
owner: context.repo.owner,
146+
repo: context.repo.repo,
147+
comment_id: botComment.id,
148+
body: body
149+
});
150+
} else {
151+
await github.rest.issues.createComment({
152+
owner: context.repo.owner,
153+
repo: context.repo.repo,
154+
issue_number: prNumber,
155+
body: body
156+
});
157+
}
158+
159+
- name: Comment on PR (failure)
160+
if: failure()
161+
uses: actions/github-script@v8
162+
env:
163+
RUN_URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}
164+
with:
165+
script: |
166+
const prNumber = ${{ env.PR_NUMBER }};
167+
const runUrl = process.env.RUN_URL;
168+
169+
const body = [
170+
'## Documentation Preview Failed',
171+
'',
172+
`The documentation deployment encountered an error. Please check the [deployment logs](${runUrl}) for more details.`
173+
].join('\n');
174+
175+
await github.rest.issues.createComment({
176+
owner: context.repo.owner,
177+
repo: context.repo.repo,
178+
issue_number: prNumber,
179+
body: body
180+
});

0 commit comments

Comments
 (0)