Skip to content

Commit 6c69227

Browse files
committed
Implement integration tests for forks
1 parent 82b02eb commit 6c69227

2 files changed

Lines changed: 295 additions & 0 deletions

File tree

Lines changed: 290 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,290 @@
1+
# Note: There is a copy of this workflow in ci.yml that is
2+
# used for triggering integration tests on forked PRs. If you tweak this
3+
# workflow, see if that also needs to be updated.
4+
5+
name: 'CI: Fork Integration Tests'
6+
7+
on:
8+
pull_request_target:
9+
types: [labeled, synchronize]
10+
branches:
11+
- main
12+
# For testing the workflow, remove before merging
13+
- fredrik/fork-integration-tests
14+
15+
permissions:
16+
contents: read
17+
18+
concurrency:
19+
group: ${{ github.workflow }}-${{ github.event.pull_request.number }}
20+
cancel-in-progress: true
21+
22+
jobs:
23+
remove-label-on-push:
24+
if: >-
25+
${{ github.event.action == 'synchronize'
26+
&& github.event.pull_request.head.repo.full_name != github.repository }}
27+
runs-on: 'blacksmith-8vcpu-ubuntu-2204'
28+
permissions:
29+
# Needed for removing the "safe-to-test" label
30+
pull-requests: write
31+
name: Remove safe-to-test label
32+
steps:
33+
- name: Remove safe-to-test label
34+
env:
35+
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
36+
PR_NUMBER: ${{ github.event.pull_request.number }}
37+
REPO: ${{ github.repository }}
38+
run: |
39+
gh pr edit "$PR_NUMBER" --repo "$REPO" --remove-label "safe-to-test" || true
40+
41+
check-label-permissions:
42+
if: >-
43+
${{ github.event.action == 'labeled'
44+
&& github.event.label.name == 'safe-to-test'
45+
&& github.event.pull_request.head.repo.full_name != github.repository }}
46+
runs-on: 'blacksmith-8vcpu-ubuntu-2204'
47+
permissions:
48+
pull-requests: write
49+
name: Check Label Sender Permissions
50+
steps:
51+
- name: Verify label sender has write access
52+
id: checkAccess
53+
uses: actions-cool/check-user-permission@v2
54+
with:
55+
require: write
56+
username: ${{ github.event.sender.login }}
57+
env:
58+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
59+
- name: Remove unauthorized label and fail
60+
if: ${{ steps.checkAccess.outputs.require-result == 'false' }}
61+
env:
62+
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
63+
PR_NUMBER: ${{ github.event.pull_request.number }}
64+
REPO: ${{ github.repository }}
65+
run: |
66+
echo "::error::User ${{ github.event.sender.login }} added safe-to-test but only has '${{ steps.checkAccess.outputs.user-permission }}' permission (write required)."
67+
gh pr edit "$PR_NUMBER" --repo "$REPO" --remove-label "safe-to-test" || true
68+
exit 1
69+
70+
integration-tests:
71+
needs: [check-label-permissions]
72+
if: >-
73+
${{ github.event.action == 'labeled'
74+
&& github.event.label.name == 'safe-to-test'
75+
&& github.event.pull_request.head.repo.full_name != github.repository
76+
&& github.event.pull_request.draft == false }}
77+
name: Integration Tests (${{ matrix.test-name }}, ${{ matrix.test-project }}${{ matrix.next-version && format(', {0}', matrix.next-version) || '' }})
78+
permissions:
79+
contents: read
80+
actions: write
81+
runs-on: 'blacksmith-8vcpu-ubuntu-2204'
82+
defaults:
83+
run:
84+
shell: bash
85+
timeout-minutes: ${{ vars.TIMEOUT_MINUTES_LONG && fromJSON(vars.TIMEOUT_MINUTES_LONG) || 15 }}
86+
87+
strategy:
88+
fail-fast: false
89+
# This needs to be kept in sync with ci.yml
90+
matrix:
91+
test-name:
92+
[
93+
'generic',
94+
'express',
95+
'fastify',
96+
'ap-flows',
97+
'localhost',
98+
'sessions',
99+
'sessions:staging',
100+
'handshake',
101+
'handshake:staging',
102+
'astro',
103+
'tanstack-react-start',
104+
'vue',
105+
'nuxt',
106+
'react-router',
107+
'custom',
108+
'hono',
109+
'chrome-extension',
110+
]
111+
test-project: ['chrome']
112+
include:
113+
- test-name: 'billing'
114+
test-project: 'chrome'
115+
- test-name: 'machine'
116+
test-project: 'chrome'
117+
- test-name: 'nextjs'
118+
test-project: 'chrome'
119+
next-version: '15'
120+
- test-name: 'nextjs'
121+
test-project: 'chrome'
122+
next-version: '16'
123+
- test-name: 'quickstart'
124+
test-project: 'chrome'
125+
next-version: '15'
126+
- test-name: 'quickstart'
127+
test-project: 'chrome'
128+
next-version: '16'
129+
- test-name: 'cache-components'
130+
test-project: 'chrome'
131+
next-version: '16'
132+
133+
steps:
134+
# Phase 1: Check out the base branch so that the composite action
135+
# at .github/actions/init-blacksmith comes from trusted code.
136+
- name: Checkout base branch
137+
uses: actions/checkout@v4
138+
with:
139+
fetch-depth: 1
140+
fetch-tags: false
141+
filter: 'blob:none'
142+
show-progress: false
143+
144+
- name: Setup (from base branch)
145+
id: config
146+
uses: ./.github/actions/init-blacksmith
147+
with:
148+
turbo-signature: ${{ secrets.TURBO_REMOTE_CACHE_SIGNATURE_KEY }}
149+
turbo-team: ${{ vars.TURBO_TEAM }}
150+
turbo-token: ${{ secrets.TURBO_TOKEN }}
151+
playwright-enabled: true
152+
153+
# Phase 2: Overlay the fork code at the exact SHA frozen in the event payload.
154+
# This SHA was captured when the label was applied and cannot be changed by
155+
# subsequent pushes to the fork branch.
156+
- name: Checkout fork PR (SHA-pinned)
157+
uses: actions/checkout@v4
158+
with:
159+
repository: ${{ github.event.pull_request.head.repo.full_name }}
160+
ref: ${{ github.event.pull_request.head.sha }}
161+
fetch-depth: 1
162+
fetch-tags: false
163+
filter: 'blob:none'
164+
show-progress: false
165+
clean: false
166+
167+
- name: Re-install dependencies for fork code
168+
run: pnpm install
169+
170+
- name: Verify jq is installed
171+
shell: bash
172+
run: |
173+
if ! command -v jq &> /dev/null; then
174+
echo "jq not found, installing..."
175+
sudo apt-get update && sudo apt-get install -y jq
176+
fi
177+
jq --version
178+
179+
- name: Validate turbo task
180+
env:
181+
E2E_APP_CLERK_JS_DIR: ${{runner.temp}}
182+
E2E_APP_CLERK_UI_DIR: ${{runner.temp}}
183+
E2E_CLERK_JS_VERSION: 'latest'
184+
E2E_CLERK_UI_VERSION: 'latest'
185+
E2E_NEXTJS_VERSION: ${{ matrix.next-version }}
186+
E2E_PROJECT: ${{ matrix.test-project }}
187+
INTEGRATION_INSTANCE_KEYS: ${{ secrets.INTEGRATION_INSTANCE_KEYS }}
188+
run: |
189+
TASK_NAME="test:integration:${{ matrix.test-name }}"
190+
TURBO_STDERR=$(mktemp)
191+
if ! TURBO_JSON=$(pnpm turbo run "$TASK_NAME" --dry=json 2>"$TURBO_STDERR"); then
192+
echo "::error::Turbo task '$TASK_NAME' failed validation"
193+
cat "$TURBO_STDERR"
194+
exit 1
195+
fi
196+
197+
if ! TASK_COUNT=$(jq -er '.tasks | length' <<< "$TURBO_JSON"); then
198+
echo "::error::Turbo task '$TASK_NAME' returned invalid JSON or missing .tasks"
199+
printf '%s\n' "$TURBO_JSON"
200+
exit 1
201+
fi
202+
203+
if [ "$TASK_COUNT" -eq 0 ]; then
204+
echo "::error::Turbo task '$TASK_NAME' returned 0 tasks"
205+
exit 1
206+
fi
207+
208+
echo "Task '$TASK_NAME' validated ($TASK_COUNT tasks in graph)"
209+
210+
- name: Build packages
211+
run: pnpm turbo build $TURBO_ARGS --only
212+
213+
- name: Publish to local registry
214+
run: pkglab pub --force
215+
216+
- name: Edit .npmrc [link-workspace-packages=false]
217+
run: sed -i -E 's/link-workspace-packages=(deep|true)/link-workspace-packages=false/' .npmrc
218+
219+
- name: Install @clerk/clerk-js in os temp
220+
working-directory: ${{runner.temp}}
221+
run: |
222+
mkdir clerk-js && cd clerk-js
223+
pnpm init
224+
pkglab add @clerk/clerk-js
225+
226+
- name: Install @clerk/ui in os temp
227+
working-directory: ${{runner.temp}}
228+
run: |
229+
mkdir clerk-ui && cd clerk-ui
230+
pnpm init
231+
pkglab add @clerk/ui
232+
233+
- name: Copy components @clerk/astro
234+
if: ${{ matrix.test-name == 'astro' }}
235+
run: cd packages/astro && pnpm copy:components
236+
237+
- name: Write all ENV certificates to files in integration/certs
238+
uses: actions/github-script@v7
239+
env:
240+
INTEGRATION_CERTS: '${{secrets.INTEGRATION_CERTS}}'
241+
INTEGRATION_ROOT_CA: '${{secrets.INTEGRATION_ROOT_CA}}'
242+
with:
243+
script: |
244+
const fs = require('fs');
245+
const path = require('path');
246+
const rootCa = process.env.INTEGRATION_ROOT_CA;
247+
console.log('rootCa', rootCa);
248+
fs.writeFileSync(path.join(process.env.GITHUB_WORKSPACE, 'integration/certs', 'rootCA.pem'), rootCa);
249+
const certs = JSON.parse(process.env.INTEGRATION_CERTS);
250+
for (const [name, cert] of Object.entries(certs)) {
251+
fs.writeFileSync(path.join(process.env.GITHUB_WORKSPACE, 'integration/certs', name), cert);
252+
}
253+
254+
- name: LS certs
255+
working-directory: ./integration/certs
256+
run: ls -la && pwd
257+
258+
- name: Run Integration Tests
259+
id: integration-tests
260+
timeout-minutes: 25
261+
run: pnpm turbo test:integration:${{ matrix.test-name }} $TURBO_ARGS
262+
env:
263+
E2E_DEBUG: '1'
264+
E2E_APP_CLERK_JS_DIR: ${{runner.temp}}
265+
E2E_APP_CLERK_UI_DIR: ${{runner.temp}}
266+
E2E_CLERK_JS_VERSION: 'latest'
267+
E2E_CLERK_UI_VERSION: 'latest'
268+
E2E_NEXTJS_VERSION: ${{ matrix.next-version }}
269+
E2E_PROJECT: ${{ matrix.test-project }}
270+
E2E_CLERK_ENCRYPTION_KEY: ${{ matrix.clerk-encryption-key }}
271+
INTEGRATION_INSTANCE_KEYS: ${{ secrets.INTEGRATION_INSTANCE_KEYS }}
272+
NODE_EXTRA_CA_CERTS: ${{ github.workspace }}/integration/certs/rootCA.pem
273+
VERCEL_AUTOMATION_BYPASS_SECRET: ${{ secrets.VERCEL_AUTOMATION_BYPASS_SECRET }}
274+
275+
- name: Sanitize artifact name
276+
if: ${{ cancelled() || failure() }}
277+
id: sanitize
278+
run: |
279+
SANITIZED="${TEST_NAME//:/-}"
280+
echo "artifact-suffix=${SANITIZED}" >> $GITHUB_OUTPUT
281+
env:
282+
TEST_NAME: ${{ matrix.test-name }}
283+
284+
- name: Upload test-results
285+
if: ${{ cancelled() || failure() }}
286+
uses: actions/upload-artifact@v4
287+
with:
288+
name: playwright-traces-fork-${{ github.run_id }}-${{ github.run_attempt }}-${{ steps.sanitize.outputs.artifact-suffix }}${{ matrix.next-version && format('-next{0}', matrix.next-version) || '' }}
289+
path: test-results
290+
retention-days: 1

.github/workflows/ci.yml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
# Note: There is a copy of this workflow in ci-fork-integration.yml that is
2+
# used for triggering integration tests on forked PRs. If you tweak this
3+
# workflow, see if that also needs to be updated.
4+
15
name: CI
26

37
on:
@@ -289,6 +293,7 @@ jobs:
289293

290294
strategy:
291295
fail-fast: false
296+
# This needs to be kept in sync with ci-fork-integration.yml
292297
matrix:
293298
test-name:
294299
[

0 commit comments

Comments
 (0)