name: Development

on:
  workflow_call:
    inputs:
      php:
        required: true
        type: string
      mysql:
        required: true
        type: string
      template_engine:
        type: string
        default: 'both'
      module_codecept_test_group:
        type: string
        default: 'gdproptin_module'
      report_sonarcloud:
        type: boolean
        default: false
      report_slack:
        type: boolean
        default: true

  workflow_dispatch:
    inputs:
      php:
        description: 'PHP version'
        required: true
        default: '8.0'
        type: choice
        options:
          - '8.0'
          - '8.1'
      mysql:
        description: 'MySQL version'
        required: true
        default: '5.7.37'
        type: choice
        options:
          - '5.7.37'
          - '8.0'
      template_engine:
        description: 'Template engine - smarty with flow theme, twig with twig or apex theme'
        required: true
        default: 'twig-apex'
        type: choice
        options:
          - 'both'
          - 'twig-apex'
          - 'twig-twig'
          - 'smarty'
      module_codecept_test_group:
        description: 'Module codeception test group'
        required: true
        default: 'gdproptin_module'
        type: string
      report_sonarcloud:
        description: 'Trigger sonarcloud analize?'
        required: true
        default: true
        type: boolean
      report_slack:
        description: 'Trigger slack notification?'
        required: true
        default: true
        type: boolean

env:
  PACKAGE_NAME: 'oxid-esales/gdpr-optin-module'
  MODULE_ID: 'oegdproptin'
  SONARCLOUD_ORGANIZATION: 'oxid-esales'
  SONARCLOUD_PROJECT_KEY: 'OXID-eSales_gdpr-optin-module'

jobs:
  install_shop_with_module:
    runs-on: ubuntu-latest
    steps:
      - name: Print run parameters
        run: |
          echo "Running job with:\
            PHP version: ${{ inputs.php }}\
            MySQL version: ${{ inputs.mysql }}\
            Template engine: ${{ inputs.template_engine }}\
            Tests group: ${{ inputs.module_codecept_test_group }}\
            Trigger event: ${{ github.event_name }}"

      - name: Clone testing environment
        run: git clone https://github.com/OXID-eSales/docker-eshop-sdk.git .

      - name: Clone the shop
        run: git clone --depth 1 https://github.com/OXID-eSales/oxideshop_ce.git --branch b-7.0.x --single-branch source

      - name: Cache current installation
        uses: actions/cache@v3
        with:
          path: |
            ./*
          key: installation-${{ join(inputs, '-') }}-${{ github.run_number }}-${{ github.run_attempt }}

      - name: Prepare container configuration
        run: |
          make setup
          make addbasicservices
          make file=services/selenium-chrome.yml addservice

          perl -pi\
            -e 's#PHP_VERSION=.*#PHP_VERSION=${{ inputs.php }}#g;'\
            -e "s#MYSQL_VERSION=.*#MYSQL_VERSION=${{ inputs.mysql }}#g;"\
            .env

          perl -pi\
            -e 's#display_errors =.*#display_errors = false#g;'\
            -e 's#error_reporting = .*#error_reporting = E_ALL ^ E_WARNING ^ E_DEPRECATED#g;'\
            -e 'print "xdebug.max_nesting_level=1000\nxdebug.mode=coverage\n\n"'\
            containers/php/custom.ini

          perl -pi\
            -e 's#/var/www/#/var/www/source/#g;'\
            containers/httpd/project.conf

      - name: Prepare shop configuration
        run: |
          cp source/source/config.inc.php.dist source/source/config.inc.php
          sed -i "1s+^+SetEnvIf Authorization "\(.*\)" HTTP_AUTHORIZATION=\$1\n\n+" source/source/.htaccess
          sed -i -e 's/<dbHost>/mysql/'\
                 -e 's/<dbUser>/root/'\
                 -e 's/<dbName>/example/'\
                 -e 's/<dbPwd>/root/'\
                 -e 's/<dbPort>/3306/'\
                 -e 's/<sShopURL>/http:\/\/localhost.local\//'\
                 -e 's/<sShopDir>/\/var\/www\/source\//'\
                 -e 's/<sCompileDir>/\/var\/www\/source\/tmp\//'\
              source/source/config.inc.php

      - name: Checkout current module
        uses: actions/checkout@v3
        with:
          path: source/test-module

      - name: Start containers
        run: |
          make up
          sleep 2

      - name: Install module
        run: |
          docker-compose exec -T \
            php composer config repositories.${{ env.PACKAGE_NAME }} \
            --json '{"type":"path", "url":"./test-module", "options": {"symlink": true}}'
          docker-compose exec -T \
            php composer require ${{ env.PACKAGE_NAME }}:* --no-interaction --no-update

      - name: Install dependencies and reset shop
        run: |
          docker-compose exec -T php composer update --no-interaction
          docker-compose exec -T php bin/oe-console oe:database:reset \
            --db-host=mysql --db-port=3306 --db-name=example --db-user=root --db-password=root --force
          docker-compose exec -T php bin/oe-console oe:module:activate ${{ env.MODULE_ID }}

      - name: Stop containers
        run: |
          docker-compose down
          sleep 2

      - name: Show docker log
        if: always()
        run: |
          docker-compose logs

      - name: Upload configuration artifacts
        if: always()
        uses: actions/upload-artifact@v3
        with:
          name: Configs-${{ inputs.php }}-${{ inputs.mysql }}-${{ inputs.template_engine }}
          path: |
            docker-compose.yml
            source/composer.json
            source/composer.lock
            source/source/config.inc.php

  styles:
    needs: [ install_shop_with_module ]
    runs-on: ubuntu-latest
    steps:
      - name: Load current installation from cache
        uses: actions/cache@v3
        with:
          path: |
            ./*
          key: installation-${{ join(inputs, '-') }}-${{ github.run_number }}-${{ github.run_attempt }}
          restore-keys: |
            installation-${{ join(inputs, '-') }}-${{ github.run_number }}-${{ github.run_attempt }}

      - name: Start containers
        run: |
          make up
          sleep 2

      - name: Install module dependencies
        run: |
          docker-compose exec -T \
            --workdir=/var/www/test-module \
            php composer install

      - name: Run phpcs
        if: always()
        run: |
          docker-compose exec -T \
            --workdir=/var/www/test-module \
            php composer phpcs

      - name: Run phpstan scan and show results
        id: phpstan
        if: always()
        run: |
          docker-compose exec -T \
            --workdir=/var/www/test-module \
            php composer phpstan

      - name: Run phpstan scan and generate report for further processing
        if: always()
        run: |
          docker-compose exec -T \
            --workdir=/var/www/test-module \
            php composer phpstan-report

      - name: Stop containers
        if: always()
        run: |
          make down
          sleep 2

      - name: Upload log artifact
        if: always()
        uses: actions/upload-artifact@v3
        with:
          name: StylesLog-${{ inputs.php }}
          path: |
            source/test-module/phpstan.report.json
            source/test-module/phpmd.report.json

  integration_tests:
    needs: [ install_shop_with_module ]
    runs-on: ubuntu-latest
    steps:
      - name: Load current installation from cache
        uses: actions/cache@v3
        with:
          path: |
            ./*
          key: installation-${{ join(inputs, '-') }}-${{ github.run_number }}-${{ github.run_attempt }}
          restore-keys: |
            installation-${{ join(inputs, '-') }}-${{ github.run_number }}-${{ github.run_attempt }}

      - name: Start containers
        run: |
          make up
          sleep 2

      - name: Run tests
        run: |
          docker-compose exec -T \
            -e XDEBUG_MODE=coverage \
            php php vendor/bin/phpunit \
              -c /var/www/vendor/${{ env.PACKAGE_NAME }}/tests/phpunit.xml \
              --testsuite=Integration \
              --bootstrap=/var/www/source/bootstrap.php \
              --coverage-php=/var/www/integration.cov \
              --coverage-text

      - name: Upload log artifact
        if: always()
        uses: actions/upload-artifact@v3
        with:
          name: ModuleIntegrationTestsLog-${{ inputs.php }}-${{ inputs.mysql }}-${{ inputs.template_engine }}
          path: |
            source/integration.cov
            source/source/log/oxideshop.log
            data/php/logs/error_log.txt

      - name: Stop containers
        if: always()
        run: |
          docker-compose down
          sleep 2

  unit_tests:
    needs: [ install_shop_with_module ]
    runs-on: ubuntu-latest
    steps:
      - name: Load current installation from cache
        uses: actions/cache@v3
        with:
          path: |
            ./*
          key: installation-${{ join(inputs, '-') }}-${{ github.run_number }}-${{ github.run_attempt }}
          restore-keys: |
            installation-${{ join(inputs, '-') }}-${{ github.run_number }}-${{ github.run_attempt }}

      - name: Start containers
        run: |
          make up
          sleep 2

      - name: Run tests
        run: |
          docker-compose exec -T \
            -e XDEBUG_MODE=coverage \
            php php vendor/bin/phpunit \
              -c /var/www/vendor/${{ env.PACKAGE_NAME }}/tests/phpunit.xml \
              --testsuite=Unit \
              --coverage-php=/var/www/unit.cov \
              --coverage-text

      - name: Upload log artifact
        if: always()
        uses: actions/upload-artifact@v3
        with:
          name: ModuleUnitTestsLog-${{ inputs.php }}-${{ inputs.mysql }}-${{ inputs.template_engine }}
          path: |
            source/unit.cov
            source/source/log/oxideshop.log
            data/php/logs/error_log.txt

      - name: Stop containers
        if: always()
        run: |
          docker-compose down
          sleep 2

  codeception_twig:
    needs: [ install_shop_with_module ]
    if: ${{ inputs.template_engine == 'both' || inputs.template_engine == 'twig-twig' || inputs.template_engine == 'twig-apex' }}
    runs-on: ubuntu-latest
    steps:
      - name: Load current installation from cache
        uses: actions/cache@v3
        with:
          path: |
            ./*
          key: installation-${{ join(inputs, '-') }}-${{ github.run_number }}-${{ github.run_attempt }}
          restore-keys: |
            installation-${{ join(inputs, '-') }}-${{ github.run_number }}-${{ github.run_attempt }}

      - name: Start containers
        run: |
          make up
          sleep 2

      - name: Set Github dependencies
        run: |
          docker-compose run -T --rm php composer config github-protocols https
          docker-compose run -T --rm php composer config -g github-oauth.github.com ${{ secrets.GH_CI_JENKINS_TOKEN }}

      - name: Install twig template engine with twig and apex theme
        run: |
          docker-compose exec -T php composer require oxid-esales/twig-component:dev-b-7.0.x --no-update
          docker-compose exec -T php composer require oxid-esales/twig-admin-theme:dev-b-7.0.x --no-update
          docker-compose exec -T php composer require oxid-esales/twig-theme:dev-b-7.0.x --no-update
          docker-compose exec -T \
          php composer config repositories.oxid-esales/apex-theme \
            --json '{"type":"git", "url":"https://github.com/OXID-eSales/apex-theme.git"}'
          docker-compose exec -T php composer require oxid-esales/apex-theme:dev-main --no-update
          docker-compose exec -T php composer update --no-interaction

      - name: Reconfigure codeception for apex theme
        if: ${{ inputs.template_engine == 'both' || inputs.template_engine == 'twig-apex' }}
        run: |
          perl -pi \
          -e 's#views/twig#views/apex#g;' \
          source/test-module/tests/Codeception/acceptance.suite.yml

      - name: Run tests with apex theme
        if: ${{ inputs.template_engine == 'both' || inputs.template_engine == 'twig-apex' }}
        run: |
          docker-compose exec -T \
            -e SELENIUM_SERVER_HOST=selenium \
            -e BROWSER_NAME=chrome \
            -e THEME_ID=apex \
            -e MODULE_IDS=${{ env.MODULE_ID }} \
            php vendor/bin/codecept run acceptance \
                -c /var/www/vendor/${{ env.PACKAGE_NAME }}/tests/codeception.yml -g ${{ inputs.module_codecept_test_group }}

      - name: Install codeception-page-objects for twig theme
        if: ${{ inputs.template_engine == 'both' || inputs.template_engine == 'twig-twig' }}
        run: |
          docker-compose exec -T php composer require oxid-esales/codeception-page-objects:dev-b-7.0.x-twig-theme --no-update
          docker-compose exec -T php composer require oxid-esales/codeception-modules:dev-b-7.0.x-twig-theme --no-update
          docker-compose exec -T php composer update --no-interaction

      - name: Reconfigure codeception for twig theme
        if: ${{ inputs.template_engine == 'both' || inputs.template_engine == 'twig-twig' }}
        run: |
          perl -pi \
          -e 's#views/apex#views/twig#g;' \
          source/test-module/tests/Codeception/acceptance.suite.yml

      - name: Run tests with twig theme
        if: ${{ inputs.template_engine == 'both' || inputs.template_engine == 'twig-twig' }}
        run: |
          docker-compose exec -T \
            -e SELENIUM_SERVER_HOST=selenium \
            -e BROWSER_NAME=chrome \
            -e THEME_ID=twig \
            -e MODULE_IDS=${{ env.MODULE_ID }} \
            php vendor/bin/codecept run acceptance \
                -c /var/www/vendor/${{ env.PACKAGE_NAME }}/tests/codeception.yml -g ${{ inputs.module_codecept_test_group }}

      - name: Upload log artifact
        if: always()
        uses: actions/upload-artifact@v3
        with:
          name: ModuleCodeceptionTestsLog-${{ inputs.php }}-${{ inputs.mysql }}-${{ inputs.template_engine }}
          path: |
            docker-compose.yml
            source/composer.json
            source/composer.lock
            source/source/config.inc.php
            source/source/log/oxideshop.log
            data/php/logs/error_log.txt
            source/tests/Codeception/_output

      - name: Stop containers
        if: always()
        run: |
          make down
          sleep 2

  codeception_smarty:
    needs: [ install_shop_with_module ]
    if: ${{ inputs.template_engine == 'both' || inputs.template_engine == 'smarty' }}
    runs-on: ubuntu-latest
    steps:
      - name: Load current installation from cache
        uses: actions/cache@v3
        with:
          path: |
            ./*
          key: installation-${{ join(inputs, '-') }}-${{ github.run_number }}-${{ github.run_attempt }}
          restore-keys: |
            installation-${{ join(inputs, '-') }}-${{ github.run_number }}-${{ github.run_attempt }}

      - name: Reconfigure codeception for smarty themes
        run: |
          perl -pi \
          -e 's#admin_twig#admin_smarty#g;' \
          source/test-module/tests/Codeception/acceptance.suite.yml
          perl -pi \
          -e 's#views/twig#views/flow/translations#g;' \
          source/test-module/tests/Codeception/acceptance.suite.yml
          perl -pi \
          -e 's#views/apex#views/flow/translations#g;' \
          source/test-module/tests/Codeception/acceptance.suite.yml

      - name: Start containers
        run: |
          make up
          sleep 2

      - name: Install codeception-page-objects for twig theme
        run: |
          docker-compose exec -T php composer require oxid-esales/codeception-page-objects:dev-b-7.0.x-twig-theme --no-update
          docker-compose exec -T php composer require oxid-esales/codeception-modules:dev-b-7.0.x-twig-theme --no-update
          docker-compose exec -T php composer update --no-interaction

      - name: Install smarty template engine and flow theme
        run: |
          docker-compose exec -T php composer require oxid-esales/smarty-component:dev-b-7.0.x --no-update
          docker-compose exec -T php composer require oxid-esales/smarty-admin-theme:dev-b-7.0.x --no-update
          docker-compose exec -T php composer require oxid-esales/flow-theme:dev-b-7.0.x --no-update
          docker-compose exec -T php composer update --no-interaction

      - name: Run tests
        run: |
          docker-compose exec -T \
            -e SELENIUM_SERVER_HOST=selenium \
            -e BROWSER_NAME=chrome \
            -e THEME_ID=flow \
            -e MODULE_IDS=${{ env.MODULE_ID }} \
            php vendor/bin/codecept run acceptance \
                -c /var/www/vendor/${{ env.PACKAGE_NAME }}/tests/codeception.yml -g ${{ inputs.module_codecept_test_group }}

      - name: Upload log artifact
        if: always()
        uses: actions/upload-artifact@v3
        with:
          name: sModuleCodeceptionTestsLog-${{ inputs.php }}-${{ inputs.mysql }}-${{ inputs.template_engine }}
          path: |
            docker-compose.yml
            source/composer.json
            source/composer.lock
            source/source/config.inc.php
            source/source/log/oxideshop.log
            data/php/logs/error_log.txt
            source/tests/Codeception/_output

      - name: Stop containers
        if: always()
        run: |
          make down
          sleep 2

  prepare_coverage_results:
    needs: [ unit_tests, integration_tests ]
    if: ${{ always() && inputs.report_sonarcloud }}
    runs-on: ubuntu-latest
    steps:
      - name: Load current installation from cache
        uses: actions/cache@v3
        with:
          path: |
            ./*
          key: installation-${{ join(inputs, '-') }}-${{ github.run_number }}-${{ github.run_attempt }}
          restore-keys: |
            installation-${{ join(inputs, '-') }}-${{ github.run_number }}-${{ github.run_attempt }}

      - name: Download unit artifacts
        uses: actions/download-artifact@v3
        with:
          name: ModuleUnitTestsLog-${{ inputs.php }}-${{ inputs.mysql }}-${{ inputs.template_engine }}
          path: ./source/coverage/

      - name: Download integration artifacts
        uses: actions/download-artifact@v3
        with:
          name: ModuleIntegrationTestsLog-${{ inputs.php }}-${{ inputs.mysql }}-${{ inputs.template_engine }}
          path: ./source/coverage/

      - name: Start containers
        run: |
          make up
          sleep 2

      - name: Collect and merge coverage reports
        continue-on-error: true
        run: |
          ls -alh source/coverage
          wget https://phar.phpunit.de/phpcov.phar
          mv phpcov.phar source/phpcov.phar
          docker-compose exec -T php php phpcov.phar merge --clover coverage.xml ./coverage
          sed -i 's+/var/www/test-module/+./+' source/coverage.xml

      - name: Upload log artifact
        uses: actions/upload-artifact@v3
        with:
          name: TestsLog-${{ inputs.php }}-${{ inputs.mysql }}
          path: source/coverage.xml

  sonarcloud:
    needs: [ prepare_coverage_results ]
    if: ${{ always() && inputs.report_sonarcloud }}
    runs-on: ubuntu-latest
    steps:
      - name: Checkout current module
        uses: actions/checkout@v3

      - name: Download TestsLog artifacts
        continue-on-error: true
        uses: actions/download-artifact@v3
        with:
          name: TestsLog-${{ inputs.php }}-${{ inputs.mysql }}
          path: ./tests/

      - name: SonarCloud Scan
        uses: sonarsource/sonarcloud-github-action@master
        env:
          SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
        with:
          args: >
            -Dsonar.organization=${{ env.SONARCLOUD_ORGANIZATION }}
            -Dsonar.projectKey=${{ env.SONARCLOUD_PROJECT_KEY }}
            -Dsonar.sources=src
            -Dsonar.tests=tests
            -Dsonar.sourceEncoding=UTF-8
            -Dsonar.php.coverage.reportPaths=tests/coverage.xml
            -Dsonar.cpd.php.minimumTokens=25
            -Dsonar.cpd.php.minimumLines=5

  notify_slack:
    needs: [ unit_tests, integration_tests, codeception_twig, codeception_smarty, styles ]
    runs-on: ubuntu-latest
    if: ${{ always() && inputs.report_slack }}
    steps:
      - name: Send custom JSON data to Slack workflow
        uses: slackapi/slack-github-action@v1.23.0
        with:
          payload: >
            { "text": "
            ${{ github.event_name == 'workflow_dispatch' && 'Manual run of' || 'Scheduled run of' }} ${{ github.workflow }} on ${{ github.repository }} by ${{ github.actor }}
            ${{ needs.unit_tests.result=='success' && needs.integration_tests.result=='success' && ((inputs.template_engine=='twig_apex' && needs.codeception_twig.result=='success') || (inputs.template_engine=='twig_twig' && needs.codeception_twig.result=='success') || (inputs.template_engine=='smarty' && needs.codeception_smarty.result=='success') || (inputs.template_engine=='both' && needs.codeception_twig.result=='success' && needs.codeception_smarty.result=='success')) && 'Successful' || 'Failed' }}
            ", "blocks": [ { "type": "header","text": { "type": "plain_text", "emoji": true, "text": "
            ${{ github.event_name == 'workflow_dispatch' && 'Manual run of' || 'Scheduled' }} ${{ github.workflow }} on ${{ github.repository }} by ${{ github.actor }}
            " } },{ "type": "section","fields": [ { "type": "mrkdwn","text": "
            *Status:* ${{ needs.unit_tests.result=='success' && needs.integration_tests.result=='success' && ((inputs.template_engine=='twig_apex' && needs.codeception_twig.result=='success') || (inputs.template_engine=='twig_twig' && needs.codeception_twig.result=='success') || (inputs.template_engine=='smarty' && needs.codeception_smarty.result=='success') || (inputs.template_engine=='both' && needs.codeception_twig.result=='success' && needs.codeception_smarty.result=='success')) && ':white_check_mark:' || ':x:' }}
            " },{ "type": "mrkdwn","text": "
            Repository: <${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}|${{ github.repository }}/actions/runs/${{ github.run_id }}>
            " } ] },{ "type": "section", "text": { "type": "mrkdwn", "text": "
            \n* Module Unit ${{ (needs.unit_tests.result=='success') && ':white_check_mark:' || ':x:' }}
            \n* Module Integration ${{ (needs.integration_tests.result=='success') && ':white_check_mark:' || ':x:' }}
            \n* Module Codeception with Smarty ${{ ((inputs.template_engine=='smarty' && needs.codeception_smarty.result=='success') || (inputs.template_engine=='both' && needs.codeception_smarty.result=='success')) && ':white_check_mark:' || ':x:' }}
            \n* Module Codeception with Twig ${{ ((inputs.template_engine=='twig-apex' && needs.codeception_twig.result=='success') || (inputs.template_engine=='twig-twig' && needs.codeception_twig.result=='success') || (inputs.template_engine=='both' && needs.codeception_twig.result=='success')) && ':white_check_mark:' || ':x:' }}
            \n* Module Styles ${{ (needs.styles.result=='success') && ':white_check_mark:' || ':x:' }}
            " } }, { "type": "divider" } ] }
        env:
          SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }}
          SLACK_WEBHOOK_TYPE: INCOMING_WEBHOOK
