chore: Run PR verification (unit tests, coverage, static analysis) on… #6
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| # Runs the unit-test gate on GitHub Actions, replacing the monolithic | |
| # CodeBuild `./gradlew build`. The unit-test suite runs exactly once (via Kover, | |
| # which also emits the coverage report), and static analysis runs in parallel so | |
| # cheap failures surface fast. Coverage upload is observability only and never | |
| # gates the merge. | |
| name: PR Verification | |
| on: | |
| pull_request: | |
| branches: | |
| - 'main' | |
| push: | |
| branches: | |
| - 'main' | |
| workflow_dispatch: | |
| permissions: | |
| contents: read | |
| # Required for the test-report step to attach annotations to the run's check. | |
| # Note: fork PRs get a read-only token, so annotations are skipped there — the | |
| # step is continue-on-error so this never fails the required job, and the | |
| # actual test pass/fail is still determined by the Gradle exit code. | |
| checks: write | |
| concurrency: | |
| group: ${{ github.workflow }}-${{ github.ref }} | |
| # Only cancel superseded runs on PRs. Runs on `main` are never cancelled — | |
| # cancelling one would drop that commit's Codecov upload and leave a gap in | |
| # main's coverage history. | |
| cancel-in-progress: ${{ github.event_name == 'pull_request' }} | |
| jobs: | |
| # REQUIRED. Runs the full unit-test suite once and uploads coverage to Codecov | |
| # as a soft-fail (observability-only) step. | |
| unit-tests: | |
| runs-on: ubuntu-latest | |
| env: | |
| CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} | |
| steps: | |
| - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 | |
| - name: Setup Java | |
| uses: actions/setup-java@b6effb05e454b25005698d916606bdc6ffcbf961 # v5 | |
| with: | |
| java-version: '17' | |
| distribution: 'corretto' | |
| - name: Setup Gradle | |
| uses: gradle/actions/setup-gradle@9c971963bec38e04b3d30dcc455b5382be2fdbfb # v6.3.0 | |
| # `koverXmlReport` runs the unit-test suite once and emits the coverage | |
| # report as a byproduct. Note: Kover only aggregates modules that apply the | |
| # Kover plugin, which is applied via PublishingConventionPlugin — so only | |
| # *published* modules have their tests run here. Every module with test | |
| # sources is currently also published, so this is at parity with the old | |
| # `./gradlew build` gate. A future non-published module with unit tests | |
| # would silently drop out of this gate (see design doc; follow-up: a CI | |
| # guard that fails if a module has test sources but no Kover plugin). | |
| - name: Run tests and generate Kover report | |
| run: ./gradlew koverXmlReport | |
| # Surfaces failing tests as inline annotations on this job's check (no | |
| # separate check run — annotate_only). Runs even when the test step failed | |
| # (that's when it's most useful) and is soft-fail so a read-only token on | |
| # fork PRs never fails the job. | |
| - name: Publish test report annotations | |
| uses: mikepenz/action-junit-report@d9f48fc87bc235f7e214acf696ca5abc0a986f16 # v6.4.2 | |
| if: ${{ !cancelled() }} | |
| continue-on-error: true | |
| with: | |
| report_paths: '**/build/test-results/**/*.xml' | |
| annotate_only: true | |
| # Soft-fail: Codecov upload is observability only and must never fail this | |
| # required job. Skipped on fork PRs where the token is absent. | |
| - name: Upload coverage to Codecov | |
| if: ${{ !cancelled() && env.CODECOV_TOKEN != '' }} | |
| continue-on-error: true | |
| uses: codecov/codecov-action@fb8b3582c8e4def4969c97caa2f19720cb33a72f # v6 | |
| with: | |
| name: report | |
| files: build/reports/kover/report.xml | |
| token: ${{ env.CODECOV_TOKEN }} | |
| - name: Upload test reports | |
| uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 | |
| if: failure() | |
| with: | |
| name: test-reports | |
| path: '**/reports/tests/**' | |
| retention-days: 7 | |
| # REQUIRED. Runs in parallel with unit-tests so lint/format/API-compat breaks | |
| # surface fast. `lint` is included because the old `./gradlew build` gate ran | |
| # Android lint with abortOnError/warningsAsErrors — dropping it would silently | |
| # remove a gating check. | |
| static-analysis: | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 | |
| - name: Setup Java | |
| uses: actions/setup-java@b6effb05e454b25005698d916606bdc6ffcbf961 # v5 | |
| with: | |
| java-version: '17' | |
| distribution: 'corretto' | |
| - name: Setup Gradle | |
| uses: gradle/actions/setup-gradle@ed408507eac070d1f99cc633dbcf757c94c7933a # v4.4.3 | |
| - name: Run static analysis | |
| run: ./gradlew ktlintCheck checkstyle apiCheck lint | |
| # REQUIRED. Verifies that every external type in each published module's public | |
| # API surface is resolvable on the compile classpath a downstream consumer | |
| # assembles from the published artifact. A failure means a dependency supplying | |
| # a public-API type is scoped `implementation` (runtime) but must be `api` | |
| # (compile). Runs in parallel with the other gates. | |
| scope-check: | |
| runs-on: ubuntu-latest | |
| # Only needs read access; the workflow-level `checks: write` (for the | |
| # test-report annotator) is not required here. | |
| permissions: | |
| contents: read | |
| steps: | |
| - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 | |
| - name: Setup Java | |
| uses: actions/setup-java@b6effb05e454b25005698d916606bdc6ffcbf961 # v5 | |
| with: | |
| java-version: '17' | |
| distribution: 'corretto' | |
| - name: Setup Gradle | |
| uses: gradle/actions/setup-gradle@ed408507eac070d1f99cc633dbcf757c94c7933a # v4.4.3 | |
| - name: Verify API scopes | |
| run: scripts/verify_api_scopes.sh |