name: CI
on: [push, pull_request]

jobs:
  tests:
    name: PHP ${{ matrix.php }}

    runs-on: ubuntu-latest
    timeout-minutes: 5
    strategy:
      matrix:
        php: ["8.1", "8.2", "8.3"]
    env:
      extensions: mbstring, pcov
      ini: pcov.directory=., "pcov.exclude=\"~(vendor|tests)~\""

    steps:
      - name: Checkout
        uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 # pin@v3

      - name: Setup PHP cache environment
        id: ext-cache
        uses: shivammathur/cache-extensions@d622719c5f9eb1f119bee963028d0c0b984525c5 # pin@v1
        with:
          php-version: ${{ matrix.php }}
          extensions: ${{ env.extensions }}
          key: php-v1

      - name: Cache PHP extensions
        uses: actions/cache@704facf57e6136b1bc63b828d79edcd491f0ee84 # pin@v3
        with:
          path: ${{ steps.ext-cache.outputs.dir }}
          key: ${{ steps.ext-cache.outputs.key }}
          restore-keys: ${{ steps.ext-cache.outputs.key }}

      - name: Setup PHP environment
        uses: shivammathur/setup-php@e6f75134d35752277f093989e72e140eaa222f35 # pin@v2
        with:
          php-version: ${{ matrix.php }}
          extensions: ${{ env.extensions }}
          ini-values: ${{ env.ini }}
          coverage: pcov
          tools: phpunit:9.5.13, psalm:4.11.2

      - name: Setup problem matchers
        run: |
          echo "::add-matcher::${{ runner.tool_cache }}/php.json"
          echo "::add-matcher::${{ runner.tool_cache }}/phpunit.json"

      - name: Get Composer cache directory
        id: composerCache
        run: echo "::set-output name=dir::$(composer config cache-files-dir)"

      - name: Cache dependencies
        uses: actions/cache@704facf57e6136b1bc63b828d79edcd491f0ee84 # pin@v3
        with:
          path: ${{ steps.composerCache.outputs.dir }}
          key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.lock') }}
          restore-keys: ${{ runner.os }}-composer-

      - name: Install dependencies
        run: composer install --prefer-dist

      - name: Cache analysis data
        id: finishPrepare
        uses: actions/cache@704facf57e6136b1bc63b828d79edcd491f0ee84 # pin@v3
        with:
          path: ~/.cache/psalm
          key: backend-analysis-${{ matrix.php }}-v2

      - name: Run tests
        if: always() && steps.finishPrepare.outcome == 'success'
        run: phpunit --coverage-clover ${{ github.workspace }}/clover.xml
      # - name: Statically analyze using Psalm
      #   if: always() && steps.finishPrepare.outcome == 'success'
      #   run: psalm --output-format=github --php-version=${{ matrix.php }}

      # - name: Upload coverage results to Codecov
      #   uses: codecov/codecov-action@66b3de25f6f91f65eb92c514d31d6b6f13d5ab18 # pin@v3
      #   with:
      #     file: ${{ github.workspace }}/clover.xml
      #     flags: backend
      #     env_vars: PHP
      #   env:
      #     PHP: ${{ matrix.php }}

  analysis:
    name: Analysis

    runs-on: ubuntu-latest
    timeout-minutes: 5
    env:
      php: "8.1"
      extensions: mbstring

    steps:
      - name: Checkout
        uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 # pin@v3

      - name: Setup PHP cache environment
        id: ext-cache
        uses: shivammathur/cache-extensions@d622719c5f9eb1f119bee963028d0c0b984525c5 # pin@v1
        with:
          php-version: ${{ env.php }}
          extensions: ${{ env.extensions }}
          key: php-v1

      - name: Cache PHP extensions
        uses: actions/cache@704facf57e6136b1bc63b828d79edcd491f0ee84 # pin@v3
        with:
          path: ${{ steps.ext-cache.outputs.dir }}
          key: ${{ steps.ext-cache.outputs.key }}
          restore-keys: ${{ steps.ext-cache.outputs.key }}

      - name: Setup PHP environment
        id: finishPrepare
        uses: shivammathur/setup-php@e6f75134d35752277f093989e72e140eaa222f35 # pin@v2
        with:
          php-version: ${{ env.php }}
          extensions: ${{ env.extensions }}
          coverage: none
          tools: |
            composer:2.3.7, composer-normalize:2.28.0,
            composer-unused:0.7.12, phpcpd:6.0.3, phpmd:2.12.0

      - name: Validate composer.json/composer.lock
        if: always() && steps.finishPrepare.outcome == 'success'
        run: composer validate --strict --no-check-version --no-check-all

      - name: Ensure that composer.json is normalized
        if: always() && steps.finishPrepare.outcome == 'success'
        run: composer-normalize --dry-run

      - name: Get Composer cache directory
        id: composerCache1
        if: always() && steps.finishPrepare.outcome == 'success'
        run: echo "::set-output name=dir::$(composer config cache-files-dir)"

      - name: Cache dependencies
        id: composerCache2
        if: always() && steps.composerCache1.outcome == 'success'
        uses: actions/cache@704facf57e6136b1bc63b828d79edcd491f0ee84 # pin@v3
        with:
          path: ${{ steps.composerCache1.outputs.dir }}
          key: ${{ runner.os }}-composer-locked-${{ hashFiles('**/composer.lock') }}
          restore-keys: ${{ runner.os }}-composer-locked-

      - name: Install dependencies
        id: composerInstall
        if: always() && steps.composerCache2.outcome == 'success'
        run: composer install --prefer-dist

      # - name: Check for unused Composer dependencies
      #   if: always() && steps.composerInstall.outcome == 'success'
      #   run: composer-unused --no-progress

      - name: Check for duplicated code
        if: always() && steps.composerInstall.outcome == 'success'
        run: phpcpd --fuzzy --exclude tests --exclude vendor .

      - name: Statically analyze using PHPMD
        if: always() && steps.composerInstall.outcome == 'success'
        run: phpmd . github phpmd.xml.dist --exclude 'tests/*,vendor/*,_templates/*'

  coding-style:
    name: Coding Style

    runs-on: ubuntu-latest
    timeout-minutes: 5

    steps:
      - name: Checkout
        uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 # pin@v3

      - name: Setup PHP environment
        uses: shivammathur/setup-php@e6f75134d35752277f093989e72e140eaa222f35 # pin@v2
        with:
          coverage: none
          tools: php-cs-fixer:3.49.0

      - name: Cache analysis data
        id: finishPrepare
        uses: actions/cache@704facf57e6136b1bc63b828d79edcd491f0ee84 # pin@v3
        with:
          path: ~/.php-cs-fixer
          key: coding-style

      - name: Check for PHP coding style violations
        if: always() && steps.finishPrepare.outcome == 'success'
        env:
          PHP_CS_FIXER_IGNORE_ENV: 1
        # Use the --dry-run flag in push builds to get a failed CI status
        run: >
          php-cs-fixer fix --diff ${{ github.event_name != 'pull_request' && '--dry-run' || '' }}

      - name: Create code suggestions from the coding style changes (on PR only)
        if: >
          always() && steps.finishPrepare.outcome == 'success' && github.event_name == 'pull_request'
        uses: reviewdog/action-suggester@94877e550e6b522dc1d21231974b645ff2f084ce # pin@v1
        with:
          tool_name: PHP-CS-Fixer
          fail_on_error: "true"
