playwright-slack-report-burak 3.0.10 → 3.0.13

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.
@@ -97,11 +97,13 @@ class SlackReporter {
97
97
  }
98
98
  try {
99
99
  // Get workflow run details
100
- const apiUrl = `https://api.github.com/repos/safetywing/${repo}/actions/runs/${runId}/jobs`;
100
+ const apiUrl = `https://api.github.com/repos/${repo}/actions/runs/${runId}/jobs`;
101
+ this.log(`🔍 [GitHub Actions Detection] API URL: ${apiUrl}`);
101
102
  const response = await axios.get(apiUrl, {
102
103
  headers: {
103
- 'Authorization': `token ${githubToken}`,
104
- 'Accept': 'application/vnd.github.v3+json'
104
+ 'Accept': 'application/vnd.github+json',
105
+ 'Authorization': `Bearer ${githubToken}`,
106
+ 'X-GitHub-Api-Version': '2022-11-28'
105
107
  },
106
108
  params: {
107
109
  per_page: 100
@@ -112,41 +114,120 @@ class SlackReporter {
112
114
  this.log(`🔍 [GitHub Actions Detection] No jobs found in workflow run`);
113
115
  return null;
114
116
  }
115
- // Filter jobs that are part of the same workflow run and have the same name (matrix jobs)
116
- // Group by job name to find matrix jobs
117
+
118
+ this.log(`🔍 [GitHub Actions Detection] Found ${jobs.length} total jobs in workflow run`);
119
+
120
+ // Helper function to normalize job names by removing shard indicators
121
+ // e.g., "Run tests (shard 3/4)" -> "Run tests"
122
+ const normalizeJobName = (name) => {
123
+ if (!name) return '';
124
+ // Remove common matrix patterns: (shard X/Y), (X, Y), [X], etc.
125
+ return name
126
+ .replace(/\s*\(shard\s+\d+\/\d+\)/gi, '')
127
+ .replace(/\s*\(\d+\/\d+\)/g, '')
128
+ .replace(/\s*\(\d+,\s*\d+\)/g, '')
129
+ .replace(/\s*\[\d+\]/g, '')
130
+ .trim();
131
+ };
132
+
133
+ // Group jobs by normalized name to find matrix jobs
117
134
  const jobGroups = {};
118
135
  for (const job of jobs) {
119
136
  const jobName = job.name || '';
120
- if (!jobGroups[jobName]) {
121
- jobGroups[jobName] = [];
137
+ const normalizedName = normalizeJobName(jobName);
138
+ if (!jobGroups[normalizedName]) {
139
+ jobGroups[normalizedName] = [];
122
140
  }
123
- jobGroups[jobName].push(job);
141
+ jobGroups[normalizedName].push(job);
124
142
  }
143
+
144
+ this.log(`🔍 [GitHub Actions Detection] Grouped into ${Object.keys(jobGroups).length} job group(s)`);
145
+ for (const [groupName, groupJobs] of Object.entries(jobGroups)) {
146
+ this.log(`🔍 Group "${groupName}": ${groupJobs.length} job(s)`);
147
+ }
148
+
125
149
  // Find the job group that contains the current job
126
150
  let currentJob = null;
127
151
  let jobGroup = null;
128
- for (const [jobName, jobsInGroup] of Object.entries(jobGroups)) {
129
- currentJob = jobsInGroup.find(j => j.id.toString() === currentJobId || j.name === currentJobId);
130
- if (currentJob) {
131
- jobGroup = jobsInGroup;
132
- break;
152
+
153
+ // Strategy 1: Find the currently running job (status: in_progress or completed recently)
154
+ const runningJobs = jobs.filter(j => j.status === 'in_progress' || j.status === 'queued');
155
+ this.log(`🔍 [GitHub Actions Detection] Found ${runningJobs.length} running/queued job(s)`);
156
+
157
+ if (runningJobs.length === 1) {
158
+ // Perfect - only one job is running, must be us
159
+ currentJob = runningJobs[0];
160
+ const normalizedName = normalizeJobName(currentJob.name);
161
+ jobGroup = jobGroups[normalizedName];
162
+ this.log(`🔍 [GitHub Actions Detection] Matched by running status: "${currentJob.name}"`);
163
+ } else if (runningJobs.length > 1) {
164
+ // Multiple running jobs - try to match by job ID or name
165
+ for (const job of runningJobs) {
166
+ // Check if this job's name contains the GITHUB_JOB id
167
+ // But be more specific - avoid matching "Generate test matrix" when looking for "test"
168
+ const jobIdLower = currentJobId.toLowerCase();
169
+ const jobNameLower = (job.name || '').toLowerCase();
170
+
171
+ // Match if job name starts with or equals the job ID (more specific)
172
+ if (jobNameLower.startsWith(jobIdLower) ||
173
+ jobNameLower.includes(`${jobIdLower} `) ||
174
+ jobNameLower.includes(`${jobIdLower}(`) ||
175
+ jobNameLower === jobIdLower) {
176
+ currentJob = job;
177
+ const normalizedName = normalizeJobName(job.name);
178
+ jobGroup = jobGroups[normalizedName];
179
+ this.log(`🔍 [GitHub Actions Detection] Matched running job by ID match: "${job.name}"`);
180
+ break;
181
+ }
182
+ }
183
+
184
+ // Still no match? Take the first running job that looks like a test job
185
+ if (!currentJob) {
186
+ for (const job of runningJobs) {
187
+ if (job.name && (job.name.includes('shard') || job.name.includes('test') || job.name.includes('matrix'))) {
188
+ currentJob = job;
189
+ const normalizedName = normalizeJobName(job.name);
190
+ jobGroup = jobGroups[normalizedName];
191
+ this.log(`🔍 [GitHub Actions Detection] Matched by test-like name: "${job.name}"`);
192
+ break;
193
+ }
194
+ }
133
195
  }
134
196
  }
135
- // If we can't find current job by ID, try to match by name from GITHUB_JOB
136
- if (!currentJob && currentJobId) {
137
- for (const [jobName, jobsInGroup] of Object.entries(jobGroups)) {
138
- if (jobName.includes(currentJobId) || currentJobId.includes(jobName)) {
139
- jobGroup = jobsInGroup;
140
- // Try to find the job by looking at run_attempt or other identifiers
141
- currentJob = jobsInGroup[0];
197
+
198
+ // Strategy 2: If no running job found, look at all jobs
199
+ if (!currentJob) {
200
+ this.log(`🔍 [GitHub Actions Detection] No running job matched, checking all jobs`);
201
+ for (const job of jobs) {
202
+ const jobIdLower = currentJobId.toLowerCase();
203
+ const jobNameLower = (job.name || '').toLowerCase();
204
+
205
+ if (jobNameLower.startsWith(jobIdLower) ||
206
+ jobNameLower.includes(`${jobIdLower} `) ||
207
+ jobNameLower.includes(`${jobIdLower}(`)) {
208
+ currentJob = job;
209
+ const normalizedName = normalizeJobName(job.name);
210
+ jobGroup = jobGroups[normalizedName];
211
+ this.log(`🔍 [GitHub Actions Detection] Matched job by name: "${job.name}"`);
142
212
  break;
143
213
  }
144
214
  }
145
215
  }
146
- // If still no match, use all jobs (might be a single job or we can't determine)
216
+
217
+ // Fallback: Use the largest job group (likely the matrix jobs)
147
218
  if (!jobGroup || jobGroup.length === 0) {
148
- jobGroup = jobs;
149
- currentJob = jobs[0];
219
+ this.log(`🔍 [GitHub Actions Detection] Could not match job, using largest job group`);
220
+ let largestGroup = [];
221
+ let largestGroupName = '';
222
+ for (const [groupName, groupJobs] of Object.entries(jobGroups)) {
223
+ if (groupJobs.length > largestGroup.length) {
224
+ largestGroup = groupJobs;
225
+ largestGroupName = groupName;
226
+ }
227
+ }
228
+ jobGroup = largestGroup;
229
+ currentJob = jobGroup[0];
230
+ this.log(`🔍 [GitHub Actions Detection] Using largest group "${largestGroupName}" with ${jobGroup.length} job(s)`);
150
231
  }
151
232
  // Sort jobs by name or ID to get consistent ordering
152
233
  jobGroup.sort((a, b) => {
@@ -155,13 +236,23 @@ class SlackReporter {
155
236
  }
156
237
  return a.id - b.id;
157
238
  });
158
- // Find index of current job
159
- const currentJobIndex = jobGroup.findIndex(j =>
160
- j.id === currentJob?.id ||
161
- j.name === currentJob?.name ||
162
- (currentJobId && (j.name === currentJobId || j.name?.includes(currentJobId)))
163
- );
164
- const shardIndex = currentJobIndex >= 0 ? currentJobIndex : 0;
239
+
240
+ // Find index of current job in the sorted group
241
+ const currentJobIndex = jobGroup.findIndex(j => j.id === currentJob?.id || j.name === currentJob?.name);
242
+
243
+ // Try to extract shard number from job name (e.g., "shard 3/4" -> index 2)
244
+ let shardIndex = currentJobIndex >= 0 ? currentJobIndex : 0;
245
+ if (currentJob && currentJob.name) {
246
+ const shardMatch = currentJob.name.match(/shard\s+(\d+)\/(\d+)/i);
247
+ if (shardMatch) {
248
+ const shardNum = parseInt(shardMatch[1], 10);
249
+ const totalFromName = parseInt(shardMatch[2], 10);
250
+ // Convert to 0-based index (shard 3/4 -> index 2)
251
+ shardIndex = shardNum - 1;
252
+ this.log(`🔍 [GitHub Actions Detection] Extracted shard info from name: ${shardNum}/${totalFromName} -> index ${shardIndex}`);
253
+ }
254
+ }
255
+
165
256
  const totalShards = jobGroup.length;
166
257
  this.log(`🔍 [GitHub Actions Detection] Detected via API:`);
167
258
  this.log(`🔍 Total jobs in group: ${totalShards}`);
@@ -489,3 +580,4 @@ class SlackReporter {
489
580
  }
490
581
  }
491
582
  exports.default = SlackReporter;
583
+
package/package.json CHANGED
@@ -32,7 +32,7 @@
32
32
  "lint-fix": "npx eslint . --ext .ts --fix"
33
33
  },
34
34
  "name": "playwright-slack-report-burak",
35
- "version": "3.0.10",
35
+ "version": "3.0.13",
36
36
  "main": "index.js",
37
37
  "types": "dist/index.d.ts",
38
38
  "author": "Burak B. <burak.boluk@hotmail.com>",