Skip to content

Commit 030378c

Browse files
authored
ci: add test summary using JUnitXML (#346) (#383)
1 parent 5c7160c commit 030378c

File tree

2 files changed

+160
-0
lines changed

2 files changed

+160
-0
lines changed

.github/workflows/build.yml

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -382,8 +382,26 @@ jobs:
382382
-n $(nproc) \
383383
--runner=${{ matrix.test-config.runner }} \
384384
--rt ${{ matrix.test-config.runtime }} \
385+
--junitxml=test-results-${{ matrix.test-config.runtime }}.xml \
385386
packages
386387
388+
- name: Surface failing tests
389+
if: always()
390+
uses: pmeier/pytest-results-action@20b595761ba9bf89e115e875f8bc863f913bc8ad # v0.7.2
391+
with:
392+
path: test-results-${{ matrix.test-config.runtime }}.xml
393+
summary: true # Always display overall test statistics summary
394+
display-options: fE # Show detailed list only for failed (f) and error (E) tests
395+
fail-on-empty: true
396+
title: "Test Results - ${{ matrix.test-config.runtime }}"
397+
398+
- name: Upload test results XML
399+
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
400+
with:
401+
name: test-results-${{ matrix.test-config.runtime }}
402+
path: test-results-${{ matrix.test-config.runtime }}.xml
403+
if: always()
404+
387405
# This job runs the SciPy tests with Node.js based on the
388406
# above checks; separate from the main test job.
389407
test-scipy:
@@ -469,6 +487,7 @@ jobs:
469487
run: node scipy-pytest.js --pyargs scipy -m "not slow" -vra
470488
working-directory: packages/scipy/
471489

490+
472491
release: # deploy to pyodide channel
473492
runs-on: ubuntu-latest
474493
defaults:
Lines changed: 141 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,141 @@
1+
name: Comment Test Summary
2+
3+
on:
4+
workflow_run:
5+
workflows: ["Build Recipes"]
6+
types:
7+
- completed
8+
9+
permissions:
10+
pull-requests: write
11+
contents: read
12+
13+
jobs:
14+
download:
15+
runs-on: ubuntu-latest
16+
if: ${{ github.event.workflow_run.conclusion == 'failure' && github.event.workflow_run.event == 'pull_request' }}
17+
steps:
18+
- name: 'Download test summary artifacts'
19+
uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea # v7.0.1
20+
with:
21+
script: |
22+
let allArtifacts = await github.rest.actions.listWorkflowRunArtifacts({
23+
owner: context.repo.owner,
24+
repo: context.repo.repo,
25+
run_id: context.payload.workflow_run.id,
26+
});
27+
28+
// Find all test summary artifacts
29+
let testSummaryArtifacts = allArtifacts.data.artifacts.filter((artifact) => {
30+
return artifact.name.startsWith("test-summary-");
31+
});
32+
33+
if (testSummaryArtifacts.length === 0) {
34+
console.log("No test summary artifacts found");
35+
return;
36+
}
37+
38+
const fs = require('fs');
39+
const path = require('path');
40+
const temp = '${{ runner.temp }}/test-artifacts';
41+
42+
if (!fs.existsSync(temp)){
43+
fs.mkdirSync(temp);
44+
}
45+
46+
// Download all test summary artifacts
47+
for (let artifact of testSummaryArtifacts) {
48+
let download = await github.rest.actions.downloadArtifact({
49+
owner: context.repo.owner,
50+
repo: context.repo.repo,
51+
artifact_id: artifact.id,
52+
archive_format: 'zip',
53+
});
54+
55+
const artifactPath = path.join(temp, `${artifact.name}.zip`);
56+
fs.writeFileSync(artifactPath, Buffer.from(download.data));
57+
console.log(`Downloaded artifact: ${artifact.name}`);
58+
}
59+
60+
- name: 'Unzip test summary artifacts'
61+
run: |
62+
cd "${{ runner.temp }}/test-artifacts"
63+
for zip in *.zip; do
64+
if [ -f "$zip" ]; then
65+
unzip "$zip" -d "${zip%.zip}"
66+
echo "Unzipped: $zip"
67+
fi
68+
done
69+
70+
- name: 'Comment test summary on PR'
71+
uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea # v7.0.1
72+
with:
73+
github-token: ${{ secrets.GITHUB_TOKEN }}
74+
script: |
75+
const fs = require('fs');
76+
const path = require('path');
77+
const temp = '${{ runner.temp }}/test-artifacts';
78+
79+
// Get PR number from the workflow run
80+
const prNumber = context.payload.workflow_run.pull_requests[0]?.number;
81+
if (!prNumber) {
82+
console.log("No PR number found in workflow run");
83+
return;
84+
}
85+
86+
// Collect all test summary files
87+
let allSummaries = [];
88+
const artifactDirs = fs.readdirSync(temp).filter(item => {
89+
return fs.statSync(path.join(temp, item)).isDirectory();
90+
});
91+
92+
for (let dir of artifactDirs) {
93+
const summaryFile = path.join(temp, dir, `${dir}.md`);
94+
if (fs.existsSync(summaryFile)) {
95+
const content = fs.readFileSync(summaryFile, 'utf8');
96+
allSummaries.push(content);
97+
console.log(`Found test summary: ${dir}`);
98+
}
99+
}
100+
101+
if (allSummaries.length === 0) {
102+
console.log("No test summary files found");
103+
return;
104+
}
105+
106+
// Combine all summaries
107+
const combinedSummary = allSummaries.join('\n\n---\n\n');
108+
const finalComment = `# 🧪 Test Results Summary\n\n${combinedSummary}`;
109+
110+
// Search for existing test summary comments
111+
const comments = await github.rest.issues.listComments({
112+
issue_number: prNumber,
113+
owner: context.repo.owner,
114+
repo: context.repo.repo
115+
});
116+
117+
// Look for a comment that was created by the GitHub Actions bot and contains test summary
118+
const testSummaryComment = comments.data.find(comment =>
119+
comment.user.login === 'github-actions[bot]' &&
120+
comment.body.includes('🧪 Test Results Summary')
121+
);
122+
123+
if (testSummaryComment) {
124+
// Update existing comment
125+
await github.rest.issues.updateComment({
126+
comment_id: testSummaryComment.id,
127+
owner: context.repo.owner,
128+
repo: context.repo.repo,
129+
body: finalComment
130+
});
131+
console.log(`Updated existing test summary comment ID: ${testSummaryComment.id}`);
132+
} else {
133+
// Create new comment
134+
await github.rest.issues.createComment({
135+
issue_number: prNumber,
136+
owner: context.repo.owner,
137+
repo: context.repo.repo,
138+
body: finalComment
139+
});
140+
console.log('Created new test summary comment');
141+
}

0 commit comments

Comments
 (0)