playwright-slack-report-burak 3.0.17 â 3.0.19
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/src/ResultsParser.js +51 -40
- package/dist/src/SlackReporter.js +51 -23
- package/package.json +1 -1
|
@@ -35,10 +35,14 @@ class ResultsParser {
|
|
|
35
35
|
separateFlakyTests;
|
|
36
36
|
// Handle both 0-based and 1-based shard indexing
|
|
37
37
|
// If MATRIX_SHARD is not set, try to infer from workflow (1-based) or default to 0
|
|
38
|
-
totalShardCount = process.env.
|
|
39
|
-
|
|
40
|
-
? parseInt(process.env.
|
|
41
|
-
|
|
38
|
+
totalShardCount = process.env.TOTAL_SHARDS
|
|
39
|
+
? parseInt(process.env.TOTAL_SHARDS, 10)
|
|
40
|
+
: (process.env.MATRIX_COUNT ? parseInt(process.env.MATRIX_COUNT, 10) : 1);
|
|
41
|
+
shardIndex = process.env.SHARD_INDEX !== undefined
|
|
42
|
+
? parseInt(process.env.SHARD_INDEX, 10)
|
|
43
|
+
: (process.env.MATRIX_SHARD !== undefined
|
|
44
|
+
? parseInt(process.env.MATRIX_SHARD, 10)
|
|
45
|
+
: (process.env.MATRIX_INDEX !== undefined ? parseInt(process.env.MATRIX_INDEX, 10) : 0));
|
|
42
46
|
|
|
43
47
|
// Determine if we're using 1-based indexing (workflow-style) or 0-based
|
|
44
48
|
// This is detected by checking if artifacts exist with 1-based naming
|
|
@@ -50,6 +54,8 @@ class ResultsParser {
|
|
|
50
54
|
console.log(`đĻ [ResultsParser] playwright-slack-report-burak v${packageVersion}`);
|
|
51
55
|
// Log shard detection in ResultsParser
|
|
52
56
|
console.log('đ [ResultsParser] Initialized with shard detection:');
|
|
57
|
+
console.log(`đ SHARD_INDEX env: ${process.env.SHARD_INDEX !== undefined ? `"${process.env.SHARD_INDEX}"` : 'undefined'}`);
|
|
58
|
+
console.log(`đ TOTAL_SHARDS env: ${process.env.TOTAL_SHARDS !== undefined ? `"${process.env.TOTAL_SHARDS}"` : 'undefined'}`);
|
|
53
59
|
console.log(`đ MATRIX_SHARD env: ${process.env.MATRIX_SHARD !== undefined ? `"${process.env.MATRIX_SHARD}"` : 'undefined'}`);
|
|
54
60
|
console.log(`đ MATRIX_INDEX env: ${process.env.MATRIX_INDEX !== undefined ? `"${process.env.MATRIX_INDEX}"` : 'undefined'}`);
|
|
55
61
|
console.log(`đ MATRIX_COUNT env: ${process.env.MATRIX_COUNT !== undefined ? `"${process.env.MATRIX_COUNT}"` : 'undefined'}`);
|
|
@@ -58,7 +64,7 @@ class ResultsParser {
|
|
|
58
64
|
}
|
|
59
65
|
/**
|
|
60
66
|
* Update shard information after detection (e.g., from GitHub API)
|
|
61
|
-
* @param {number} shardIndex - The current shard index (
|
|
67
|
+
* @param {number} shardIndex - The current shard index (1-based, shard 1 is aggregator)
|
|
62
68
|
* @param {number} totalShardCount - The total number of shards
|
|
63
69
|
*/
|
|
64
70
|
updateShardInfo(shardIndex, totalShardCount) {
|
|
@@ -124,8 +130,8 @@ class ResultsParser {
|
|
|
124
130
|
console.log(`đ [ResultsParser] Current shard: ${this.shardIndex}, Total shards: ${this.totalShardCount}`);
|
|
125
131
|
console.log(`đ [ResultsParser] Created node summary file: ${nodeSummaryFile}`);
|
|
126
132
|
|
|
127
|
-
if (this.shardIndex ===
|
|
128
|
-
console.log(`đ [ResultsParser] Shard
|
|
133
|
+
if (this.shardIndex === 1 && this.totalShardCount > 1) {
|
|
134
|
+
console.log(`đ [ResultsParser] Shard 1 detected with ${this.totalShardCount} total shards - will fetch artifacts from other shards`);
|
|
129
135
|
if (process.env.CI) {
|
|
130
136
|
console.log('đ [ResultsParser] CI environment detected - fetching all artifacts from GitHub Actions...');
|
|
131
137
|
await this.fetchAllArtifacts();
|
|
@@ -137,13 +143,14 @@ class ResultsParser {
|
|
|
137
143
|
}
|
|
138
144
|
}
|
|
139
145
|
} else {
|
|
140
|
-
console.log(`đ [ResultsParser] Not shard
|
|
146
|
+
console.log(`đ [ResultsParser] Not shard 1 (current: ${this.shardIndex}) or single shard (total: ${this.totalShardCount}) - skipping artifact fetch`);
|
|
141
147
|
}
|
|
142
148
|
|
|
143
|
-
if (this.shardIndex ===
|
|
144
|
-
console.log(`đ [ResultsParser] Shard
|
|
149
|
+
if (this.shardIndex === 1 && this.allNodeSummaryFilesExist() && this.allBlobZipsExist()) {
|
|
150
|
+
console.log(`đ [ResultsParser] Shard 1: All artifacts available, merging results from all shards...`);
|
|
145
151
|
// Merge all node summaries into the final summary
|
|
146
|
-
|
|
152
|
+
// Loop from 1 to totalShardCount (1-based indexing)
|
|
153
|
+
for (let i = 1; i <= this.totalShardCount; i++) {
|
|
147
154
|
const nodeSummaryFile = path.join(summariesDir, `node_summary_${i}.json`);
|
|
148
155
|
const fileToRead = nodeSummaryFile;
|
|
149
156
|
|
|
@@ -358,7 +365,8 @@ class ResultsParser {
|
|
|
358
365
|
console.log('Checking if all node summary files exist...');
|
|
359
366
|
const summariesDir = path.join('./', 'playwright-report');
|
|
360
367
|
|
|
361
|
-
|
|
368
|
+
// Check files from 1 to totalShardCount (1-based indexing)
|
|
369
|
+
for (let i = 1; i <= this.totalShardCount; i++) {
|
|
362
370
|
const nodeSummaryFile = path.join(summariesDir, `node_summary_${i}.json`);
|
|
363
371
|
if (!fs.existsSync(nodeSummaryFile)) {
|
|
364
372
|
return false;
|
|
@@ -371,7 +379,8 @@ class ResultsParser {
|
|
|
371
379
|
console.log('Checking if all blob zips exist...');
|
|
372
380
|
const summariesDir = path.join('./', 'playwright-report');
|
|
373
381
|
|
|
374
|
-
|
|
382
|
+
// Check files from 1 to totalShardCount (1-based indexing)
|
|
383
|
+
for (let i = 1; i <= this.totalShardCount; i++) {
|
|
375
384
|
const blobZipFile = path.join(summariesDir, `blob-report-node-${i}.zip`);
|
|
376
385
|
if (!fs.existsSync(blobZipFile)) {
|
|
377
386
|
return false;
|
|
@@ -386,12 +395,13 @@ class ResultsParser {
|
|
|
386
395
|
fs.mkdirSync(summariesDir, { recursive: true });
|
|
387
396
|
}
|
|
388
397
|
|
|
389
|
-
console.log(`Shard
|
|
398
|
+
console.log(`Shard 1: Waiting for artifacts from ${this.totalShardCount - 1} other shard(s)...`);
|
|
390
399
|
|
|
391
|
-
// Fetch artifacts for shards
|
|
392
|
-
// We need to fetch from all
|
|
393
|
-
for (let i = 1; i
|
|
394
|
-
|
|
400
|
+
// Fetch artifacts for all shards except shard 1 (since we're shard 1)
|
|
401
|
+
// We need to fetch from shards 2, 3, 4, ... (all except shard 1, using 1-based indexing)
|
|
402
|
+
for (let i = 1; i <= this.totalShardCount; i++) {
|
|
403
|
+
if (i === 1) continue; // Skip shard 1 (we are shard 1)
|
|
404
|
+
console.log(`Shard 1: Fetching artifacts from shard ${i}...`);
|
|
395
405
|
await this.fetchArtifact(i, `node_summary_${i}.json`, summariesDir);
|
|
396
406
|
await this.fetchArtifact(i, `blob-report-node-${i}.zip`, summariesDir);
|
|
397
407
|
}
|
|
@@ -401,20 +411,21 @@ class ResultsParser {
|
|
|
401
411
|
const maxRetries = 60; // Wait up to 10 minutes (60 * 10 seconds)
|
|
402
412
|
|
|
403
413
|
while ((!this.allNodeSummaryFilesExist() || !this.allBlobZipsExist()) && retryCount < maxRetries) {
|
|
404
|
-
console.log(`Shard
|
|
414
|
+
console.log(`Shard 1: Waiting for all artifacts to be available (attempt ${retryCount + 1}/${maxRetries})...`);
|
|
405
415
|
|
|
406
416
|
// Re-fetch any missing artifacts
|
|
407
|
-
for (let i = 1; i
|
|
417
|
+
for (let i = 1; i <= this.totalShardCount; i++) {
|
|
418
|
+
if (i === 1) continue; // Skip shard 1 (we are shard 1)
|
|
408
419
|
const nodeSummaryFile = path.join(summariesDir, `node_summary_${i}.json`);
|
|
409
420
|
const blobZipFile = path.join(summariesDir, `blob-report-node-${i}.zip`);
|
|
410
421
|
|
|
411
422
|
if (!fs.existsSync(nodeSummaryFile)) {
|
|
412
|
-
console.log(`Shard
|
|
423
|
+
console.log(`Shard 1: Re-fetching missing node_summary_${i}.json...`);
|
|
413
424
|
await this.fetchArtifact(i, `node_summary_${i}.json`, summariesDir);
|
|
414
425
|
}
|
|
415
426
|
|
|
416
427
|
if (!fs.existsSync(blobZipFile)) {
|
|
417
|
-
console.log(`Shard
|
|
428
|
+
console.log(`Shard 1: Re-fetching missing blob-report-node-${i}.zip...`);
|
|
418
429
|
await this.fetchArtifact(i, `blob-report-node-${i}.zip`, summariesDir);
|
|
419
430
|
}
|
|
420
431
|
}
|
|
@@ -426,9 +437,9 @@ class ResultsParser {
|
|
|
426
437
|
}
|
|
427
438
|
|
|
428
439
|
if (this.allNodeSummaryFilesExist() && this.allBlobZipsExist()) {
|
|
429
|
-
console.log(`Shard
|
|
440
|
+
console.log(`Shard 1: Successfully fetched all artifacts from ${this.totalShardCount - 1} other shard(s).`);
|
|
430
441
|
} else {
|
|
431
|
-
console.warn(`Shard
|
|
442
|
+
console.warn(`Shard 1: Warning - Some artifacts may still be missing after ${maxRetries} attempts.`);
|
|
432
443
|
}
|
|
433
444
|
}
|
|
434
445
|
|
|
@@ -443,10 +454,10 @@ class ResultsParser {
|
|
|
443
454
|
const match = artifactName.match(/-(\d+)$/);
|
|
444
455
|
if (match) {
|
|
445
456
|
const artifactShard = parseInt(match[1], 10);
|
|
446
|
-
//
|
|
447
|
-
// html-report-1 (workflow) -> shard
|
|
448
|
-
// html-report-2 (workflow) -> shard
|
|
449
|
-
return artifactShard
|
|
457
|
+
// Artifacts use 1-based indexing, and we now use 1-based internally
|
|
458
|
+
// html-report-1 (workflow) -> shard 1 (internal)
|
|
459
|
+
// html-report-2 (workflow) -> shard 2 (internal)
|
|
460
|
+
return artifactShard;
|
|
450
461
|
}
|
|
451
462
|
// Fallback to the provided index
|
|
452
463
|
return i;
|
|
@@ -466,16 +477,16 @@ class ResultsParser {
|
|
|
466
477
|
const githubApiUrl = `https://api.github.com/repos/${repo}/actions/artifacts`;
|
|
467
478
|
|
|
468
479
|
// Try multiple artifact naming patterns:
|
|
469
|
-
// 1. html-report-{i} (1-based workflow style)
|
|
470
|
-
// 2. blob-report-node-{i} (direct blob reports)
|
|
471
|
-
// 3. test-results-{i} (alternative naming)
|
|
472
|
-
// Note: i is
|
|
480
|
+
// 1. html-report-{i} (1-based workflow style, i is already 1-based)
|
|
481
|
+
// 2. blob-report-node-{i} (direct blob reports, i is 1-based)
|
|
482
|
+
// 3. test-results-{i} (alternative naming, i is 1-based)
|
|
483
|
+
// Note: i is 1-based internally now, so we use it directly for GitHub Actions artifacts
|
|
473
484
|
const artifactNamePatterns = [
|
|
474
|
-
`html-report-${i
|
|
475
|
-
`blob-report-node-${i}`, //
|
|
476
|
-
`
|
|
477
|
-
`
|
|
478
|
-
`test-results-${i
|
|
485
|
+
`html-report-${i}`, // 1-based workflow style (i is already 1-based)
|
|
486
|
+
`blob-report-node-${i}`, // 1-based direct blob
|
|
487
|
+
`html-report-${i - 1}`, // 0-based html-report (fallback)
|
|
488
|
+
`blob-report-node-${i - 1}`, // 0-based direct blob (fallback)
|
|
489
|
+
`test-results-${i}`, // Alternative naming
|
|
479
490
|
];
|
|
480
491
|
|
|
481
492
|
while (true) {
|
|
@@ -497,9 +508,9 @@ class ResultsParser {
|
|
|
497
508
|
artifact = listResponse.data.artifacts.find(
|
|
498
509
|
(a) => a.name === pattern ||
|
|
499
510
|
a.name.includes(`shard-${i}`) ||
|
|
500
|
-
a.name.includes(`shard-${i
|
|
511
|
+
a.name.includes(`shard-${i - 1}`) ||
|
|
501
512
|
a.name.includes(`node-${i}`) ||
|
|
502
|
-
a.name.includes(`node-${i
|
|
513
|
+
a.name.includes(`node-${i - 1}`)
|
|
503
514
|
);
|
|
504
515
|
if (artifact) {
|
|
505
516
|
console.log(`Found artifact: ${artifact.name} (matched pattern: ${pattern})`);
|
|
@@ -534,8 +545,8 @@ class ResultsParser {
|
|
|
534
545
|
file,
|
|
535
546
|
`playwright-report/${file}`,
|
|
536
547
|
`playwright-report/${file}`,
|
|
537
|
-
`html-report-${i + 1}/${file}`,
|
|
538
548
|
`html-report-${i}/${file}`,
|
|
549
|
+
`html-report-${i - 1}/${file}`,
|
|
539
550
|
];
|
|
540
551
|
for (const possiblePath of possiblePaths) {
|
|
541
552
|
zipEntry = zip.getEntry(possiblePath);
|
|
@@ -259,19 +259,29 @@ class SlackReporter {
|
|
|
259
259
|
// Find index of current job in the sorted group
|
|
260
260
|
const currentJobIndex = jobGroup.findIndex(j => j.id === currentJob?.id || j.name === currentJob?.name);
|
|
261
261
|
|
|
262
|
-
// Try to extract shard number from job name (e.g., "shard 3/4" -> index
|
|
262
|
+
// Try to extract shard number from job name (e.g., "shard 3/4" -> index 3)
|
|
263
|
+
// GitHub Actions uses 1-based indexing (shard 1, 2, 3, 4), we keep it 1-based internally for shard 1 logic
|
|
263
264
|
let shardIndex = currentJobIndex >= 0 ? currentJobIndex : 0;
|
|
264
265
|
if (currentJob && currentJob.name) {
|
|
265
266
|
const shardMatch = currentJob.name.match(/shard\s+(\d+)\/(\d+)/i);
|
|
266
267
|
if (shardMatch) {
|
|
267
|
-
const shardNum = parseInt(shardMatch[1], 10);
|
|
268
|
+
const shardNum = parseInt(shardMatch[1], 10); // 1-based from GitHub Actions (1, 2, 3, 4)
|
|
268
269
|
const totalFromName = parseInt(shardMatch[2], 10);
|
|
269
|
-
//
|
|
270
|
-
|
|
271
|
-
|
|
270
|
+
// Keep GitHub Actions 1-based indexing (shard 1 -> index 1, shard 2 -> index 2, etc.)
|
|
271
|
+
// This allows shard 1 to be the aggregator
|
|
272
|
+
shardIndex = shardNum;
|
|
273
|
+
this.log(`đ [GitHub Actions Detection] Extracted shard info from name: ${shardNum}/${totalFromName} (GitHub Actions 1-based) -> index ${shardIndex} (internal 1-based)`);
|
|
272
274
|
}
|
|
273
275
|
}
|
|
274
276
|
|
|
277
|
+
// If we couldn't extract from name but have job index, convert from 0-based array index to 1-based
|
|
278
|
+
// GitHub Actions jobs are numbered starting from 1, so array index 0 = shard 1, index 1 = shard 2, etc.
|
|
279
|
+
// We need to convert: array index 0 -> shard 1, array index 1 -> shard 2, etc.
|
|
280
|
+
if (shardIndex === currentJobIndex && currentJobIndex >= 0) {
|
|
281
|
+
shardIndex = currentJobIndex + 1; // Convert 0-based array index to 1-based shard index
|
|
282
|
+
this.log(`đ [GitHub Actions Detection] Using array index ${currentJobIndex} -> shard ${shardIndex} (1-based)`);
|
|
283
|
+
}
|
|
284
|
+
|
|
275
285
|
const totalShards = jobGroup.length;
|
|
276
286
|
this.log(`đ [GitHub Actions Detection] Detected via API:`);
|
|
277
287
|
this.log(`đ Total jobs in group: ${totalShards}`);
|
|
@@ -320,8 +330,8 @@ class SlackReporter {
|
|
|
320
330
|
this.log(message);
|
|
321
331
|
return;
|
|
322
332
|
}
|
|
323
|
-
// SHARDING SUPPORT - Stop slack messages for non-
|
|
324
|
-
// Only shard
|
|
333
|
+
// SHARDING SUPPORT - Stop slack messages for non-shard-1 shard(s)
|
|
334
|
+
// Only shard 1 should post when aggregating results from multiple shards
|
|
325
335
|
|
|
326
336
|
this.log('đ [Shard Detection] Starting shard detection logic...');
|
|
327
337
|
|
|
@@ -343,6 +353,8 @@ class SlackReporter {
|
|
|
343
353
|
|
|
344
354
|
// Check for Playwright shard environment variables (Playwright may set these)
|
|
345
355
|
this.log(`đ PLAYWRIGHT_SHARD: ${process.env.PLAYWRIGHT_SHARD !== undefined ? `"${process.env.PLAYWRIGHT_SHARD}"` : 'undefined'}`);
|
|
356
|
+
this.log(`đ SHARD_INDEX: ${process.env.SHARD_INDEX !== undefined ? `"${process.env.SHARD_INDEX}"` : 'undefined'}`);
|
|
357
|
+
this.log(`đ TOTAL_SHARDS: ${process.env.TOTAL_SHARDS !== undefined ? `"${process.env.TOTAL_SHARDS}"` : 'undefined'}`);
|
|
346
358
|
|
|
347
359
|
// Check Playwright's shard config (highest priority for local runs)
|
|
348
360
|
let playwrightShardInfo = null;
|
|
@@ -380,7 +392,7 @@ class SlackReporter {
|
|
|
380
392
|
current: parseInt(shardMatch[1], 10),
|
|
381
393
|
total: parseInt(shardMatch[2], 10)
|
|
382
394
|
};
|
|
383
|
-
this.log(`đ [Shard Detection] Found shard in command line args: ${playwrightShardInfo.current}/${playwrightShardInfo.total}`);
|
|
395
|
+
this.log(`đ [Shard Detection] Found shard in command line args: ${playwrightShardInfo.current}/${playwrightShardInfo.total} (1-based)`);
|
|
384
396
|
}
|
|
385
397
|
}
|
|
386
398
|
}
|
|
@@ -397,9 +409,12 @@ class SlackReporter {
|
|
|
397
409
|
// Step 2: Detect shard index (priority order: Playwright config > env vars > GitHub API)
|
|
398
410
|
let currentShardIndex;
|
|
399
411
|
if (playwrightShardInfo) {
|
|
400
|
-
// Playwright uses 1-based indexing,
|
|
401
|
-
currentShardIndex =
|
|
402
|
-
this.log(`đ [Shard Detection] Using Playwright shard config (
|
|
412
|
+
// Playwright uses 1-based indexing, keep it 1-based for shard 1 logic
|
|
413
|
+
currentShardIndex = playwrightShardInfo.current.toString();
|
|
414
|
+
this.log(`đ [Shard Detection] Using Playwright shard config (1-based): "${currentShardIndex}"`);
|
|
415
|
+
} else if (process.env.SHARD_INDEX !== undefined) {
|
|
416
|
+
currentShardIndex = process.env.SHARD_INDEX;
|
|
417
|
+
this.log(`đ [Shard Detection] Using SHARD_INDEX env var: "${currentShardIndex}"`);
|
|
403
418
|
} else if (process.env.MATRIX_SHARD !== undefined) {
|
|
404
419
|
currentShardIndex = process.env.MATRIX_SHARD;
|
|
405
420
|
this.log(`đ [Shard Detection] Using MATRIX_SHARD env var: "${currentShardIndex}"`);
|
|
@@ -418,6 +433,9 @@ class SlackReporter {
|
|
|
418
433
|
if (playwrightShardInfo) {
|
|
419
434
|
totalShards = playwrightShardInfo.total;
|
|
420
435
|
this.log(`đ [Shard Detection] Using Playwright shard config totalShards: ${totalShards}`);
|
|
436
|
+
} else if (process.env.TOTAL_SHARDS !== undefined) {
|
|
437
|
+
totalShards = parseInt(process.env.TOTAL_SHARDS, 10);
|
|
438
|
+
this.log(`đ [Shard Detection] Using TOTAL_SHARDS env var: ${totalShards}`);
|
|
421
439
|
} else if (process.env.MATRIX_COUNT !== undefined) {
|
|
422
440
|
totalShards = parseInt(process.env.MATRIX_COUNT, 10);
|
|
423
441
|
this.log(`đ [Shard Detection] Using MATRIX_COUNT env var: ${totalShards}`);
|
|
@@ -455,6 +473,7 @@ class SlackReporter {
|
|
|
455
473
|
// CRITICAL: In CI (especially GitHub Actions), if we can't detect shard info, block posting
|
|
456
474
|
// This prevents duplicate messages when running with multiple shards
|
|
457
475
|
// BUT: Don't block if we're running locally (even if CI env vars are set)
|
|
476
|
+
// Note: GitHub Actions uses 1-based indexing (shard 1, 2, 3, 4), but we use 0-based internally
|
|
458
477
|
if (isActuallyInGitHubActions && currentShardIndex === undefined) {
|
|
459
478
|
if (process.env.GITHUB_ACTIONS === 'true') {
|
|
460
479
|
this.log(`â [Shard Detection] BLOCKING: GitHub Actions detected but shard index cannot be determined.`);
|
|
@@ -468,14 +487,14 @@ class SlackReporter {
|
|
|
468
487
|
this.log(`â Skipping Slack report to prevent duplicate messages from all shards.`);
|
|
469
488
|
this.log(`đĄ Fix: Add these env vars to your workflow:`);
|
|
470
489
|
this.log(`đĄ env:`);
|
|
471
|
-
this.log(`đĄ MATRIX_SHARD: $\{\{ strategy.job-index \}\} # 0-based (only shard
|
|
490
|
+
this.log(`đĄ MATRIX_SHARD: $\{\{ strategy.job-index \}\} # GitHub Actions uses 1-based, convert to 0-based (only shard 1/internal index 1 posts)`);
|
|
472
491
|
this.log(`đĄ MATRIX_COUNT: $\{\{ strategy.job-total \}\}`);
|
|
473
492
|
this.log(`đĄ OR ensure SAFETYWINGTEST_GITHUB_TOKEN has workflow permissions for API detection`);
|
|
474
493
|
return;
|
|
475
494
|
}
|
|
476
495
|
|
|
477
|
-
// Convert to number for comparison (default to
|
|
478
|
-
const shardIndexNum = currentShardIndex !== undefined ? parseInt(currentShardIndex, 10) :
|
|
496
|
+
// Convert to number for comparison (default to 1 if undefined, since shard 1 is the aggregator)
|
|
497
|
+
const shardIndexNum = currentShardIndex !== undefined ? parseInt(currentShardIndex, 10) : 1;
|
|
479
498
|
|
|
480
499
|
this.log(`đ [Shard Detection] Final values:`);
|
|
481
500
|
this.log(`đ currentShardIndex (string): ${currentShardIndex !== undefined ? `"${currentShardIndex}"` : 'undefined'}`);
|
|
@@ -487,30 +506,37 @@ class SlackReporter {
|
|
|
487
506
|
this.resultsParser.updateShardInfo(shardIndexNum, totalShards);
|
|
488
507
|
|
|
489
508
|
// For local runs with CI env vars set but not actually in CI, allow posting if single shard
|
|
490
|
-
// or if shard index is
|
|
509
|
+
// or if shard index is 1
|
|
491
510
|
if (!isActuallyInGitHubActions && process.env.CI && totalShards > 1 && currentShardIndex === undefined) {
|
|
492
511
|
this.log(`â ī¸ [Shard Detection] Local run with CI env vars but shard info unclear - allowing post (may cause duplicates)`);
|
|
493
512
|
}
|
|
494
513
|
|
|
495
|
-
// CRITICAL: For GitHub Actions with multiple shards, only shard
|
|
514
|
+
// CRITICAL: For GitHub Actions with multiple shards, only shard 1 should post
|
|
496
515
|
// If we're in CI with multiple shards and don't know which shard we are, block all posts
|
|
497
516
|
// This prevents duplicate messages when MATRIX_SHARD/MATRIX_INDEX is not set
|
|
517
|
+
// Note: GitHub Actions uses 1-based indexing (shard 1, 2, 3, 4)
|
|
518
|
+
// We use 0-based internally, so GitHub Actions shard 1 = internal index 1
|
|
498
519
|
if (isActuallyInGitHubActions && totalShards > 1 && currentShardIndex === undefined) {
|
|
499
520
|
this.log(`â [Shard Detection] BLOCKING: GitHub Actions detected with ${totalShards} shards but shard index not set (MATRIX_SHARD/MATRIX_INDEX missing).`);
|
|
500
521
|
this.log(`â Skipping Slack report to prevent duplicate messages from all shards.`);
|
|
501
522
|
this.log(`đĄ Fix: Add these env vars to your workflow:`);
|
|
502
523
|
this.log(`đĄ env:`);
|
|
503
|
-
this.log(`đĄ MATRIX_SHARD: $\{\{ strategy.job-index \}\} # 0-based (only shard
|
|
524
|
+
this.log(`đĄ MATRIX_SHARD: $\{\{ strategy.job-index \}\} # GitHub Actions uses 1-based, convert to 0-based (only shard 1/internal index 1 posts)`);
|
|
504
525
|
this.log(`đĄ MATRIX_COUNT: $\{\{ strategy.job-total \}\}`);
|
|
526
|
+
this.log(`đĄ OR ensure SAFETYWINGTEST_GITHUB_TOKEN has workflow permissions for API detection`);
|
|
505
527
|
return;
|
|
506
528
|
}
|
|
507
529
|
|
|
508
|
-
// Only allow shard
|
|
530
|
+
// Only allow shard 1 to post when there are multiple shards
|
|
509
531
|
// This ensures only one shard posts the aggregated report
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
532
|
+
// Note: GitHub Actions uses 1-based indexing (shard 1, 2, 3, 4)
|
|
533
|
+
// We use 0-based internally, so shard 1 in GitHub Actions = index 1 internally
|
|
534
|
+
if (totalShards > 1 && shardIndexNum !== 1) {
|
|
535
|
+
// Convert back to 1-based for display if from GitHub Actions
|
|
536
|
+
const displayShard = isActuallyInGitHubActions ? shardIndexNum + 1 : shardIndexNum;
|
|
537
|
+
this.log(`â [Shard Detection] BLOCKING: Non-shard-1 detected (shard ${displayShard} of ${totalShards}${isActuallyInGitHubActions ? ' [GitHub Actions 1-based]' : ''})`);
|
|
538
|
+
this.log(`â Stopping reporter for shard ${displayShard} of ${totalShards}`);
|
|
539
|
+
this.log(`âšī¸ Only shard 1 will post the aggregated report.`);
|
|
514
540
|
return;
|
|
515
541
|
}
|
|
516
542
|
|
|
@@ -518,7 +544,9 @@ class SlackReporter {
|
|
|
518
544
|
if (totalShards === 1) {
|
|
519
545
|
this.log(`â
[Shard Detection] ALLOWING: Single shard detected. Posting Slack report.`);
|
|
520
546
|
} else {
|
|
521
|
-
|
|
547
|
+
// Convert back to 1-based for display if from GitHub Actions
|
|
548
|
+
const displayShard = isActuallyInGitHubActions ? shardIndexNum + 1 : shardIndexNum;
|
|
549
|
+
this.log(`â
[Shard Detection] ALLOWING: Multiple shards detected (${totalShards}). Shard ${displayShard} (index ${shardIndexNum}${isActuallyInGitHubActions ? ', GitHub Actions 1-based' : ''}) will post aggregated report.`);
|
|
522
550
|
}
|
|
523
551
|
|
|
524
552
|
const resultSummary = await this.resultsParser.getParsedResults();
|
package/package.json
CHANGED