1+ name : Preview Pages Management
2+
3+ on :
4+ issue_comment :
5+ types : [created]
6+ pull_request :
7+ branches : [main]
8+ types : [closed]
9+
10+ jobs :
11+ check-permission :
12+ name : Check Author & Command
13+ if : github.event.issue.pull_request && contains(github.event.comment.body, '/preview')
14+ runs-on : ubuntu-latest
15+ outputs :
16+ authorized : ${{ steps.check.outputs.authorized }}
17+ steps :
18+ - name : Check user permissions
19+ id : check
20+ uses : actions/github-script@v7
21+ with :
22+ script : |
23+ const { owner, repo } = context.repo;
24+ const username = context.actor;
25+
26+ const { data: permission } = await github.rest.repos.getCollaboratorPermissionLevel({
27+ owner,
28+ repo,
29+ username,
30+ });
31+
32+ const allowed = ['admin', 'write'].includes(permission.permission);
33+ if (!allowed) {
34+ core.setFailed(`User @${username} is not authorized to trigger preview deployments.`);
35+ }
36+ core.setOutput('authorized', allowed);
37+
38+ notify-preview-start :
39+ name : Post Building Comment & Cleanup Trigger
40+ needs : check-permission
41+ runs-on : ubuntu-latest
42+ permissions :
43+ pull-requests : write
44+ outputs :
45+ pr_num : ${{ steps.pr_data.outputs.pr_num }}
46+ sha : ${{ steps.pr_data.outputs.sha }}
47+ ref : ${{ steps.pr_data.outputs.ref }}
48+ pr_author : ${{ steps.pr_data.outputs.pr_author }}
49+ comment_id : ${{ steps.create_comment.outputs.comment_id }}
50+ steps :
51+ - name : Get PR Information
52+ id : pr_data
53+ uses : actions/github-script@v7
54+ with :
55+ script : |
56+ const pr = await github.rest.pulls.get({
57+ owner: context.repo.owner,
58+ repo: context.repo.repo,
59+ pull_number: context.issue.number,
60+ });
61+ core.setOutput('pr_num', pr.data.number);
62+ core.setOutput('sha', pr.data.head.sha);
63+ core.setOutput('ref', pr.data.head.ref);
64+ core.setOutput('pr_author', pr.data.user.login);
65+
66+ - name : Delete triggering /preview comment
67+ uses : actions/github-script@v7
68+ with :
69+ script : |
70+ await github.rest.issues.deleteComment({
71+ owner: context.repo.owner,
72+ repo: context.repo.repo,
73+ comment_id: context.payload.comment.id,
74+ });
75+
76+ - name : Post "Preview building" comment
77+ id : create_comment
78+ uses : actions/github-script@v7
79+ with :
80+ script : |
81+ const triggerUser = context.actor;
82+ const prAuthor = "${{ steps.pr_data.outputs.pr_author }}";
83+
84+ let mentions = `@${triggerUser}`;
85+ if (prAuthor && prAuthor !== triggerUser) {
86+ mentions += ` @${prAuthor}`;
87+ }
88+
89+ const { data: comment } = await github.rest.issues.createComment({
90+ owner: context.repo.owner,
91+ repo: context.repo.repo,
92+ issue_number: context.issue.number,
93+ body: `⏳ **Preview building...**`,
94+ });
95+ core.setOutput('comment_id', comment.id);
96+
97+ deploy-preview :
98+ name : Deploy Preview to Cloudflare Pages
99+ needs : [check-permission, notify-preview-start]
100+ runs-on : ubuntu-latest
101+ permissions :
102+ pull-requests : write
103+ contents : read
104+ steps :
105+ - name : Checkout Engine
106+ uses : actions/checkout@v4
107+ with :
108+ path : engine
109+ repository : ThePythonLedger/Docusaurus-engine
110+
111+ - name : Checkout Curriculum (PR Code)
112+ uses : actions/checkout@v4
113+ with :
114+ path : Curriculum
115+ repository : ThePythonLedger/Curriculum
116+ ref : ${{ needs.notify-preview-start.outputs.sha }}
117+
118+ - name : Setup Node.js
119+ uses : actions/setup-node@v4
120+ with :
121+ node-version : 20
122+ cache : ' npm'
123+ cache-dependency-path : engine/package-lock.json
124+
125+ - name : Build Site Assets
126+ env :
127+ DOCUSAURUS_URL : https://engine-pr-${{ needs.notify-preview-start.outputs.pr_num }}.python-ledger-preview.pages.dev
128+ DOCUSAURUS_BASE_URL : /
129+ run : |
130+ cd engine
131+ npm ci
132+ npm run build
133+
134+ - name : Deploy to Cloudflare Pages
135+ uses : cloudflare/wrangler-action@v4
136+ id : cloudflare_deploy
137+ with :
138+ apiToken : ${{ secrets.CF_API_TOKEN }}
139+ accountId : ${{ secrets.CF_ACCOUNT_ID }}
140+ command : pages deploy engine/build --project-name=python-ledger-preview --branch=pr-${{ needs.notify-preview-start.outputs.pr_num }}
141+
142+ - name : Update Preview Comment with Link
143+ uses : actions/github-script@v7
144+ with :
145+ script : |
146+ const prNumber = ${{ needs.notify-preview-start.outputs.pr_num }};
147+ const prAuthor = "${{ needs.notify-preview-start.outputs.pr_author }}";
148+ const triggerUser = context.actor;
149+ const previewUrl = `https://pr-${prNumber}.python-ledger-preview.pages.dev`;
150+
151+ let mentions = `@${triggerUser}`;
152+ if (prAuthor && prAuthor !== triggerUser) {
153+ mentions += ` @${prAuthor}`;
154+ }
155+
156+ const message = `🚀 **Preview Deployment Ready!**\n\ncc ${mentions}\n\nView changes live at:\n${previewUrl}`;
157+
158+ await github.rest.issues.updateComment({
159+ owner: context.repo.owner,
160+ repo: context.repo.repo,
161+ comment_id: ${{ needs.notify-preview-start.outputs.comment_id }},
162+ body: message,
163+ });
164+
165+ - name : Mark Preview as Failed
166+ if : failure()
167+ uses : actions/github-script@v7
168+ with :
169+ script : |
170+ await github.rest.issues.updateComment({
171+ owner: context.repo.owner,
172+ repo: context.repo.repo,
173+ comment_id: ${{ needs.notify-preview-start.outputs.comment_id }},
174+ body: `❌ **Preview build failed.** Check the [workflow run](${context.serverUrl}/${context.repo.owner}/${context.repo.repo}/actions/runs/${context.runId}) for details.`,
175+ });
176+
177+ cleanup-preview :
178+ name : Delete Cloudflare Pages Preview
179+ if : github.event.action == 'closed'
180+ runs-on : ubuntu-latest
181+ steps :
182+ - name : Delete Cloudflare Pages Branch via API
183+ env :
184+ CLOUDFLARE_API_TOKEN : ${{ secrets.CF_API_TOKEN }}
185+ CLOUDFLARE_ACCOUNT_ID : ${{ secrets.CF_ACCOUNT_ID }}
186+ run : |
187+ BRANCH_NAME="pr-${{ github.event.number }}"
188+ PROJECT_NAME="python-ledger-preview"
189+
190+ echo "Deleting Cloudflare Pages branch: $BRANCH_NAME"
191+
192+ curl -s -X DELETE \
193+ "https://api.cloudflare.com/client/v4/accounts/${CLOUDFLARE_ACCOUNT_ID}/pages/projects/${PROJECT_NAME}/branches/${BRANCH_NAME}" \
194+ -H "Authorization: Bearer ${CLOUDFLARE_API_TOKEN}" \
195+ -H "Content-Type: application/json"
0 commit comments