|
| 1 | +# Runs the unit-test gate on GitHub Actions, replacing the monolithic |
| 2 | +# CodeBuild `./gradlew build`. The unit-test suite runs exactly once (via Kover, |
| 3 | +# which also emits the coverage report), and static analysis runs in parallel so |
| 4 | +# cheap failures surface fast. Coverage upload is observability only and never |
| 5 | +# gates the merge. |
| 6 | + |
| 7 | +name: PR Verification |
| 8 | + |
| 9 | +on: |
| 10 | + pull_request: |
| 11 | + branches: |
| 12 | + - 'main' |
| 13 | + push: |
| 14 | + branches: |
| 15 | + - 'main' |
| 16 | + workflow_dispatch: |
| 17 | + |
| 18 | +permissions: |
| 19 | + contents: read |
| 20 | + # Required for the test-report step to attach annotations to the run's check. |
| 21 | + # Note: fork PRs get a read-only token, so annotations are skipped there — the |
| 22 | + # step is continue-on-error so this never fails the required job, and the |
| 23 | + # actual test pass/fail is still determined by the Gradle exit code. |
| 24 | + checks: write |
| 25 | + |
| 26 | +concurrency: |
| 27 | + group: ${{ github.workflow }}-${{ github.ref }} |
| 28 | + # Only cancel superseded runs on PRs. Runs on `main` are never cancelled — |
| 29 | + # cancelling one would drop that commit's Codecov upload and leave a gap in |
| 30 | + # main's coverage history. |
| 31 | + cancel-in-progress: ${{ github.event_name == 'pull_request' }} |
| 32 | + |
| 33 | +jobs: |
| 34 | + # REQUIRED. Runs the full unit-test suite once and uploads coverage to Codecov |
| 35 | + # as a soft-fail (observability-only) step. |
| 36 | + unit-tests: |
| 37 | + runs-on: ubuntu-latest |
| 38 | + env: |
| 39 | + CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} |
| 40 | + |
| 41 | + steps: |
| 42 | + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 |
| 43 | + |
| 44 | + - name: Setup Java |
| 45 | + uses: actions/setup-java@b6effb05e454b25005698d916606bdc6ffcbf961 # v5 |
| 46 | + with: |
| 47 | + java-version: '17' |
| 48 | + distribution: 'corretto' |
| 49 | + |
| 50 | + - name: Setup Gradle |
| 51 | + uses: gradle/actions/setup-gradle@9c971963bec38e04b3d30dcc455b5382be2fdbfb # v6.3.0 |
| 52 | + |
| 53 | + # `koverXmlReport` runs the unit-test suite once and emits the coverage |
| 54 | + # report as a byproduct. Note: Kover only aggregates modules that apply the |
| 55 | + # Kover plugin, which is applied via PublishingConventionPlugin — so only |
| 56 | + # *published* modules have their tests run here. Every module with test |
| 57 | + # sources is currently also published, so this is at parity with the old |
| 58 | + # `./gradlew build` gate. A future non-published module with unit tests |
| 59 | + # would silently drop out of this gate (see design doc; follow-up: a CI |
| 60 | + # guard that fails if a module has test sources but no Kover plugin). |
| 61 | + - name: Run tests and generate Kover report |
| 62 | + run: ./gradlew koverXmlReport |
| 63 | + |
| 64 | + # Surfaces failing tests as inline annotations on this job's check (no |
| 65 | + # separate check run — annotate_only). Runs even when the test step failed |
| 66 | + # (that's when it's most useful) and is soft-fail so a read-only token on |
| 67 | + # fork PRs never fails the job. |
| 68 | + - name: Publish test report annotations |
| 69 | + uses: mikepenz/action-junit-report@d9f48fc87bc235f7e214acf696ca5abc0a986f16 # v6.4.2 |
| 70 | + if: ${{ !cancelled() }} |
| 71 | + continue-on-error: true |
| 72 | + with: |
| 73 | + report_paths: '**/build/test-results/**/*.xml' |
| 74 | + annotate_only: true |
| 75 | + |
| 76 | + # Soft-fail: Codecov upload is observability only and must never fail this |
| 77 | + # required job. Skipped on fork PRs where the token is absent. |
| 78 | + - name: Upload coverage to Codecov |
| 79 | + if: ${{ !cancelled() && env.CODECOV_TOKEN != '' }} |
| 80 | + continue-on-error: true |
| 81 | + uses: codecov/codecov-action@fb8b3582c8e4def4969c97caa2f19720cb33a72f # v6 |
| 82 | + with: |
| 83 | + name: report |
| 84 | + files: build/reports/kover/report.xml |
| 85 | + token: ${{ env.CODECOV_TOKEN }} |
| 86 | + |
| 87 | + - name: Upload test reports |
| 88 | + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 |
| 89 | + if: failure() |
| 90 | + with: |
| 91 | + name: test-reports |
| 92 | + path: '**/reports/tests/**' |
| 93 | + retention-days: 7 |
| 94 | + |
| 95 | + # REQUIRED. Runs in parallel with unit-tests so lint/format/API-compat breaks |
| 96 | + # surface fast. `lint` is included because the old `./gradlew build` gate ran |
| 97 | + # Android lint with abortOnError/warningsAsErrors — dropping it would silently |
| 98 | + # remove a gating check. |
| 99 | + static-analysis: |
| 100 | + runs-on: ubuntu-latest |
| 101 | + |
| 102 | + steps: |
| 103 | + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 |
| 104 | + |
| 105 | + - name: Setup Java |
| 106 | + uses: actions/setup-java@b6effb05e454b25005698d916606bdc6ffcbf961 # v5 |
| 107 | + with: |
| 108 | + java-version: '17' |
| 109 | + distribution: 'corretto' |
| 110 | + |
| 111 | + - name: Setup Gradle |
| 112 | + uses: gradle/actions/setup-gradle@ed408507eac070d1f99cc633dbcf757c94c7933a # v4.4.3 |
| 113 | + |
| 114 | + - name: Run static analysis |
| 115 | + run: ./gradlew ktlintCheck checkstyle apiCheck lint |
| 116 | + |
| 117 | + # REQUIRED. Verifies that every external type in each published module's public |
| 118 | + # API surface is resolvable on the compile classpath a downstream consumer |
| 119 | + # assembles from the published artifact. A failure means a dependency supplying |
| 120 | + # a public-API type is scoped `implementation` (runtime) but must be `api` |
| 121 | + # (compile). Runs in parallel with the other gates. |
| 122 | + scope-check: |
| 123 | + runs-on: ubuntu-latest |
| 124 | + # Only needs read access; the workflow-level `checks: write` (for the |
| 125 | + # test-report annotator) is not required here. |
| 126 | + permissions: |
| 127 | + contents: read |
| 128 | + |
| 129 | + steps: |
| 130 | + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 |
| 131 | + |
| 132 | + - name: Setup Java |
| 133 | + uses: actions/setup-java@b6effb05e454b25005698d916606bdc6ffcbf961 # v5 |
| 134 | + with: |
| 135 | + java-version: '17' |
| 136 | + distribution: 'corretto' |
| 137 | + |
| 138 | + - name: Setup Gradle |
| 139 | + uses: gradle/actions/setup-gradle@ed408507eac070d1f99cc633dbcf757c94c7933a # v4.4.3 |
| 140 | + |
| 141 | + - name: Verify API scopes |
| 142 | + run: scripts/verify_api_scopes.sh |
0 commit comments