playwright-slack-report-burak 3.0.0 → 3.0.3

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.
@@ -343,19 +343,53 @@ class ResultsParser {
343
343
 
344
344
  async fetchAllArtifacts() {
345
345
  const summariesDir = path.join('./', 'playwright-report');
346
- while (!this.allNodeSummaryFilesExist() || !this.allBlobZipsExist()) {
347
- console.log('Waiting for all blob zips to exist...');
348
- if (!fs.existsSync(summariesDir)) {
349
- fs.mkdirSync(summariesDir, { recursive: true });
350
- }
351
- // Fetch artifacts for shards 1 to totalShardCount-1 (if using 1-based) or 0 to totalShardCount-1 (if 0-based)
352
- // Since we're shard 0, we need to fetch from other shards
353
- // The workflow uses 1-based shards (1, 2, 3...), but we need to map them to 0-based internally (0, 1, 2...)
354
- // So shard 1 in workflow = shard 0 internally, shard 2 = shard 1, etc.
355
- for (let i = 1; i < this.totalShardCount; i++) {
356
- await this.fetchArtifact(i, `node_summary_${i}.json`, summariesDir);
357
- await this.fetchArtifact(i, `blob-report-node-${i}.zip`, summariesDir);
358
- }
346
+ if (!fs.existsSync(summariesDir)) {
347
+ fs.mkdirSync(summariesDir, { recursive: true });
348
+ }
349
+
350
+ console.log(`Shard 0: Waiting for artifacts from ${this.totalShardCount - 1} other shard(s)...`);
351
+
352
+ // Fetch artifacts for shards 1 to totalShardCount-1 (since we're shard 0)
353
+ // We need to fetch from all other shards before proceeding
354
+ for (let i = 1; i < this.totalShardCount; i++) {
355
+ console.log(`Shard 0: Fetching artifacts from shard ${i}...`);
356
+ await this.fetchArtifact(i, `node_summary_${i}.json`, summariesDir);
357
+ await this.fetchArtifact(i, `blob-report-node-${i}.zip`, summariesDir);
358
+ }
359
+
360
+ // After fetching, verify all files exist and wait if needed
361
+ let retryCount = 0;
362
+ const maxRetries = 60; // Wait up to 10 minutes (60 * 10 seconds)
363
+
364
+ while ((!this.allNodeSummaryFilesExist() || !this.allBlobZipsExist()) && retryCount < maxRetries) {
365
+ console.log(`Shard 0: Waiting for all artifacts to be available (attempt ${retryCount + 1}/${maxRetries})...`);
366
+
367
+ // Re-fetch any missing artifacts
368
+ for (let i = 1; i < this.totalShardCount; i++) {
369
+ const nodeSummaryFile = path.join(summariesDir, `node_summary_${i}.json`);
370
+ const blobZipFile = path.join(summariesDir, `blob-report-node-${i}.zip`);
371
+
372
+ if (!fs.existsSync(nodeSummaryFile)) {
373
+ console.log(`Shard 0: Re-fetching missing node_summary_${i}.json...`);
374
+ await this.fetchArtifact(i, `node_summary_${i}.json`, summariesDir);
375
+ }
376
+
377
+ if (!fs.existsSync(blobZipFile)) {
378
+ console.log(`Shard 0: Re-fetching missing blob-report-node-${i}.zip...`);
379
+ await this.fetchArtifact(i, `blob-report-node-${i}.zip`, summariesDir);
380
+ }
381
+ }
382
+
383
+ retryCount++;
384
+ if (!this.allNodeSummaryFilesExist() || !this.allBlobZipsExist()) {
385
+ await new Promise(resolve => setTimeout(resolve, 10000)); // Wait 10 seconds before retry
386
+ }
387
+ }
388
+
389
+ if (this.allNodeSummaryFilesExist() && this.allBlobZipsExist()) {
390
+ console.log(`Shard 0: Successfully fetched all artifacts from ${this.totalShardCount - 1} other shard(s).`);
391
+ } else {
392
+ console.warn(`Shard 0: Warning - Some artifacts may still be missing after ${maxRetries} attempts.`);
359
393
  }
360
394
  }
361
395
 
@@ -70,21 +70,58 @@ class SlackReporter {
70
70
  this.log(message);
71
71
  return;
72
72
  }
73
- const resultSummary = await this.resultsParser.getParsedResults();
74
73
  // SHARDING SUPPORT - Stop slack messages for non-zero index shard(s)
75
- // Support both explicit MATRIX_SHARD/MATRIX_INDEX and workflow-style 1-based indexing
76
- // If MATRIX_SHARD is not set, shard 0 will still send reports (handles single shard case)
77
- const currentShardIndex = process.env.MATRIX_SHARD !== undefined
74
+ // Only shard 0 (0-based) should post when aggregating results from multiple shards
75
+
76
+ // Detect shard index from multiple sources (GitHub Actions compatible)
77
+ let currentShardIndex = process.env.MATRIX_SHARD !== undefined
78
78
  ? process.env.MATRIX_SHARD
79
79
  : (process.env.MATRIX_INDEX !== undefined ? process.env.MATRIX_INDEX : undefined);
80
80
 
81
- // Only skip if explicitly set and not 0 (or '0')
82
- // This allows shard 0 to send reports even when MATRIX_SHARD is not set
83
- if (currentShardIndex !== undefined && currentShardIndex !== '0' && currentShardIndex !== 0) {
84
- const totalShards = process.env.MATRIX_COUNT || '1';
81
+ // Get shard info from ResultsParser which might have detected it
82
+ const parserShardIndex = this.resultsParser.shardIndex;
83
+ const parserTotalShards = this.resultsParser.totalShardCount;
84
+
85
+ // Use parser values if env vars not set
86
+ const totalShards = process.env.MATRIX_COUNT ? parseInt(process.env.MATRIX_COUNT, 10) : parserTotalShards;
87
+
88
+ // If we still don't have shard index, try to infer from parser
89
+ if (currentShardIndex === undefined && parserShardIndex !== undefined) {
90
+ currentShardIndex = parserShardIndex.toString();
91
+ }
92
+
93
+ // Convert to number for comparison (default to 0 if undefined)
94
+ const shardIndexNum = currentShardIndex !== undefined ? parseInt(currentShardIndex, 10) : 0;
95
+
96
+ // CRITICAL: For GitHub Actions with multiple shards, only shard 0 should post
97
+ // If we're in CI with multiple shards and don't know which shard we are, block all posts
98
+ // This prevents duplicate messages when MATRIX_SHARD/MATRIX_INDEX is not set
99
+ if (process.env.CI && totalShards > 1 && currentShardIndex === undefined) {
100
+ this.log(`❌ GitHub Actions detected with ${totalShards} shards but shard index not set (MATRIX_SHARD/MATRIX_INDEX missing).`);
101
+ this.log(`❌ Skipping Slack report to prevent duplicate messages from all shards.`);
102
+ this.log(`💡 Fix: Add these env vars to your workflow:`);
103
+ this.log(`💡 env:`);
104
+ this.log(`💡 MATRIX_SHARD: $\{\{ strategy.job-index \}\} # 0-based (only shard 0 posts)`);
105
+ this.log(`💡 MATRIX_COUNT: $\{\{ strategy.job-total \}\}`);
106
+ return;
107
+ }
108
+
109
+ // Only allow shard 0 (0-based) to post when there are multiple shards
110
+ // This ensures only one shard posts the aggregated report
111
+ if (totalShards > 1 && shardIndexNum !== 0) {
85
112
  this.log(`❌ Stopping reporter for non-zero index shard ${currentShardIndex} of ${totalShards}`);
113
+ this.log(`ℹ️ Only shard 0 will post the aggregated report.`);
86
114
  return;
87
115
  }
116
+
117
+ // Single shard - always allow posting
118
+ if (totalShards === 1) {
119
+ this.log(`ℹ️ Single shard detected. Posting Slack report.`);
120
+ } else {
121
+ this.log(`ℹ️ Multiple shards detected (${totalShards}). Shard ${currentShardIndex} will post aggregated report.`);
122
+ }
123
+
124
+ const resultSummary = await this.resultsParser.getParsedResults();
88
125
  resultSummary.meta = this.meta;
89
126
  const maxRetry = Math.max(...resultSummary.tests.map((o) => o.retry));
90
127
  if (this.sendResults === 'on-failure'
package/package.json CHANGED
@@ -31,7 +31,7 @@
31
31
  "lint-fix": "npx eslint . --ext .ts --fix"
32
32
  },
33
33
  "name": "playwright-slack-report-burak",
34
- "version": "3.0.0",
34
+ "version": "3.0.3",
35
35
  "main": "index.js",
36
36
  "types": "dist/index.d.ts",
37
37
  "author": "Burak B. <burak.boluk@hotmail.com>",