name: Build and test

on:
  pull_request:
  push:
    branches:
      - 'main'

jobs:
  build_and_test_with_code_coverage:
    name: Build and test
    runs-on: ${{ matrix.os }}
    strategy:
      # We need multiple builds to run even if the 1st one is failing, because
      # test failures may be OS-specific (or the tests themselves flaky).
      fail-fast: false
      matrix:
        os: [ ubuntu-latest, macos-latest, windows-latest ]

    # A possible workaround for <https://github.com/dorny/test-reporter/issues/168>.
    permissions:
      checks: write
      contents: write
      pull-requests: write
      statuses: write

    steps:
      - uses: actions/checkout@v4
      - name: Set up JDK 11
        uses: actions/setup-java@v4
        with:
          java-version: 11
          distribution: temurin
      - name: Retrieve Kotlin version
        shell: bash
        run: |
          kv=$(cat gradle/libs.versions.toml | grep '^kotlin =' | awk -F'[=]' '{print $2}' | tr -d '" ')
          echo KOTLIN_VERSION=$kv >> $GITHUB_ENV
      - name: Cache konan
        uses: actions/cache@v4
        with:
          # [@actions/glob](https://github.com/actions/toolkit/tree/main/packages/glob) is used to match paths
          # It should correctly expand `~` on every OS.
          path: ~/.konan
          key: ${{ runner.os }}-gradle-konan-${{ env.KOTLIN_VERSION }}
      - uses: gradle/gradle-build-action@v3
        with:
          gradle-version: wrapper
          # The `--continue` flag is necessary so that Gradle keeps going after the 1st test failure.
          # By default, when test for all MPP targets are executed, Kotlin Gradle Plugin generates a single aggregated HTML report.
          # Property `kotlin.tests.individualTaskReports` enables individual Junit-style XML reports.
          # See org.jetbrains.kotlin.gradle.testing.internal.KotlinTestReport.
          arguments: |
            build
            --continue
            -x detekt
            -Pkotlin.tests.individualTaskReports=true
            -Porg.gradle.caching=true
            -Pdetekt.multiplatform.disabled=true
            -PdisableRedundantTargets=true
            -PenabledExecutables=debug
            -PgprUser=${{ github.actor }}
            -PgprKey=${{ secrets.GITHUB_TOKEN }}

        # This step needs a Git repository, so it's impossible to extract it
        # into a separate job (or, otherwise, we'd need to upload the content
        # of the whole `.git` folder as an artifact).
      - name: JUnit Tests (dorny/test-reporter@v1)
        uses: dorny/test-reporter@v1
        if: ${{ always() }}
        with:
          name: JUnit Tests (${{ runner.os }}, dorny/test-reporter@v1)
          # Comma-separated values.
          path: "**/build/test-results/*/TEST-*.xml"
          reporter: java-junit
        # Ignore the "Resource not accessible by integration" error when a PR
        # originates from a non-collaborator. This is
        # <https://github.com/dorny/test-reporter/issues/168> which may be
        # potentially fixed with <https://github.com/dorny/test-reporter/pull/174>.
        continue-on-error: true

      - name: Upload test results
        uses: actions/upload-artifact@v4
        if: ${{ always() }}
        with:
          name: xml-test-reports-${{ runner.os }}
          path: |
            **/build/test-results/*/TEST-*.xml
          retention-days: 1

      - name: Upload gradle reports
        if: ${{ always() }}
        uses: actions/upload-artifact@v4
        with:
          name: gradle-reports-${{ matrix.os }}
          path: '**/build/reports/'
      - name: Code coverage report
        if: ${{ runner.os == 'Linux' }}
        uses: codecov/codecov-action@v4
        with:
          flags: unittests
          fail_ci_if_error: false # optional (default = false)

  report:
    name: Publish JUnit test results
    if: ${{ always() }}
    needs: build_and_test_with_code_coverage
    runs-on: ${{ matrix.os }}

    strategy:
      matrix:
        os: [ ubuntu-latest, macos-latest, windows-latest ]

    permissions:
      checks: write
      pull-requests: write

    steps:
      - uses: actions/download-artifact@v4
        if: ${{ always() }}
        with:
          name: xml-test-reports-${{ runner.os }}

        # Uses Docker, that's why Linux-only.
      - name: JUnit Tests (EnricoMi/publish-unit-test-result-action@v1, Linux)
        uses: EnricoMi/publish-unit-test-result-action@v2
        if: ${{ runner.os == 'Linux' }}
        with:
          check_name: JUnit Tests (${{ runner.os }}, EnricoMi/publish-unit-test-result-action@v1)
          files: |
            **/build/test-results/*/TEST-*.xml

      - name: JUnit Tests (EnricoMi/publish-unit-test-result-action@v1, Windows or Mac OS X)
        uses: EnricoMi/publish-unit-test-result-action/composite@v2
        if: ${{ runner.os == 'Windows' || runner.os == 'macOS' }}
        with:
          check_name: JUnit Tests (${{ runner.os }}, EnricoMi/publish-unit-test-result-action@v1)
          files: |
            **/build/test-results/*/TEST-*.xml
