@@ -93,53 +93,17 @@ jobs:
9393 core.info('PR lint passed.');
9494 }
9595
96- build :
97- name : Build (JDK ${{ matrix.java }} / ${{ matrix.arch }})
98- needs : pr-lint
99- runs-on : ${{ matrix.runner }}
100- strategy :
101- fail-fast : false
102- matrix :
103- include :
104- - java : ' 8'
105- runner : ubuntu-latest
106- arch : x86_64
107- - java : ' 17'
108- runner : ubuntu-24.04-arm
109- arch : aarch64
110-
111- steps :
112- - uses : actions/checkout@v4
113-
114- - name : Set up JDK ${{ matrix.java }}
115- uses : actions/setup-java@v4
116- with :
117- java-version : ${{ matrix.java }}
118- distribution : ' temurin'
119-
120- - name : Cache Gradle packages
121- uses : actions/cache@v4
122- with :
123- path : |
124- ~/.gradle/caches
125- ~/.gradle/wrapper
126- key : ${{ runner.os }}-${{ matrix.arch }}-gradle-${{ hashFiles('**/*.gradle', '**/gradle-wrapper.properties') }}
127- restore-keys : ${{ runner.os }}-${{ matrix.arch }}-gradle-
128-
129- - name : Build
130- run : ./gradlew clean build -x test
131-
13296 checkstyle :
13397 name : Checkstyle
134- runs-on : ubuntu-latest
98+ runs-on : ubuntu-24.04-arm
13599
136100 steps :
137101 - uses : actions/checkout@v4
138102
139- - name : Set up JDK 8
103+ - name : Set up JDK 17
140104 uses : actions/setup-java@v4
141105 with :
142- java-version : ' 8 '
106+ java-version : ' 17 '
143107 distribution : ' temurin'
144108
145109 - name : Cache Gradle packages
@@ -163,20 +127,29 @@ jobs:
163127 framework/build/reports/checkstyle/
164128 plugins/build/reports/checkstyle/
165129
166- test :
167- name : Unit Tests (JDK ${{ matrix.java }} / ${{ matrix.arch }})
130+ build :
131+ name : Build ${{ matrix.os-name }}(JDK ${{ matrix.java }} / ${{ matrix.arch }})
132+ needs : [pr-lint, checkstyle]
168133 runs-on : ${{ matrix.runner }}
169- needs : build
170- timeout-minutes : 60
171134 strategy :
172135 fail-fast : false
173136 matrix :
174137 include :
175138 - java : ' 8'
176139 runner : ubuntu-latest
140+ os-name : ubuntu
177141 arch : x86_64
178142 - java : ' 17'
179143 runner : ubuntu-24.04-arm
144+ os-name : ubuntu
145+ arch : aarch64
146+ - java : ' 8'
147+ runner : macos-26-intel
148+ os-name : macos
149+ arch : x86_64
150+ - java : ' 17'
151+ runner : macos-latest
152+ os-name : macos
180153 arch : aarch64
181154
182155 steps :
@@ -197,13 +170,280 @@ jobs:
197170 key : ${{ runner.os }}-${{ matrix.arch }}-gradle-${{ hashFiles('**/*.gradle', '**/gradle-wrapper.properties') }}
198171 restore-keys : ${{ runner.os }}-${{ matrix.arch }}-gradle-
199172
200- - name : Run tests
201- run : ./gradlew test
173+ - name : Build
174+ run : ./gradlew clean build --no-daemon
175+
176+ docker-build-rockylinux :
177+ name : Build rockylinux (JDK 8 / x86_64)
178+ needs : [pr-lint, checkstyle]
179+ runs-on : ubuntu-latest
180+
181+ container :
182+ image : rockylinux:8
202183
203- - name : Upload test reports
204- if : failure()
184+ env :
185+ GRADLE_USER_HOME : /github/home/.gradle
186+ LANG : en_US.UTF-8
187+ LC_ALL : en_US.UTF-8
188+
189+ steps :
190+ - name : Checkout code
191+ uses : actions/checkout@v4
192+
193+ - name : Install dependencies (Rocky 8 + JDK8)
194+ run : |
195+ set -euxo pipefail
196+ dnf -y install java-1.8.0-openjdk-devel git wget unzip which jq bc curl glibc-langpack-en
197+ dnf -y groupinstall "Development Tools"
198+
199+ - name : Check Java version
200+ run : java -version
201+
202+ - name : Cache Gradle
203+ uses : actions/cache@v4
204+ with :
205+ path : |
206+ /github/home/.gradle/caches
207+ /github/home/.gradle/wrapper
208+ key : ${{ runner.os }}-rockylinux-gradle-${{ hashFiles('**/*.gradle*', '**/gradle-wrapper.properties') }}
209+ restore-keys : |
210+ ${{ runner.os }}-rockylinux-gradle-
211+
212+ - name : Prepare checkstyle config copy
213+ run : |
214+ set -euxo pipefail
215+ cp -f config/checkstyle/checkStyle.xml config/checkstyle/checkStyleAll.xml || true
216+
217+ - name : Grant execute permission
218+ run : chmod +x gradlew
219+
220+ - name : Stop Gradle daemon
221+ run : ./gradlew --stop || true
222+
223+ - name : Build
224+ run : ./gradlew clean build --no-daemon --no-build-cache
225+ # run: |
226+ # ./gradlew clean build -x test --no-daemon --no-build-cache
227+ # ./gradlew framework:test --tests org.tron.core.zksnark.ShieldedReceiveTest
228+
229+ - name : Generate JaCoCo report
230+ run : ./gradlew jacocoTestReport --no-daemon --no-build-cache
231+
232+ - name : Upload JaCoCo artifacts
205233 uses : actions/upload-artifact@v4
206234 with :
207- name : test-reports-${{ matrix.arch }}
235+ name : jacoco-rockylinux
208236 path : |
209- **/build/reports/tests/
237+ **/build/reports/jacoco/test/jacocoTestReport.xml
238+ **/build/reports/**
239+ **/build/test-results/**
240+ if-no-files-found : error
241+
242+ docker-build-debian11 :
243+ name : Build debian11 (JDK 8 / x86_64)
244+ needs : [pr-lint, checkstyle]
245+ runs-on : ubuntu-latest
246+
247+ container :
248+ image : eclipse-temurin:8-jdk # base image is Debian 11 (Bullseye)
249+
250+ defaults :
251+ run :
252+ shell : bash
253+
254+ env :
255+ GRADLE_USER_HOME : /github/home/.gradle
256+
257+ steps :
258+ - name : Checkout code
259+ uses : actions/checkout@v4
260+
261+ - name : Install dependencies (Debian + build tools)
262+ run : |
263+ set -euxo pipefail
264+ apt-get update
265+ apt-get install -y git wget unzip build-essential curl jq
266+
267+ - name : Check Java version
268+ run : java -version
269+
270+ - name : Cache Gradle
271+ uses : actions/cache@v4
272+ with :
273+ path : |
274+ /github/home/.gradle/caches
275+ /github/home/.gradle/wrapper
276+ key : ${{ runner.os }}-debian11-gradle-${{ hashFiles('**/*.gradle*', '**/gradle-wrapper.properties') }}
277+ restore-keys : |
278+ ${{ runner.os }}-debian11-gradle-
279+
280+ - name : Grant execute permission
281+ run : chmod +x gradlew
282+
283+ - name : Build
284+ run : ./gradlew clean build --no-daemon --no-build-cache
285+
286+
287+ coverage-gate :
288+ name : Coverage Gate (from rockylinux build)
289+ needs : docker-build-rockylinux
290+ runs-on : ubuntu-latest
291+
292+ permissions :
293+ contents : read
294+
295+ defaults :
296+ run :
297+ shell : bash
298+
299+ steps :
300+ - name : Checkout code (needed by codecov-action for git context)
301+ uses : actions/checkout@v4
302+
303+ - name : Download JaCoCo artifacts (rockylinux)
304+ uses : actions/download-artifact@v4
305+ with :
306+ name : jacoco-rockylinux
307+ path : artifacts/jacoco-rockylinux
308+
309+ - name : List downloaded reports
310+ run : |
311+ set -eux
312+ echo "JaCoCo XML reports found:"
313+ find artifacts/jacoco-rockylinux -name jacocoTestReport.xml
314+
315+ - name : Upload coverage to Codecov
316+ uses : codecov/codecov-action@v5
317+ with :
318+ token : ${{ secrets.CODECOV_TOKEN }}
319+ directory : artifacts/jacoco-rockylinux
320+ override_commit : ${{ github.event.pull_request.head.sha }}
321+ override_branch : ${{ github.event.pull_request.head.ref }}
322+ override_pr : ${{ github.event.pull_request.number }}
323+ verbose : true
324+ fail_ci_if_error : true
325+
326+ - name : Install tools
327+ run : sudo apt-get update && sudo apt-get install -y jq bc curl
328+
329+ - name : Wait for Codecov processing
330+ env :
331+ CODECOV_API_TOKEN : ${{ secrets.CODECOV_API_TOKEN }}
332+ CODECOV_OWNER : ${{ github.repository_owner }}
333+ CODECOV_REPO : ${{ github.event.repository.name }}
334+ COMMIT_ID : ${{ github.event.pull_request.head.sha }}
335+ run : |
336+ set -euxo pipefail
337+
338+ API_URL="https://api.codecov.io/api/v2/github/${CODECOV_OWNER}/repos/${CODECOV_REPO}/commits/${COMMIT_ID}"
339+ MAX_ATTEMPTS=20
340+ INTERVAL=30
341+
342+ for i in $(seq 1 $MAX_ATTEMPTS); do
343+ echo "=== Polling attempt $i / $MAX_ATTEMPTS ==="
344+
345+ http_code=$(curl -sS -o /tmp/poll.json -w '%{http_code}' \
346+ -H "Authorization: Bearer ${CODECOV_API_TOKEN}" \
347+ "$API_URL")
348+
349+ if [ "$http_code" = "200" ]; then
350+ state=$(jq -r '.state // "unknown"' /tmp/poll.json)
351+ echo "Commit processing state: $state"
352+ if [ "$state" = "complete" ]; then
353+ echo "Codecov has finished processing."
354+ exit 0
355+ fi
356+ else
357+ echo "HTTP $http_code — commit not yet available."
358+ cat /tmp/poll.json 2>/dev/null || true
359+ fi
360+
361+ if [ "$i" -lt "$MAX_ATTEMPTS" ]; then
362+ sleep "$INTERVAL"
363+ fi
364+ done
365+
366+ echo "Timed out waiting for Codecov (${MAX_ATTEMPTS} x ${INTERVAL}s)."
367+ exit 1
368+
369+ - name : Coverage gate via Codecov REST API
370+ env :
371+ CODECOV_API_TOKEN : ${{ secrets.CODECOV_API_TOKEN }}
372+ CODECOV_OWNER : ${{ github.repository_owner }}
373+ CODECOV_REPO : ${{ github.event.repository.name }}
374+ COMMIT_ID : ${{ github.event.pull_request.head.sha }}
375+ BASE_BRANCH : ${{ github.event.pull_request.base.ref }}
376+ PR_NUMBER : ${{ github.event.pull_request.number }}
377+ run : |
378+ set -euxo pipefail
379+
380+ API_BASE="https://api.codecov.io/api/v2/github/${CODECOV_OWNER}/repos/${CODECOV_REPO}"
381+ AUTH="Authorization: Bearer ${CODECOV_API_TOKEN}"
382+
383+ # Helper: GET with error handling
384+ api_get() {
385+ local url="$1"
386+ local http_code
387+ http_code=$(curl -sS -o /tmp/api_out.json -w '%{http_code}' \
388+ -H "$AUTH" "$url")
389+ if [ "$http_code" != "200" ]; then
390+ echo "ERROR: GET $url => HTTP $http_code" >&2
391+ cat /tmp/api_out.json >&2
392+ return 1
393+ fi
394+ cat /tmp/api_out.json
395+ }
396+
397+ # 1) Current commit coverage
398+ echo "=== 1. Current commit coverage (sha: ${COMMIT_ID}) ==="
399+ commit_resp=$(api_get "${API_BASE}/totals/?sha=${COMMIT_ID}")
400+ self_cov=$(echo "$commit_resp" | jq -r '.totals.coverage // 0')
401+ echo "self_cov = ${self_cov}%"
402+
403+ # 2) Base branch head coverage
404+ echo "=== 2. Base branch coverage (branch: ${BASE_BRANCH}) ==="
405+ base_resp=$(api_get "${API_BASE}/totals/?branch=${BASE_BRANCH}")
406+ base_branch_cov=$(echo "$base_resp" | jq -r '.totals.coverage // 0')
407+ echo "base_branch_cov = ${base_branch_cov}%"
408+
409+ # 3) PR comparison — patch coverage
410+ echo "=== 3. PR #${PR_NUMBER} comparison ==="
411+ compare_resp=$(api_get "${API_BASE}/compare/?pullid=${PR_NUMBER}")
412+ patch_cov=$(echo "$compare_resp" | jq -r '.totals.patch.coverage // 0')
413+ impacted_files=$(echo "$compare_resp" | jq -r '(.files // []) | length')
414+ echo "patch_cov = ${patch_cov}%"
415+ echo "impacted_files = ${impacted_files}"
416+
417+ # ===== Gate Rules =====
418+
419+ # Rule 1: current commit must have valid coverage
420+ if [ "$(echo "$self_cov <= 0" | bc)" -eq 1 ]; then
421+ echo "FAIL: Could not retrieve valid coverage for commit ${COMMIT_ID}."
422+ exit 1
423+ fi
424+
425+ # Rule 2: overall coverage must not decrease vs base branch
426+ if [ "$(echo "$self_cov < $base_branch_cov" | bc)" -eq 1 ]; then
427+ echo "FAIL: Overall coverage decreased!"
428+ echo " Current commit : ${self_cov}%"
429+ echo " Base branch : ${base_branch_cov}%"
430+ echo "Please add unit tests to maintain coverage."
431+ exit 1
432+ fi
433+
434+ # Rule 3: patch coverage on changed files >= 80%
435+ # if [ "$impacted_files" -gt 0 ] && [ "$(echo "$patch_cov > 0" | bc)" -eq 1 ]; then
436+ # if [ "$(echo "$patch_cov < 80" | bc)" -eq 1 ]; then
437+ # echo "FAIL: Patch coverage is ${patch_cov}% (minimum 80%)."
438+ # echo "Please add tests for new/changed code."
439+ # exit 1
440+ # fi
441+ # else
442+ # echo "No impacted files or no patch data; skipping patch coverage check."
443+ # fi
444+
445+ echo ""
446+ echo "All coverage gates passed!"
447+ echo " Current commit : ${self_cov}%"
448+ echo " Base branch : ${base_branch_cov}%"
449+ echo " Patch coverage : ${patch_cov}%"
0 commit comments