Skip to content

Commit 5f8b40e

Browse files
authored
chore(repo): Cleanup leftover users from the e2e instances (#2181)
* chore(repo): Cleanup leftover users from the e2e instances Playwright will not run the cleanup tasks on test failure, so it's possible that some temp users will not be deleted. * Create moody-radios-begin.md
1 parent e2d67fc commit 5f8b40e

File tree

5 files changed

+122
-1
lines changed

5 files changed

+122
-1
lines changed

.changeset/moody-radios-begin.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
---
2+
---

.github/workflows/e2e-cleanups.yml

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
name: Nightly upstream tests
2+
on:
3+
workflow_dispatch:
4+
schedule:
5+
- cron: '0 5,17 * * *'
6+
7+
jobs:
8+
integration-tests:
9+
name: Cleanup e2e instances
10+
runs-on: ${{ vars.RUNNER_NORMAL }}
11+
timeout-minutes: ${{ fromJSON(vars.TIMEOUT_MINUTES_NORMAL) }}
12+
13+
steps:
14+
- name: Checkout Repo
15+
uses: actions/checkout@v4
16+
with:
17+
fetch-depth: 0
18+
show-progress: false
19+
20+
- name: Setup
21+
id: config
22+
uses: ./.github/actions/init
23+
with:
24+
turbo-signature: ${{ secrets.TURBO_REMOTE_CACHE_SIGNATURE_KEY }}
25+
turbo-team: ${{ vars.TURBO_TEAM }}
26+
turbo-token: ${{ secrets.TURBO_TOKEN }}
27+
playwright-enabled: true
28+
29+
- name: Verdaccio
30+
uses: ./.github/actions/verdaccio
31+
with:
32+
publish-cmd: |
33+
if [ "$(npm config get registry)" = "https://registry.npmjs.org/" ]; then echo 'Error: Using default registry' && exit 1; else npx turbo build $TURBO_ARGS && npx changeset publish --no-git-tag; fi
34+
35+
- name: Install @clerk/backend in /integration
36+
working-directory: ./integration
37+
run: npm init -y && npm install @clerk/backend
38+
39+
- name: Run cleanup
40+
run: npm run test:integration:cleanup
41+
env:
42+
INTEGRATION_INSTANCE_KEYS: ${{ secrets.INTEGRATION_INSTANCE_KEYS }}
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
import type { User } from '@clerk/backend';
2+
import { Clerk } from '@clerk/backend';
3+
import { test as setup } from '@playwright/test';
4+
5+
import { appConfigs } from '../presets/';
6+
7+
setup('cleanup instances ', async () => {
8+
const secretKeys = Object.values(appConfigs.envs)
9+
.map(e => e.toJson())
10+
.map(json => json.private)
11+
.map(keys => keys['CLERK_SECRET_KEY'])
12+
.filter(Boolean);
13+
14+
for (const secretKey of secretKeys) {
15+
console.log(`Cleanup for ${secretKey.replace(/(sk_test_)(.+)(...)/, '$1***$3')}`);
16+
const clerkClient = Clerk({ secretKey });
17+
const { data: users, errors } = await clerkClient.users.getUserList({
18+
orderBy: '-created_at',
19+
query: 'clerkcookie',
20+
limit: 100,
21+
});
22+
23+
if (errors) {
24+
console.log(errors);
25+
return;
26+
}
27+
28+
const batches = batchElements(skipUsersThatWereCreatedToday(users), 5);
29+
for (const batch of batches) {
30+
console.log(`Starting batch...`);
31+
await Promise.all(
32+
batch.map(user => {
33+
console.log(
34+
`Cleaning up user ${user.id} (${user.emailAddresses[0]?.emailAddress}) (${new Date(
35+
user.createdAt,
36+
).toISOString()})`,
37+
);
38+
return clerkClient.users.deleteUser(user.id);
39+
}),
40+
);
41+
await new Promise(r => setTimeout(r, 1000));
42+
}
43+
}
44+
});
45+
46+
const skipUsersThatWereCreatedToday = (users: User[]): User[] => {
47+
const today = new Date();
48+
const todayString = today.toISOString().slice(0, 10);
49+
return users.filter(user => new Date(user.createdAt).toISOString().slice(0, 10) !== todayString);
50+
};
51+
52+
function batchElements<T>(users: T[], batchSize = 5): T[][] {
53+
const batches = [];
54+
for (let i = 0; i < users.length; i += batchSize) {
55+
batches.push(users.slice(i, i + batchSize));
56+
}
57+
return batches;
58+
}
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
import { defineConfig } from '@playwright/test';
2+
import { config } from 'dotenv';
3+
import * as path from 'path';
4+
5+
import { common } from './playwright.config';
6+
7+
config({ path: path.resolve(__dirname, '.env.local') });
8+
9+
export default defineConfig({
10+
...common,
11+
testDir: './cleanup',
12+
projects: [
13+
{
14+
name: 'setup',
15+
testMatch: /cleanup\.setup/,
16+
},
17+
],
18+
});

package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,8 +31,9 @@
3131
"test": "FORCE_COLOR=1 turbo test --concurrency=${TURBO_CONCURRENCY:-80%}",
3232
"test:cache:clear": "FORCE_COLOR=1 turbo test:cache:clear --continue --concurrency=${TURBO_CONCURRENCY:-80%}",
3333
"test:integration:base": "DEBUG=1 npx playwright test --config integration/playwright.config.ts",
34+
"test:integration:cleanup": "DEBUG=1 npx playwright test --config integration/playwright.cleanup.config.ts",
3435
"test:integration:deployment:nextjs": "DEBUG=1 npx playwright test --config integration/playwright.deployments.config.ts",
35-
"test:integration:express": "E2E_APP_ID=express.* npm run test:integration:base -- --grep \"@generic|@express\"",
36+
"test:integration:express": "E2E_APP_ID=express.* npm run test:integration:base -- --grep @express",
3637
"test:integration:generic": "E2E_APP_ID=react.vite.* npm run test:integration:base -- --grep @generic",
3738
"test:integration:nextjs": "E2E_APP_ID=next.appRouter.withEmailCodes npm run test:integration:base -- --grep \"@generic|@nextjs\"",
3839
"test:integration:remix": "echo 'placeholder'",

0 commit comments

Comments
 (0)