-
Notifications
You must be signed in to change notification settings - Fork 1.6k
ci: add coverage check workflow #6582
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: develop
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,92 @@ | ||
| name: Base Coverage Upload | ||
|
|
||
| on: | ||
| push: | ||
| branches: [ 'develop', 'release_**' ] | ||
|
|
||
| permissions: | ||
| contents: read | ||
|
|
||
| concurrency: | ||
| group: ${{ github.workflow }}-${{ github.ref }} | ||
| cancel-in-progress: true | ||
|
|
||
| jobs: | ||
| build-base-coverage: | ||
| name: Build Base Coverage | ||
| runs-on: ubuntu-24.04 | ||
| timeout-minutes: 60 | ||
|
|
||
| steps: | ||
| - name: Checkout code | ||
| uses: actions/checkout@v5 | ||
| with: | ||
| fetch-depth: 0 | ||
|
|
||
| - name: Set up JDK 8 | ||
| uses: actions/setup-java@v5 | ||
| with: | ||
| java-version: '8' | ||
| distribution: 'temurin' | ||
| cache: 'gradle' | ||
|
|
||
| - name: Check Java version | ||
| run: java -version | ||
|
|
||
| - name: Grant execute permission | ||
| run: chmod +x gradlew | ||
|
|
||
| - name: Stop Gradle daemon | ||
| run: ./gradlew --stop || true | ||
|
|
||
| - name: Build | ||
| run: ./gradlew clean build --no-daemon --no-build-cache --parallel | ||
|
|
||
| - name: Generate JaCoCo report | ||
| run: ./gradlew jacocoTestReport --no-daemon --no-build-cache | ||
|
|
||
| - name: Upload coverage artifacts | ||
| uses: actions/upload-artifact@v5 | ||
| with: | ||
| name: base-jacoco-xml | ||
| path: | | ||
| actuator/build/reports/jacoco/test/jacocoTestReport.xml | ||
| chainbase/build/reports/jacoco/test/jacocoTestReport.xml | ||
| common/build/reports/jacoco/test/jacocoTestReport.xml | ||
| consensus/build/reports/jacoco/test/jacocoTestReport.xml | ||
| crypto/build/reports/jacoco/test/jacocoTestReport.xml | ||
| framework/build/reports/jacoco/test/jacocoTestReport.xml | ||
| plugins/build/reports/jacoco/test/jacocoTestReport.xml | ||
| if-no-files-found: error | ||
|
|
||
| upload-base-coverage: | ||
| name: Upload Base Coverage to Codecov | ||
| needs: build-base-coverage | ||
| runs-on: ubuntu-latest | ||
| timeout-minutes: 20 | ||
|
|
||
| steps: | ||
| - name: Checkout repo | ||
| uses: actions/checkout@v5 | ||
| with: | ||
| fetch-depth: 0 | ||
|
|
||
| - name: Download coverage artifacts | ||
| uses: actions/download-artifact@v5 | ||
| with: | ||
| name: base-jacoco-xml | ||
| path: coverage-artifacts | ||
|
|
||
| - name: Show coverage files | ||
| run: find coverage-artifacts -type f | sort | ||
|
|
||
| - name: Upload base coverage to Codecov | ||
| uses: codecov/codecov-action@v5 | ||
| with: | ||
| token: ${{ secrets.CODECOV_TOKEN }} | ||
| directory: ./coverage-artifacts | ||
| root_dir: ./ | ||
| gcov_executable: '' | ||
| override_branch: ${{ github.ref_name }} | ||
| fail_ci_if_error: true | ||
| verbose: true | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,58 @@ | ||
| name: Coverage Build | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It is recommended to merge the PR code coverage workflow files. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
|
|
||
| on: | ||
| pull_request: | ||
| branches: [ 'develop', 'release_**' ] | ||
| types: [ opened, synchronize, reopened ] | ||
|
|
||
| concurrency: | ||
| group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} | ||
| cancel-in-progress: true | ||
|
|
||
| permissions: | ||
| contents: read | ||
|
|
||
| jobs: | ||
| build-coverage: | ||
| name: Build ubuntu24 (JDK 8 / x86_64) | ||
| runs-on: ubuntu-24.04 | ||
| timeout-minutes: 60 | ||
|
|
||
| steps: | ||
| - name: Checkout code | ||
| uses: actions/checkout@v5 | ||
| with: | ||
| fetch-depth: 0 | ||
|
|
||
| - name: Set up JDK 8 | ||
| uses: actions/setup-java@v5 | ||
| with: | ||
| java-version: '8' | ||
| distribution: 'temurin' | ||
| cache: 'gradle' | ||
|
|
||
| - name: Check Java version | ||
| run: java -version | ||
|
|
||
| - name: Stop Gradle daemon | ||
| run: ./gradlew --stop || true | ||
|
|
||
| - name: Build | ||
| run: ./gradlew clean build --no-daemon --no-build-cache --parallel | ||
|
|
||
| - name: Generate JaCoCo report | ||
| run: ./gradlew jacocoTestReport --no-daemon --no-build-cache | ||
|
|
||
| - name: Upload JaCoCo artifact | ||
| uses: actions/upload-artifact@v5 | ||
| with: | ||
| name: jacoco-coverage | ||
| path: | | ||
| actuator/build/reports/jacoco/test/jacocoTestReport.xml | ||
| chainbase/build/reports/jacoco/test/jacocoTestReport.xml | ||
| common/build/reports/jacoco/test/jacocoTestReport.xml | ||
| consensus/build/reports/jacoco/test/jacocoTestReport.xml | ||
| crypto/build/reports/jacoco/test/jacocoTestReport.xml | ||
| framework/build/reports/jacoco/test/jacocoTestReport.xml | ||
| plugins/build/reports/jacoco/test/jacocoTestReport.xml | ||
| if-no-files-found: error | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,73 @@ | ||
| name: Codecov Upload & Compare | ||
|
|
||
| on: | ||
| workflow_run: | ||
| workflows: | ||
| - Coverage Build | ||
| types: | ||
| - completed | ||
|
|
||
| permissions: | ||
| contents: read | ||
| actions: read | ||
| pull-requests: read | ||
|
|
||
| jobs: | ||
| upload-coverage: | ||
| name: Upload Coverage | ||
| if: > | ||
| github.event.workflow_run.conclusion == 'success' && | ||
| github.event.workflow_run.event == 'pull_request' | ||
| runs-on: ubuntu-latest | ||
| outputs: | ||
| pr_number: ${{ steps.pr.outputs.pr_number }} | ||
|
|
||
| steps: | ||
| - name: Checkout repo | ||
| uses: actions/checkout@v5 # must download source code | ||
| with: | ||
| fetch-depth: 0 | ||
| persist-credentials: false | ||
|
|
||
| - name: Download coverage artifact | ||
| uses: actions/download-artifact@v5 | ||
| with: | ||
| name: jacoco-coverage | ||
| path: coverage | ||
| run-id: ${{ github.event.workflow_run.id }} | ||
| github-token: ${{ secrets.GITHUB_TOKEN }} | ||
|
|
||
| - name: Get PR details | ||
| id: pr | ||
| uses: actions/github-script@v8 | ||
| with: | ||
| script: | | ||
| const headSha = context.payload.workflow_run.head_sha; | ||
| const headOwner = context.payload.workflow_run.head_repository.owner.login; | ||
| const headBranch = context.payload.workflow_run.head_branch; | ||
| const { data: pulls } = await github.rest.pulls.list({ | ||
| owner: context.repo.owner, | ||
| repo: context.repo.repo, | ||
| state: 'open', | ||
| head: `${headOwner}:${headBranch}` | ||
| }); | ||
| if (pulls.length > 0) { | ||
| const pr = pulls[0]; | ||
| core.setOutput('pr_number', pr.number); | ||
| core.setOutput('pr_sha', headSha); | ||
| core.setOutput('pr_branch', headBranch); | ||
| core.setOutput('base_sha', pr.base.sha); | ||
| } else { | ||
| core.setFailed(`No open pull request found for ${headOwner}:${headBranch}`); | ||
| } | ||
|
|
||
| - name: Upload to Codecov | ||
| if: ${{ steps.pr.outputs.pr_number != '' }} | ||
| uses: codecov/codecov-action@v5 | ||
| with: | ||
| token: ${{ secrets.CODECOV_TOKEN }} | ||
| override_commit: ${{ steps.pr.outputs.pr_sha }} | ||
| override_branch: ${{ steps.pr.outputs.pr_branch }} | ||
| override_pr: ${{ steps.pr.outputs.pr_number }} | ||
| fail_ci_if_error: true | ||
| verbose: true |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,119 @@ | ||
| name: Waiting Coverage project | ||
|
|
||
| on: | ||
| pull_request: | ||
| branches: [ 'develop', 'release_**' ] | ||
| types: [ opened, synchronize, reopened ] | ||
|
|
||
| permissions: | ||
| contents: read | ||
| checks: read | ||
| statuses: read | ||
| pull-requests: read | ||
|
|
||
| concurrency: | ||
| group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} | ||
| cancel-in-progress: true | ||
|
|
||
| jobs: | ||
| waiting-coverage-project: | ||
| name: waiting-coverage-report | ||
| runs-on: ubuntu-latest | ||
| timeout-minutes: 70 | ||
|
|
||
| steps: | ||
| - name: Wait for codecov/project status | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. After uploading the coverage event, check whether it was successful. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Workflow |
||
| uses: actions/github-script@v8 | ||
| with: | ||
| script: | | ||
| const owner = context.repo.owner; | ||
| const repo = context.repo.repo; | ||
| const ref = context.payload.pull_request.head.sha; | ||
|
|
||
| const targetContext = 'codecov/project'; | ||
| const maxAttempts = 120; // 120 * 30s = 60 minutes | ||
| const intervalMs = 30 * 1000; | ||
|
|
||
| function sleep(ms) { | ||
| return new Promise(resolve => setTimeout(resolve, ms)); | ||
| } | ||
|
|
||
| for (let attempt = 1; attempt <= maxAttempts; attempt++) { | ||
| core.info(`Polling attempt ${attempt}/${maxAttempts} for ${targetContext} on ${ref}`); | ||
|
|
||
| try { | ||
| // Check legacy commit statuses | ||
| const combined = await github.rest.repos.getCombinedStatusForRef({ | ||
| owner, | ||
| repo, | ||
| ref, | ||
| per_page: 100 | ||
| }); | ||
|
|
||
| const statuses = combined.data.statuses || []; | ||
| const matchedStatus = statuses.find(s => s.context === targetContext); | ||
|
|
||
| if (matchedStatus) { | ||
| core.info(`Found commit status: ${matchedStatus.context} = ${matchedStatus.state}`); | ||
|
|
||
| if (matchedStatus.state === 'success') { | ||
| core.info(`${targetContext} succeeded.`); | ||
| return; | ||
| } | ||
|
|
||
| if (matchedStatus.state === 'failure' || matchedStatus.state === 'error') { | ||
| core.setFailed(`${targetContext} is ${matchedStatus.state}.`); | ||
| return; | ||
| } | ||
|
|
||
| // pending | ||
| await sleep(intervalMs); | ||
| continue; | ||
| } | ||
|
|
||
| // Check check-runs as a fallback | ||
| const checks = await github.rest.checks.listForRef({ | ||
| owner, | ||
| repo, | ||
| ref, | ||
| per_page: 100 | ||
| }); | ||
|
|
||
| const checkRuns = checks.data.check_runs || []; | ||
| const matchedCheck = checkRuns.find(c => c.name === targetContext); | ||
|
|
||
| if (matchedCheck) { | ||
| core.info( | ||
| `Found check run: ${matchedCheck.name}, status=${matchedCheck.status}, conclusion=${matchedCheck.conclusion}` | ||
| ); | ||
|
|
||
| if (matchedCheck.status === 'completed') { | ||
| if (matchedCheck.conclusion === 'success') { | ||
| core.info(`${targetContext} succeeded.`); | ||
| return; | ||
| } | ||
|
|
||
| core.setFailed( | ||
| `${targetContext} completed with conclusion=${matchedCheck.conclusion}.` | ||
| ); | ||
| return; | ||
| } | ||
|
|
||
| // queued / in_progress | ||
| await sleep(intervalMs); | ||
| continue; | ||
| } | ||
|
|
||
| core.info(`${targetContext} not reported yet. Waiting...`); | ||
| } catch (error) { | ||
| core.warning( | ||
| `Attempt ${attempt}/${maxAttempts} failed with transient error: ${error.message}. Retrying in ${intervalMs / 1000}s...` | ||
| ); | ||
| } | ||
|
|
||
| await sleep(intervalMs); | ||
| } | ||
|
|
||
| core.setFailed( | ||
| `Timed out waiting for ${targetContext} to report success on commit ${ref}.` | ||
| ); | ||
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Base coverage should be queried first, and regenerated only if coverage for a corresponding commit is not found. This improves efficiency.
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let’s clarify the roles of the two secrets that only access in tronprotocol environment:
secrets.CODECOV_TOKEN: used to upload coverage artifactssecrets.CODECOV_API_TOKEN: used to query coverage reportsDue to GitHub’s permission restrictions,
secrets.CODECOV_API_TOKENis not available in forked pull requests, which prevents querying the base repository’s coverage first.In addition, the maintainers of java-tron have not configured
secrets.CODECOV_API_TOKEN; only the upload token (secrets.CODECOV_TOKEN) is set.