@@ -1161,101 +1161,19 @@ jobs:
11611161 if : github.ref == 'refs/heads/develop' && contains(needs.*.result, 'failure')
11621162 uses : actions/checkout@v6
11631163 with :
1164- sparse-checkout : .github
1164+ sparse-checkout : |
1165+ .github
1166+ scripts
11651167
11661168 - name : Create issues for failed jobs
11671169 if : github.ref == 'refs/heads/develop' && contains(needs.*.result, 'failure')
11681170 uses : actions/github-script@v7
11691171 with :
11701172 script : |
1171- const fs = require('fs');
1172-
1173- // Fetch actual job details from the API to get descriptive names
1174- const jobs = await github.paginate(github.rest.actions.listJobsForWorkflowRun, {
1175- owner: context.repo.owner,
1176- repo: context.repo.repo,
1177- run_id: context.runId,
1178- per_page: 100
1179- });
1180-
1181- const failedJobs = jobs.filter(job => job.conclusion === 'failure' && !job.name.includes('(optional)'));
1182-
1183- if (failedJobs.length === 0) {
1184- console.log('No failed jobs found');
1185- return;
1186- }
1187-
1188- // Read and parse template
1189- const template = fs.readFileSync('.github/FLAKY_CI_FAILURE_TEMPLATE.md', 'utf8');
1190- const [, frontmatter, bodyTemplate] = template.match(/^---\n([\s\S]*?)\n---\n([\s\S]*)$/);
1191-
1192- // Get existing open issues with Tests label
1193- const existing = await github.paginate(github.rest.issues.listForRepo, {
1194- owner: context.repo.owner,
1195- repo: context.repo.repo,
1196- state: 'open',
1197- labels: 'Tests',
1198- per_page: 100
1199- });
1200-
1201- for (const job of failedJobs) {
1202- const jobName = job.name;
1203- const jobUrl = job.html_url;
1204-
1205- // Fetch annotations from the check run to extract failed test names
1206- let testNames = [];
1207- try {
1208- const annotations = await github.paginate(github.rest.checks.listAnnotations, {
1209- owner: context.repo.owner,
1210- repo: context.repo.repo,
1211- check_run_id: job.id,
1212- per_page: 100
1213- });
1214-
1215- const testAnnotations = annotations.filter(a => a.annotation_level === 'failure' && a.path !== '.github');
1216- testNames = [...new Set(testAnnotations.map(a => a.title || a.path))];
1217- } catch (e) {
1218- console.log(`Could not fetch annotations for ${jobName}: ${e.message}`);
1219- }
1220-
1221- // If no test names found, fall back to one issue per job
1222- if (testNames.length === 0) {
1223- testNames = ['Unknown test'];
1224- }
1225-
1226- // Create one issue per failing test for proper deduplication
1227- for (const testName of testNames) {
1228- const vars = {
1229- 'JOB_NAME': jobName,
1230- 'RUN_LINK': jobUrl,
1231- 'TEST_NAME': testName
1232- };
1233-
1234- let title = frontmatter.match(/title:\s*'(.*)'/)[1];
1235- let issueBody = bodyTemplate;
1236- for (const [key, value] of Object.entries(vars)) {
1237- const pattern = new RegExp(`\\{\\{\\s*env\\.${key}\\s*\\}\\}`, 'g');
1238- title = title.replace(pattern, value);
1239- issueBody = issueBody.replace(pattern, value);
1240- }
1241-
1242- const existingIssue = existing.find(i => i.title === title);
1243-
1244- if (existingIssue) {
1245- console.log(`Issue already exists for "${testName}" in ${jobName}: #${existingIssue.number}`);
1246- continue;
1247- }
1248-
1249- const newIssue = await github.rest.issues.create({
1250- owner: context.repo.owner,
1251- repo: context.repo.repo,
1252- title: title,
1253- body: issueBody.trim(),
1254- labels: ['Tests']
1255- });
1256- console.log(`Created issue #${newIssue.data.number} for "${testName}" in ${jobName}`);
1257- }
1258- }
1173+ const { default: run } = await import(
1174+ `${process.env.GITHUB_WORKSPACE}/scripts/report-ci-failures.mjs`
1175+ );
1176+ await run({ github, context, core });
12591177
12601178 - name : Check for failures
12611179 if : cancelled() || contains(needs.*.result, 'failure') || contains(needs.*.result, 'cancelled')
0 commit comments