Skip to content

Commit 7e53296

Browse files
committed
fix(workflow): change trigger from pull_request_target to pull_request for E2E tests
1 parent 8be1457 commit 7e53296

2 files changed

Lines changed: 296 additions & 2 deletions

File tree

Lines changed: 293 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,293 @@
1+
# E2E test workflow triggered by authorized PR comments
2+
# Users with write access can comment "/test" or "/run-e2e" to trigger tests
3+
name: test-e2e-comment
4+
5+
on:
6+
issue_comment:
7+
types: [created]
8+
9+
permissions:
10+
id-token: write
11+
contents: read
12+
pull-requests: write
13+
issues: write
14+
15+
jobs:
16+
# Check if the comment should trigger E2E tests
17+
check-authorization:
18+
if: |
19+
github.event.issue.pull_request &&
20+
(contains(github.event.comment.body, '/test') || contains(github.event.comment.body, '/run-e2e'))
21+
runs-on: ubuntu-latest
22+
outputs:
23+
authorized: ${{ steps.auth-check.outputs.authorized }}
24+
pr-number: ${{ steps.pr-info.outputs.pr-number }}
25+
pr-sha: ${{ steps.pr-info.outputs.pr-sha }}
26+
steps:
27+
- name: Check user authorization
28+
id: auth-check
29+
uses: actions/github-script@v7
30+
with:
31+
script: |
32+
try {
33+
// Check if user has write access to the repository
34+
const { data: permission } = await github.rest.repos.getCollaboratorPermissionLevel({
35+
owner: context.repo.owner,
36+
repo: context.repo.repo,
37+
username: context.actor
38+
});
39+
40+
const hasWriteAccess = ['admin', 'write'].includes(permission.permission);
41+
42+
if (hasWriteAccess) {
43+
console.log(`User ${context.actor} has ${permission.permission} access - authorized`);
44+
core.setOutput('authorized', 'true');
45+
46+
// React with 👀 to show the command was received
47+
await github.rest.reactions.createForIssueComment({
48+
owner: context.repo.owner,
49+
repo: context.repo.repo,
50+
comment_id: context.payload.comment.id,
51+
content: 'eyes'
52+
});
53+
} else {
54+
console.log(`User ${context.actor} has ${permission.permission} access - not authorized`);
55+
core.setOutput('authorized', 'false');
56+
57+
// React with ❌ to show unauthorized
58+
await github.rest.reactions.createForIssueComment({
59+
owner: context.repo.owner,
60+
repo: context.repo.repo,
61+
comment_id: context.payload.comment.id,
62+
content: 'confused'
63+
});
64+
65+
// Comment explaining the requirement
66+
await github.rest.issues.createComment({
67+
owner: context.repo.owner,
68+
repo: context.repo.repo,
69+
issue_number: context.issue.number,
70+
body: '❌ Only users with write access can trigger E2E tests. Please ask a maintainer to run the tests.'
71+
});
72+
}
73+
} catch (error) {
74+
console.log(`Error checking permissions: ${error}`);
75+
core.setOutput('authorized', 'false');
76+
}
77+
78+
- name: Get PR information
79+
id: pr-info
80+
if: steps.auth-check.outputs.authorized == 'true'
81+
uses: actions/github-script@v7
82+
with:
83+
script: |
84+
const { data: pr } = await github.rest.pulls.get({
85+
owner: context.repo.owner,
86+
repo: context.repo.repo,
87+
pull_number: context.issue.number
88+
});
89+
90+
core.setOutput('pr-number', pr.number);
91+
core.setOutput('pr-sha', pr.head.sha);
92+
93+
# Run the E2E tests
94+
deploy:
95+
needs: check-authorization
96+
if: needs.check-authorization.outputs.authorized == 'true'
97+
outputs:
98+
storeAdminIp: ${{ steps.kubectl_get_service.outputs.STORE_ADMIN_IP }}
99+
storeFrontIp: ${{ steps.kubectl_get_service.outputs.STORE_FRONT_IP }}
100+
runs-on: ubuntu-latest
101+
steps:
102+
- name: Add starting comment
103+
uses: actions/github-script@v7
104+
with:
105+
script: |
106+
await github.rest.issues.createComment({
107+
owner: context.repo.owner,
108+
repo: context.repo.repo,
109+
issue_number: ${{ needs.check-authorization.outputs.pr-number }},
110+
body: '🚀 Starting E2E tests for PR #${{ needs.check-authorization.outputs.pr-number }}...\n\n📊 [View workflow run](${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }})'
111+
});
112+
113+
- name: Checkout PR code
114+
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4
115+
with:
116+
ref: ${{ needs.check-authorization.outputs.pr-sha }}
117+
118+
- name: Install Terraform
119+
uses: hashicorp/setup-terraform@b9cd54a3c349d3f38e8881555d616ced269862dd # v3
120+
121+
- name: Install azd
122+
uses: Azure/setup-azd@ae0f8b5482eeac61e940f447327d84c73beb8b1e # v2.1.0
123+
124+
- name: Install kubelogin
125+
uses: azure/use-kubelogin@76597ae0fcbaace21b05e13a2cbf8daee2c6e820 # v1
126+
with:
127+
kubelogin-version: "v0.2.8"
128+
129+
- name: Azure CLI login
130+
uses: azure/login@a457da9ea143d694b1b9c7c869ebb04ebe844ef5 # v2
131+
with:
132+
client-id: ${{ secrets.AZURE_CLIENT_ID }}
133+
tenant-id: ${{ secrets.AZURE_TENANT_ID }}
134+
subscription-id: ${{ secrets.AZURE_SUBSCRIPTION_ID }}
135+
136+
- name: Azure Developer CLI login
137+
run: |
138+
azd auth login \
139+
--client-id ${{ secrets.AZURE_CLIENT_ID }} \
140+
--federated-credential-provider "github" \
141+
--tenant-id ${{ secrets.AZURE_TENANT_ID }}
142+
143+
- name: Turn on Helm support for azd
144+
run: azd config set alpha.aks.helm on
145+
146+
- name: Provision and deploy
147+
id: provision_deploy
148+
continue-on-error: true
149+
run: |
150+
# Create unique environment name for PR
151+
export PR_ENV_NAME="${{ vars.AZURE_ENV_NAME }}-pr-${{ needs.check-authorization.outputs.pr-number }}"
152+
azd env new $PR_ENV_NAME
153+
azd env set AKS_NODE_POOL_VM_SIZE Standard_D2_v4
154+
azd env set BUILD_CONTAINERS true
155+
azd env set DEPLOY_AZURE_CONTAINER_REGISTRY true
156+
azd env set DEPLOY_AZURE_OPENAI true
157+
azd env set AZURE_OPENAI_LOCATION ${{ vars.AZURE_LOCATION }}
158+
azd env set DEPLOY_AZURE_OPENAI_DALL_E_MODEL false
159+
azd env set DEPLOY_AZURE_SERVICE_BUS true
160+
azd env set DEPLOY_AZURE_COSMOSDB true
161+
azd env set AZURE_COSMOSDB_ACCOUNT_KIND MongoDB
162+
azd env set DEPLOY_OBSERVABILITY_TOOLS true
163+
azd up --no-prompt
164+
env:
165+
AZURE_ENV_NAME: ${{ vars.AZURE_ENV_NAME }}-pr-${{ needs.check-authorization.outputs.pr-number }}
166+
AZURE_LOCATION: ${{ vars.AZURE_LOCATION }}
167+
AZURE_SUBSCRIPTION_ID: ${{ secrets.AZURE_SUBSCRIPTION_ID }}
168+
169+
- name: Save azd cache
170+
uses: actions/cache/save@5a3ec84eff668545956fd18022155c47e93e2684 # v4
171+
if: always()
172+
with:
173+
path: |
174+
.azure/
175+
key: ${{ runner.os }}-azd-pr-${{ needs.check-authorization.outputs.pr-number }}-${{ github.run_id }}
176+
177+
- name: Check provision and deploy result
178+
if: steps.provision_deploy.outcome == 'failure'
179+
run: |
180+
echo "Provision and deploy failed"
181+
exit 1
182+
183+
- name: Get Store IPs
184+
id: kubectl_get_service
185+
if: steps.provision_deploy.outcome == 'success'
186+
run: |
187+
eval $(azd env get-values)
188+
storeAdminIp=$(kubectl get service store-admin -n $AZURE_AKS_NAMESPACE -o jsonpath='{.status.loadBalancer.ingress[0].ip}')
189+
while [ -z "$storeAdminIp" ]; do
190+
sleep 60
191+
storeAdminIp=$(kubectl get service store-admin -n $AZURE_AKS_NAMESPACE -o jsonpath='{.status.loadBalancer.ingress[0].ip}')
192+
done
193+
echo "STORE_ADMIN_IP=${storeAdminIp}"
194+
echo "STORE_ADMIN_IP=${storeAdminIp}" >> "$GITHUB_OUTPUT"
195+
storeFrontIp=$(kubectl get service store-front -n $AZURE_AKS_NAMESPACE -o jsonpath='{.status.loadBalancer.ingress[0].ip}')
196+
while [ -z "$storeFrontIp" ]; do
197+
sleep 60
198+
storeFrontIp=$(kubectl get service store-front -n $AZURE_AKS_NAMESPACE -o jsonpath='{.status.loadBalancer.ingress[0].ip}')
199+
done
200+
echo "STORE_FRONT_IP=${storeFrontIp}"
201+
echo "STORE_FRONT_IP=${storeFrontIp}" >> "$GITHUB_OUTPUT"
202+
203+
- name: Comment on deployment status
204+
if: always()
205+
uses: actions/github-script@v7
206+
with:
207+
script: |
208+
const success = '${{ steps.provision_deploy.outcome }}' === 'success';
209+
const emoji = success ? '✅' : '❌';
210+
const status = success ? 'succeeded' : 'failed';
211+
212+
let body = `${emoji} Deployment ${status} for PR #${{ needs.check-authorization.outputs.pr-number }}`;
213+
214+
if (success) {
215+
body += `\n\n🔗 **Test URLs:**\n- Store Admin: http://${{ steps.kubectl_get_service.outputs.STORE_ADMIN_IP }}\n- Store Front: http://${{ steps.kubectl_get_service.outputs.STORE_FRONT_IP }}`;
216+
}
217+
218+
await github.rest.issues.createComment({
219+
owner: context.repo.owner,
220+
repo: context.repo.repo,
221+
issue_number: ${{ needs.check-authorization.outputs.pr-number }},
222+
body: body
223+
});
224+
225+
playwright-tests:
226+
needs: [check-authorization, deploy]
227+
if: needs.check-authorization.outputs.authorized == 'true' && needs.deploy.result == 'success'
228+
uses: ./.github/workflows/test-playwright.yaml
229+
secrets: inherit
230+
with:
231+
storeAdminUrl: "http://${{ needs.deploy.outputs.storeAdminIp }}"
232+
storeFrontUrl: "http://${{ needs.deploy.outputs.storeFrontIp }}"
233+
234+
teardown:
235+
if: always() && needs.check-authorization.outputs.authorized == 'true'
236+
needs: [check-authorization, playwright-tests]
237+
runs-on: ubuntu-latest
238+
steps:
239+
- name: Checkout
240+
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4
241+
242+
- name: Install Terraform
243+
uses: hashicorp/setup-terraform@b9cd54a3c349d3f38e8881555d616ced269862dd # v3
244+
245+
- name: Install azd
246+
uses: Azure/setup-azd@ae0f8b5482eeac61e940f447327d84c73beb8b1e # v2.1.0
247+
248+
- name: Restore azd cache
249+
uses: actions/cache/restore@5a3ec84eff668545956fd18022155c47e93e2684 # v4
250+
with:
251+
path: |
252+
.azure/
253+
key: ${{ runner.os }}-azd-pr-${{ needs.check-authorization.outputs.pr-number }}-${{ github.run_id }}
254+
255+
- name: Azure CLI login
256+
uses: azure/login@a457da9ea143d694b1b9c7c869ebb04ebe844ef5 # v2
257+
with:
258+
client-id: ${{ secrets.AZURE_CLIENT_ID }}
259+
tenant-id: ${{ secrets.AZURE_TENANT_ID }}
260+
subscription-id: ${{ secrets.AZURE_SUBSCRIPTION_ID }}
261+
262+
- name: Azure Developer CLI login
263+
run: |
264+
azd auth login \
265+
--client-id ${{ secrets.AZURE_CLIENT_ID }} \
266+
--federated-credential-provider "github" \
267+
--tenant-id ${{ secrets.AZURE_TENANT_ID }}
268+
269+
- name: Destroy environment
270+
run: azd down --force --purge
271+
env:
272+
AZURE_ENV_NAME: ${{ vars.AZURE_ENV_NAME }}-pr-${{ needs.check-authorization.outputs.pr-number }}
273+
AZURE_LOCATION: ${{ vars.AZURE_LOCATION }}
274+
AZURE_SUBSCRIPTION_ID: ${{ secrets.AZURE_SUBSCRIPTION_ID }}
275+
276+
- name: Remove azd folder
277+
run: rm -rf .azure
278+
279+
- name: Final comment on test results
280+
if: always()
281+
uses: actions/github-script@v7
282+
with:
283+
script: |
284+
const testResult = '${{ needs.playwright-tests.result }}';
285+
const emoji = testResult === 'success' ? '✅' : '❌';
286+
const status = testResult === 'success' ? 'passed' : 'failed';
287+
288+
await github.rest.issues.createComment({
289+
owner: context.repo.owner,
290+
repo: context.repo.repo,
291+
issue_number: ${{ needs.check-authorization.outputs.pr-number }},
292+
body: `${emoji} E2E tests ${status} for PR #${{ needs.check-authorization.outputs.pr-number }}. Environment has been cleaned up.\n\n📊 [View full workflow run](${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }})`
293+
});

.github/workflows/test-e2e-pr.yaml

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,9 @@
33
name: test-e2e-pr
44

55
on:
6-
pull_request_target:
7-
branches: [main]
6+
pull_request:
7+
branches:
8+
- main
89

910
permissions:
1011
id-token: write

0 commit comments

Comments
 (0)