Repository navigation
ci: run a curated e2e smoke subset on pull requests #3355
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: develop
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -2,24 +2,29 @@ | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| /* | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| * Resolves the spec list for a given Playwright shard using a duration baseline. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| * | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| * Usage: node getShardSpecs.js <shardIndex> <shardTotal> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| * Usage: node getShardSpecs.js <shardIndex> <shardTotal> [--smoke] | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| * | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| * Strategy: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| * 1. Read tests/pw/utils/shard-durations.json (committed baseline of spec → ms). | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| * 2. Discover every *.spec.ts under tests/e2e (so newly-added specs are not lost). | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| * 3. Greedy bin-pack longest-first into N bins. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| * 4. Print spec paths (one per line, relative to tests/pw) for the requested shard. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| * 3. With --smoke, keep only specs listed in pr-smoke-specs.json. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| * 4. Greedy bin-pack longest-first into N bins. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| * 5. Print spec paths (one per line, relative to tests/pw) for the requested shard. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| * | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| * If the baseline is missing, exits 0 with no output so the workflow can fall | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| * back to Playwright's built-in --shard. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| * back to Playwright's built-in --shard — except in --smoke mode, where falling | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| * back would silently run the FULL suite; there we pack the smoke list with | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| * equal weights instead. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+5
to
+17
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win Add the required documentation version placeholder. Proposed fix * equal weights instead.
+ *
+ * `@since` DOKAN_SINCE
*/As per coding guidelines, new code documentation must use the literal placeholder 📝 Committable suggestion
Suggested change
🤖 Prompt for AI AgentsSource: Coding guidelines |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| */ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| 'use strict'; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const fs = require('fs'); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const path = require('path'); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const [, , shardIndexArg, shardTotalArg] = process.argv; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const cliArgs = process.argv.slice(2); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const smoke = cliArgs.includes('--smoke'); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const [shardIndexArg, shardTotalArg] = cliArgs.filter(a => !a.startsWith('--')); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const shardIndex = parseInt(shardIndexArg, 10); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const shardTotal = parseInt(shardTotalArg, 10); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (!shardIndex || !shardTotal || shardIndex < 1 || shardIndex > shardTotal) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -31,12 +36,14 @@ const pwRoot = path.resolve(__dirname, '..'); | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const baselinePath = path.join(__dirname, 'shard-durations.json'); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const e2eRoot = path.join(pwRoot, 'tests', 'e2e'); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (!fs.existsSync(baselinePath)) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (!fs.existsSync(baselinePath) && !smoke) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // No baseline → fall back to alphabetical sharding upstream. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| process.exit(0); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const baseline = JSON.parse(fs.readFileSync(baselinePath, 'utf8')); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const baseline = fs.existsSync(baselinePath) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ? JSON.parse(fs.readFileSync(baselinePath, 'utf8')) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| : { specs: [] }; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const baselineByFile = new Map(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| for (const entry of baseline.specs || []) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| baselineByFile.set(entry.file, entry.ms || 0); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -64,7 +71,27 @@ if (!fs.existsSync(e2eRoot)) { | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| process.exit(0); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const allSpecs = walkSpecs(e2eRoot) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| let specFiles = walkSpecs(e2eRoot).map(f => f.split(path.sep).join('/')); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (smoke) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // Fail closed: silently degrading to the full 194-spec suite on a 5-shard | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // PR matrix is the exact cost blow-up --smoke exists to prevent. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const smokePath = path.join(__dirname, 'pr-smoke-specs.json'); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (!fs.existsSync(smokePath)) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| console.error('pr-smoke-specs.json missing — refusing to pack the full suite in smoke mode'); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| process.exit(2); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const { include } = JSON.parse(fs.readFileSync(smokePath, 'utf8')); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| specFiles = specFiles.filter(f => | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| include.some(entry => (entry.endsWith('/') ? f.startsWith(entry) : f === entry)) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (specFiles.length === 0) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| console.error('pr-smoke-specs.json matched no specs — check the include list'); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| process.exit(2); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const allSpecs = specFiles | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| .map(file => ({ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| file, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // Default newly-added (unmeasured) specs to the global mean so they | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,32 @@ | ||
| { | ||
| "description": "Curated e2e smoke subset run on pull_request events (the full suite still runs on the nightly schedule and manual workflow_dispatch). Entries are paths relative to tests/e2e/: a trailing slash includes the whole feature folder, otherwise the entry must match a spec file exactly. Consumed by getShardSpecs.js --smoke.", | ||
| "include": [ | ||
| "products/", | ||
| "product-form-manager/", | ||
| "vendor-products/", | ||
| "orders/", | ||
| "my-orders/", | ||
| "manual-order/", | ||
| "refunds/", | ||
| "coupons/", | ||
| "dashboard/", | ||
| "withdraws/", | ||
| "reverse-withdraws/", | ||
| "payments/", | ||
| "commission/", | ||
| "settings/", | ||
| "vendor-settings/", | ||
| "vendor/", | ||
| "stores/", | ||
| "store-listing/", | ||
| "single-store/", | ||
| "single-product/", | ||
| "shop/", | ||
| "customer/", | ||
| "plugin/", | ||
| "admin/admin.spec.ts", | ||
| "admin/adminDashboardHome.spec.ts", | ||
| "admin/adminVendors.spec.ts", | ||
| "admin/adminWithdraw.spec.ts" | ||
| ] | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win
Document the
develop-only PR trigger.The workflow runs this smoke path only for pull requests targeting
develop, but the documentation says “pull requests” generally. Qualify this as “pull requests targetingdevelop” to avoid misleading contributors about other base branches.🤖 Prompt for AI Agents