Skip to content

Commit 3dfdfd6

Browse files
authored
Merge branch 'master' into fix-fast
2 parents 10922b7 + bcf3964 commit 3dfdfd6

18 files changed

Lines changed: 15157 additions & 64 deletions

.github/workflows/master.yml

Lines changed: 214 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,31 @@ on:
44
push:
55
branches:
66
- master
7-
permissions: # For test summary bot
7+
permissions:
8+
contents: write
89
checks: write
910
jobs:
1011
buildAndTest:
1112
runs-on: ubuntu-latest
1213
strategy:
1314
matrix:
14-
gradle-argument: [ 'assemble && ./gradlew check -x test','testWithJava11', 'testWithJava17','testWithJava21', 'test -x testWithJava11 -x testWithJava17 -x testWithJava21' ]
15+
include:
16+
- gradle-argument: 'assemble && ./gradlew check -x test -x testng -x testngWithJava11 -x testngWithJava17 -x testngWithJava21'
17+
label: 'check'
18+
- gradle-argument: 'testWithJava11 testngWithJava11'
19+
label: 'java11'
20+
test-results-dirs: 'testWithJava11 testngWithJava11'
21+
- gradle-argument: 'testWithJava17 testngWithJava17'
22+
label: 'java17'
23+
test-results-dirs: 'testWithJava17 testngWithJava17'
24+
- gradle-argument: 'testWithJava21 testngWithJava21'
25+
label: 'java21'
26+
test-results-dirs: 'testWithJava21 testngWithJava21'
27+
- gradle-argument: 'test -x testWithJava11 -x testWithJava17 -x testWithJava21 testng jacocoTestReport'
28+
label: 'java25'
29+
test-results-dirs: 'test testng'
30+
- gradle-argument: 'jcstress'
31+
label: 'jcstress'
1532
steps:
1633
- uses: actions/checkout@v6
1734
- uses: gradle/actions/wrapper-validation@v5
@@ -21,16 +38,176 @@ jobs:
2138
java-version: '25'
2239
distribution: 'corretto'
2340
- name: build and test
24-
run: ./gradlew ${{matrix.gradle-argument}} --info --stacktrace
41+
run: |
42+
if [ "${{ matrix.label }}" = "jcstress" ]; then
43+
set -o pipefail
44+
mkdir -p build
45+
./gradlew ${{matrix.gradle-argument}} --info --stacktrace 2>&1 | tee build/jcstress-output.txt
46+
else
47+
./gradlew ${{matrix.gradle-argument}} --info --stacktrace
48+
fi
2549
- name: Publish Test Results
2650
uses: EnricoMi/publish-unit-test-result-action@v2.23.0
27-
if: always()
51+
if: always() && matrix.label != 'check' && matrix.label != 'jcstress'
2852
with:
2953
files: |
30-
**/build/test-results/test/TEST-*.xml
31-
**/build/test-results/testWithJava11/TEST-*.xml
32-
**/build/test-results/testWithJava17/TEST-*.xml
33-
**/build/test-results/testWithJava21/TEST-*.xml
54+
**/build/test-results/*/TEST-*.xml
55+
- name: Upload Coverage XML Report
56+
uses: actions/upload-artifact@v4
57+
if: always() && matrix.label == 'java25'
58+
with:
59+
name: coverage-report
60+
path: build/reports/jacoco/test/jacocoTestReport.xml
61+
retention-days: 1
62+
- name: Parse Test Results
63+
if: always() && matrix.label != 'check' && matrix.label != 'jcstress'
64+
run: |
65+
total=0; failures=0; errors=0; skipped=0
66+
for dir_name in ${{ matrix.test-results-dirs }}; do
67+
dir="build/test-results/$dir_name"
68+
for f in "$dir"/TEST-*.xml; do
69+
[ -f "$f" ] || continue
70+
t=$(grep -o 'tests="[0-9]*"' "$f" | head -1 | grep -o '[0-9]*')
71+
fl=$(grep -o 'failures="[0-9]*"' "$f" | head -1 | grep -o '[0-9]*')
72+
e=$(grep -o 'errors="[0-9]*"' "$f" | head -1 | grep -o '[0-9]*')
73+
s=$(grep -o 'skipped="[0-9]*"' "$f" | head -1 | grep -o '[0-9]*')
74+
total=$((total + ${t:-0}))
75+
failures=$((failures + ${fl:-0}))
76+
errors=$((errors + ${e:-0}))
77+
skipped=$((skipped + ${s:-0}))
78+
done
79+
done
80+
passed=$((total - failures - errors - skipped))
81+
mkdir -p /tmp/test-stats
82+
echo "{\"total\":$total,\"passed\":$passed,\"failed\":$failures,\"errors\":$errors,\"skipped\":$skipped}" \
83+
> "/tmp/test-stats/${{ matrix.label }}.json"
84+
- name: Parse jcstress Results
85+
if: always() && matrix.label == 'jcstress'
86+
run: |
87+
total=0; passed=0; failed=0; errors=0; skipped=0
88+
if [ -f build/jcstress-output.txt ]; then
89+
line=$(grep 'Results:.*planned.*passed.*failed' build/jcstress-output.txt | tail -1)
90+
if [ -n "$line" ]; then
91+
total=$(echo "$line" | sed 's/.*Results: \([0-9]*\) planned.*/\1/')
92+
passed=$(echo "$line" | sed 's/.*; \([0-9]*\) passed.*/\1/')
93+
failed=$(echo "$line" | sed 's/.*passed, \([0-9]*\) failed.*/\1/')
94+
soft=$(echo "$line" | sed 's/.*failed, \([0-9]*\) soft.*/\1/')
95+
hard=$(echo "$line" | sed 's/.*soft errs, \([0-9]*\) hard.*/\1/')
96+
errors=$((soft + hard))
97+
fi
98+
fi
99+
mkdir -p /tmp/test-stats
100+
echo "{\"total\":$total,\"passed\":$passed,\"failed\":$failed,\"errors\":$errors,\"skipped\":$skipped}" \
101+
> "/tmp/test-stats/${{ matrix.label }}.json"
102+
- name: Upload Test Stats
103+
if: always() && matrix.label != 'check'
104+
uses: actions/upload-artifact@v4
105+
with:
106+
name: test-stats-${{ matrix.label }}
107+
path: /tmp/test-stats/${{ matrix.label }}.json
108+
update-baseline:
109+
needs: buildAndTest
110+
runs-on: ubuntu-latest
111+
steps:
112+
- uses: actions/checkout@v6
113+
with:
114+
token: ${{ secrets.ADMIN_PAT }}
115+
- name: Download Test Stats
116+
uses: actions/download-artifact@v4
117+
with:
118+
pattern: test-stats-*
119+
merge-multiple: true
120+
path: test-stats/
121+
- name: Download Coverage Report
122+
uses: actions/download-artifact@v4
123+
continue-on-error: true
124+
with:
125+
name: coverage-report
126+
path: coverage/
127+
- name: Update Baseline
128+
uses: actions/github-script@v7
129+
with:
130+
script: |
131+
const fs = require('fs');
132+
const path = require('path');
133+
134+
const versions = ['java11', 'java17', 'java21', 'java25', 'jcstress'];
135+
const zeroTest = { total: 0, passed: 0, failed: 0, errors: 0, skipped: 0 };
136+
const zeroCov = { covered: 0, missed: 0 };
137+
138+
// Read current baseline
139+
const baselineFile = 'test-baseline.json';
140+
let baseline = { tests: {}, coverage: {} };
141+
if (fs.existsSync(baselineFile)) {
142+
baseline = JSON.parse(fs.readFileSync(baselineFile, 'utf8'));
143+
}
144+
145+
// Update test stats from artifacts
146+
const tests = baseline.tests || {};
147+
for (const v of versions) {
148+
const file = path.join('test-stats', `${v}.json`);
149+
if (fs.existsSync(file)) {
150+
tests[v] = JSON.parse(fs.readFileSync(file, 'utf8'));
151+
} else {
152+
tests[v] = tests[v] || zeroTest;
153+
}
154+
}
155+
156+
// Update coverage from JaCoCo XML
157+
let coverage = { overall: {}, classes: {} };
158+
const jacocoFile = path.join('coverage', 'jacocoTestReport.xml');
159+
if (fs.existsSync(jacocoFile)) {
160+
const xml = fs.readFileSync(jacocoFile, 'utf8');
161+
162+
// Overall counters (outside <package> tags)
163+
const stripped = xml.replace(/<package[\s\S]*?<\/package>/g, '');
164+
const re = /<counter type="(\w+)" missed="(\d+)" covered="(\d+)"\/>/g;
165+
let m;
166+
while ((m = re.exec(stripped)) !== null) {
167+
if (m[1] === 'LINE') coverage.overall.line = { covered: parseInt(m[3]), missed: parseInt(m[2]) };
168+
else if (m[1] === 'BRANCH') coverage.overall.branch = { covered: parseInt(m[3]), missed: parseInt(m[2]) };
169+
else if (m[1] === 'METHOD') coverage.overall.method = { covered: parseInt(m[3]), missed: parseInt(m[2]) };
170+
}
171+
172+
// Per-class counters from <package>/<class> elements
173+
const pkgRe = /<package\s+name="([^"]+)">([\s\S]*?)<\/package>/g;
174+
let pkgMatch;
175+
while ((pkgMatch = pkgRe.exec(xml)) !== null) {
176+
const pkgName = pkgMatch[1].replace(/\//g, '.');
177+
const pkgBody = pkgMatch[2];
178+
const classRe = /<class\s+name="([^"]+)"[^>]*>([\s\S]*?)<\/class>/g;
179+
let classMatch;
180+
while ((classMatch = classRe.exec(pkgBody)) !== null) {
181+
const className = classMatch[1].replace(/\//g, '.');
182+
const classBody = classMatch[2];
183+
const counters = { line: { ...zeroCov }, branch: { ...zeroCov }, method: { ...zeroCov } };
184+
const cntRe = /<counter type="(\w+)" missed="(\d+)" covered="(\d+)"\/>/g;
185+
let cntMatch;
186+
while ((cntMatch = cntRe.exec(classBody)) !== null) {
187+
const entry = { covered: parseInt(cntMatch[3]), missed: parseInt(cntMatch[2]) };
188+
if (cntMatch[1] === 'LINE') counters.line = entry;
189+
else if (cntMatch[1] === 'BRANCH') counters.branch = entry;
190+
else if (cntMatch[1] === 'METHOD') counters.method = entry;
191+
}
192+
// Skip classes with 0 total lines (interfaces, annotations, abstract classes)
193+
if (counters.line.covered + counters.line.missed > 0) {
194+
coverage.classes[className] = counters;
195+
}
196+
}
197+
}
198+
}
199+
200+
const updated = { tests, coverage };
201+
fs.writeFileSync(baselineFile, JSON.stringify(updated, null, 2) + '\n');
202+
- name: Commit Updated Baseline
203+
run: |
204+
git config user.name "github-actions[bot]"
205+
git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
206+
git add test-baseline.json
207+
git diff --cached --quiet || {
208+
git commit -m "Update test baseline [skip ci]"
209+
git push
210+
}
34211
javadoc:
35212
runs-on: ubuntu-latest
36213
steps:
@@ -43,6 +220,34 @@ jobs:
43220
distribution: 'corretto'
44221
- name: Verify Javadoc
45222
run: ./gradlew javadoc --info --stacktrace
223+
allBuildAndTestSuccessful:
224+
if: always()
225+
needs:
226+
- buildAndTest
227+
- update-baseline
228+
- javadoc
229+
- publishToMavenCentral
230+
runs-on: ubuntu-latest
231+
steps:
232+
- name: Verify all jobs passed
233+
run: |
234+
if [ "${{ needs.buildAndTest.result }}" != "success" ]; then
235+
echo "buildAndTest failed with result: ${{ needs.buildAndTest.result }}"
236+
exit 1
237+
fi
238+
if [ "${{ needs.update-baseline.result }}" != "success" ]; then
239+
echo "update-baseline failed with result: ${{ needs.update-baseline.result }}"
240+
exit 1
241+
fi
242+
if [ "${{ needs.javadoc.result }}" != "success" ]; then
243+
echo "javadoc failed with result: ${{ needs.javadoc.result }}"
244+
exit 1
245+
fi
246+
if [ "${{ needs.publishToMavenCentral.result }}" != "success" ]; then
247+
echo "publishToMavenCentral failed with result: ${{ needs.publishToMavenCentral.result }}"
248+
exit 1
249+
fi
250+
echo "All build and test jobs passed successfully."
46251
publishToMavenCentral:
47252
needs: buildAndTest
48253
runs-on: ubuntu-latest
@@ -62,4 +267,4 @@ jobs:
62267
java-version: '25'
63268
distribution: 'corretto'
64269
- name: publishToMavenCentral
65-
run: ./gradlew assemble && ./gradlew check -x test -x testng --info && ./gradlew publishToSonatype closeAndReleaseSonatypeStagingRepository -x check --info --stacktrace
270+
run: ./gradlew assemble && ./gradlew check -x test -x testng -x testngWithJava11 -x testngWithJava17 -x testngWithJava21 --info && ./gradlew publishToSonatype closeAndReleaseSonatypeStagingRepository -x check --info --stacktrace

0 commit comments

Comments
 (0)