name: Nightly
on:
  schedule:
   - cron: "0 1 * * *"
  workflow_dispatch: ~
jobs:
  GENERATE_MATRIX:
    name: Generate Matrix
    if: github.repository_owner == 'php' || github.event_name == 'workflow_dispatch'
    runs-on: ubuntu-latest
    outputs:
      branches: ${{ steps.set-matrix.outputs.branches }}
      matrix-include: ${{ steps.set-matrix.outputs.matrix-include }}
    steps:
      - uses: actions/checkout@v3
        with:
          # Set fetch-depth to 0 to clone the full repository
          # including all branches. This is required to find
          # the correct commit hashes.
          fetch-depth: 0
      - name: Grab the commit mapping
        uses: actions/cache@v3
        with:
          path: branch-commit-cache.json
          # The cache key needs to change every time for the
          # cache to be updated after this job finishes.
          key: nightly-${{ github.run_id }}-${{ github.run_attempt }}
          restore-keys: |
            nightly-
      - name: Generate Matrix
        id: set-matrix
        run: php .github/nightly_matrix.php "${{ github.event_name }}" "${{ github.run_attempt }}"
  LINUX_X64:
    needs: GENERATE_MATRIX
    if: ${{ needs.GENERATE_MATRIX.outputs.branches != '[]' }}
    strategy:
      fail-fast: false
      matrix:
        branch: ${{ fromJson(needs.GENERATE_MATRIX.outputs.branches) }}
        configuration_parameters: ['']
        debug: [true, false]
        name: ['']
        run_tests_parameters: ['']
        test_function_jit: [true]
        zts: [true, false]
        include: ${{ fromJson(needs.GENERATE_MATRIX.outputs.matrix-include) }}
    name: "${{ matrix.branch.name }}_LINUX_X64${{ matrix.name }}_${{ matrix.debug && 'DEBUG' || 'RELEASE' }}_${{ matrix.zts && 'ZTS' || 'NTS' }}"
    runs-on: ubuntu-20.04
    steps:
      - name: git checkout
        uses: actions/checkout@v3
        with:
          ref: ${{ matrix.branch.ref }}
      - name: Create MSSQL container
        uses: ./.github/actions/setup-mssql
      - name: Create Oracle container
        uses: ./.github/actions/setup-oracle
      - name: apt
        uses: ./.github/actions/apt-x64
      - name: ./configure
        uses: ./.github/actions/configure-x64
        with:
          configurationParameters: >-
            ${{ matrix.configuration_parameters }}
            --${{ matrix.debug && 'enable' || 'disable' }}-debug
            --${{ matrix.zts && 'enable' || 'disable' }}-zts
      - name: make
        run: make -j$(/usr/bin/nproc) >/dev/null
      - name: make install
        uses: ./.github/actions/install-linux
      - name: Setup
        uses: ./.github/actions/setup-x64
      - name: Test
        uses: ./.github/actions/test-linux
        with:
          runTestsParameters: >-
            ${{ matrix.run_tests_parameters }}
      - name: Test Tracing JIT
        uses: ./.github/actions/test-linux
        with:
          runTestsParameters: >-
            ${{ matrix.run_tests_parameters }}
            -d zend_extension=opcache.so
            -d opcache.enable_cli=1
            -d opcache.jit_buffer_size=16M
      - name: Test OpCache
        uses: ./.github/actions/test-linux
        with:
          runTestsParameters: >-
            ${{ matrix.run_tests_parameters }}
            -d zend_extension=opcache.so
            -d opcache.enable_cli=1
      - name: Test Function JIT
        # ASAN frequently timeouts. Each test run takes ~90 minutes, we can
        # avoid running into the 6 hour timeout by skipping the function JIT.
        if: matrix.test_function_jit
        uses: ./.github/actions/test-linux
        with:
          runTestsParameters: >-
            ${{ matrix.run_tests_parameters }}
            -d zend_extension=opcache.so
            -d opcache.enable_cli=1
            -d opcache.jit_buffer_size=16M
            -d opcache.jit=1205
      - name: Verify generated files are up to date
        uses: ./.github/actions/verify-generated-files
  LINUX_X32:
    needs: GENERATE_MATRIX
    if: ${{ needs.GENERATE_MATRIX.outputs.branches != '[]' }}
    strategy:
      fail-fast: false
      matrix:
        branch: ${{ fromJson(needs.GENERATE_MATRIX.outputs.branches) }}
        debug: [true, false]
        zts: [true, false]
    name: "${{ matrix.branch.name }}_LINUX_X32_${{ matrix.debug && 'DEBUG' || 'RELEASE' }}_${{ matrix.zts && 'ZTS' || 'NTS' }}"
    runs-on: ubuntu-latest
    container:
      image: ubuntu:20.04
    env:
      MYSQL_TEST_HOST: mysql
      PDO_MYSQL_TEST_DSN: mysql:host=mysql;dbname=test
      PDO_MYSQL_TEST_HOST: mysql
    services:
      mysql:
        image: mysql:8
        ports:
          - 3306:3306
        env:
          MYSQL_DATABASE: test
          MYSQL_ROOT_PASSWORD: root
    steps:
      - name: git checkout
        uses: actions/checkout@v3
        with:
          ref: ${{ matrix.branch.ref }}
      - name: apt
        uses: ./.github/actions/apt-x32
      - name: ./configure
        uses: ./.github/actions/configure-x32
        with:
          configurationParameters: >-
            --${{ matrix.debug && 'enable' || 'disable' }}-debug
            --${{ matrix.zts && 'enable' || 'disable' }}-zts
      - name: make
        run: make -j$(/usr/bin/nproc) >/dev/null
      - name: make install
        uses: ./.github/actions/install-linux-x32
      - name: Test
        uses: ./.github/actions/test-linux
        with:
          runTestsParameters: >-
            ${{ matrix.run_tests_parameters }}
      - name: Test Tracing JIT
        uses: ./.github/actions/test-linux
        with:
          runTestsParameters: >-
            ${{ matrix.run_tests_parameters }}
            -d zend_extension=opcache.so
            -d opcache.enable_cli=1
            -d opcache.jit_buffer_size=16M
      - name: Test OpCache
        uses: ./.github/actions/test-linux
        with:
          runTestsParameters: >-
            ${{ matrix.run_tests_parameters }}
            -d zend_extension=opcache.so
            -d opcache.enable_cli=1
      - name: Test Function JIT
        uses: ./.github/actions/test-linux
        with:
          runTestsParameters: >-
            ${{ matrix.run_tests_parameters }}
            -d zend_extension=opcache.so
            -d opcache.enable_cli=1
            -d opcache.jit_buffer_size=16M
            -d opcache.jit=1205
  MACOS:
    needs: GENERATE_MATRIX
    if: ${{ needs.GENERATE_MATRIX.outputs.branches != '[]' }}
    strategy:
      fail-fast: false
      matrix:
        branch: ${{ fromJson(needs.GENERATE_MATRIX.outputs.branches) }}
        debug: [true, false]
        zts: [true, false]
    name: "${{ matrix.branch.name }}_MACOS_${{ matrix.debug && 'DEBUG' || 'RELEASE' }}_${{ matrix.zts && 'ZTS' || 'NTS' }}"
    runs-on: macos-11
    steps:
      - name: git checkout
        uses: actions/checkout@v3
        with:
          ref: ${{ matrix.branch.ref }}
      - name: brew
        uses: ./.github/actions/brew
      - name: ./configure
        uses: ./.github/actions/configure-macos
        with:
          configurationParameters: >-
            --${{ matrix.debug && 'enable' || 'disable' }}-debug
            --${{ matrix.zts && 'enable' || 'disable' }}-zts
      - name: make
        run: |-
          export PATH="/usr/local/opt/bison/bin:$PATH"
          make -j$(sysctl -n hw.logicalcpu) >/dev/null
      - name: make install
        run: sudo make install
      - name: Test
        uses: ./.github/actions/test-macos
      - name: Test Tracing JIT
        uses: ./.github/actions/test-macos
        with:
          runTestsParameters: >-
            -d zend_extension=opcache.so
            -d opcache.enable_cli=1
            -d opcache.protect_memory=1
            -d opcache.jit_buffer_size=16M
      - name: Test OpCache
        uses: ./.github/actions/test-macos
        with:
          runTestsParameters: >-
            -d zend_extension=opcache.so
            -d opcache.enable_cli=1
            -d opcache.protect_memory=1
      - name: Test Function JIT
        uses: ./.github/actions/test-macos
        with:
          runTestsParameters: >-
            -d zend_extension=opcache.so
            -d opcache.enable_cli=1
            -d opcache.protect_memory=1
            -d opcache.jit_buffer_size=16M
            -d opcache.jit=1205
      - name: Verify generated files are up to date
        uses: ./.github/actions/verify-generated-files
  COVERAGE_DEBUG_NTS:
    if: github.repository_owner == 'php' || github.event_name == 'workflow_dispatch'
    runs-on: ubuntu-20.04
    steps:
      - name: git checkout
        uses: actions/checkout@v3
      - name: Create MSSQL container
        uses: ./.github/actions/setup-mssql
      - name: Create Oracle container
        uses: ./.github/actions/setup-oracle
      - name: apt
        uses: ./.github/actions/apt-x64
      - name: Install gcovr
        run: sudo -H pip install gcovr
      - name: ./configure
        uses: ./.github/actions/configure-x64
        with:
          configurationParameters: --enable-debug --disable-zts --enable-gcov
      - name: make
        run: make -j$(/usr/bin/nproc) >/dev/null
      - name: make install
        uses: ./.github/actions/install-linux
      - name: Setup
        uses: ./.github/actions/setup-x64
      # We only test with OpCache, the difference in coverage is negligible
      - name: Test OpCache
        uses: ./.github/actions/test-linux
        with:
          runTestsParameters: >-
            -d zend_extension=opcache.so
            -d opcache.enable_cli=1
      - name: Upload Test Coverage to Codecov.io
        if: always()
        run: bash <(curl -s https://codecov.io/bash)
  COMMUNITY:
    needs: GENERATE_MATRIX
    if: ${{ needs.GENERATE_MATRIX.outputs.branches != '[]' }}
    strategy:
      fail-fast: false
      matrix:
        branch: ${{ fromJson(needs.GENERATE_MATRIX.outputs.branches) }}
    name: "${{ matrix.branch.name }}_COMMUNITY"
    runs-on: ubuntu-20.04
    env:
      UBSAN_OPTIONS: print_stacktrace=1
      USE_ZEND_ALLOC: 0
      USE_TRACKED_ALLOC: 1
    steps:
      - name: git checkout
        uses: actions/checkout@v3
        with:
          ref: ${{ matrix.branch.ref }}
      - name: apt
        uses: ./.github/actions/apt-x64
      - name: ./configure
        uses: ./.github/actions/configure-x64
        with:
          configurationParameters: >-
            --enable-debug
            --enable-zts
            CFLAGS='-fsanitize=undefined,address -fno-sanitize-recover -DZEND_TRACK_ARENA_ALLOC'
            LDFLAGS='-fsanitize=undefined,address'
      - name: make
        run: make -j$(/usr/bin/nproc) >/dev/null
      - name: make install
        uses: ./.github/actions/install-linux
      - name: Setup
        run: |
          sudo service mysql start
          mysql -uroot -proot -e "CREATE DATABASE IF NOT EXISTS test"
          mysql -uroot -proot -e "SET GLOBAL local_infile = true"
      - name: Enable Opcache and JIT
        run: |
          echo zend_extension=opcache.so > /etc/php.d/opcache.ini
          echo opcache.enable_cli=1 >> /etc/php.d/opcache.ini
          echo opcache.protect_memory=1 >> /etc/php.d/opcache.ini
          echo opcache.jit_buffer_size=1G >> /etc/php.d/opcache.ini
      - name: Test Laravel
        if: matrix.branch.ref != 'PHP-8.0'
        run: |
          git clone https://github.com/laravel/framework.git --branch=master --depth=1
          cd framework
          git rev-parse HEAD
          php /usr/bin/composer install --no-progress --ignore-platform-reqs
          # Hack to disable a test that hangs
          php -r '$c = file_get_contents("tests/Filesystem/FilesystemTest.php"); $c = str_replace("*/\n    public function testSharedGet()", "* @group skip\n     */\n    public function testSharedGet()", $c); file_put_contents("tests/Filesystem/FilesystemTest.php", $c);'
          export ASAN_OPTIONS=exitcode=139
          php vendor/bin/phpunit --exclude-group skip || EXIT_CODE=$?
          if [ $EXIT_CODE -gt 128 ]; then
            exit 1
          fi
      - name: Test Symfony
        if: matrix.branch.ref != 'PHP-8.0'
        run: |
          git clone https://github.com/symfony/symfony.git --depth=1
          cd symfony
          git rev-parse HEAD
          php /usr/bin/composer install --no-progress --ignore-platform-reqs
          php ./phpunit install
          # Test causes a heap-buffer-overflow but I cannot reproduce it locally...
          php -r '$c = file_get_contents("src/Symfony/Component/HtmlSanitizer/Tests/HtmlSanitizerCustomTest.php"); $c = str_replace("public function testSanitizeDeepNestedString()", "/** @group skip */\n    public function testSanitizeDeepNestedString()", $c); file_put_contents("src/Symfony/Component/HtmlSanitizer/Tests/HtmlSanitizerCustomTest.php", $c);'
          # Buggy FFI test in Symfony, see https://github.com/symfony/symfony/issues/47668
          php -r '$c = file_get_contents("src/Symfony/Component/VarDumper/Tests/Caster/FFICasterTest.php"); $c = str_replace("*/\n    public function testCastNonTrailingCharPointer()", "* @group skip\n     */\n    public function testCastNonTrailingCharPointer()", $c); file_put_contents("src/Symfony/Component/VarDumper/Tests/Caster/FFICasterTest.php", $c);'
          export ASAN_OPTIONS=exitcode=139
          export SYMFONY_DEPRECATIONS_HELPER=max[total]=999
          X=0
          for component in $(find src/Symfony -mindepth 2 -type f -name phpunit.xml.dist -printf '%h\n'); do
            php ./phpunit $component --exclude-group tty,benchmark,intl-data,transient --exclude-group skip || EXIT_CODE=$?
            if [ $EXIT_CODE -gt 128 ]; then
              X=1;
            fi
          done
          exit $X
      - name: Test PHPUnit
        if: always()
        run: |
          git clone https://github.com/sebastianbergmann/phpunit.git --branch=main --depth=1
          cd phpunit
          git rev-parse HEAD
          export ASAN_OPTIONS=exitcode=139
          php /usr/bin/composer install --no-progress --ignore-platform-reqs
          php ./phpunit || EXIT_CODE=$?
          if [ $EXIT_CODE -gt 128 ]; then
            exit 1
          fi
      - name: 'Symfony Preloading'
        if: matrix.branch.ref != 'PHP-8.0'
        run: |
          php /usr/bin/composer create-project symfony/symfony-demo symfony_demo --no-progress --ignore-platform-reqs
          cd symfony_demo
          git rev-parse HEAD
          sed -i 's/PHP_SAPI/"cli-server"/g' var/cache/dev/App_KernelDevDebugContainer.preload.php
          php -d opcache.preload=var/cache/dev/App_KernelDevDebugContainer.preload.php public/index.php
      - name: Test Wordpress
        if: always()
        run: |
          git clone https://github.com/WordPress/wordpress-develop.git wordpress --depth=1
          cd wordpress
          git rev-parse HEAD
          export ASAN_OPTIONS=exitcode=139
          php /usr/bin/composer install --no-progress --ignore-platform-reqs
          cp wp-tests-config-sample.php wp-tests-config.php
          sed -i 's/youremptytestdbnamehere/test/g' wp-tests-config.php
          sed -i 's/yourusernamehere/root/g' wp-tests-config.php
          sed -i 's/yourpasswordhere/root/g' wp-tests-config.php
          php vendor/bin/phpunit || EXIT_CODE=$?
          if [ $EXIT_CODE -gt 128 ]; then
            exit 1
          fi
  OPCACHE_VARIATION:
    needs: GENERATE_MATRIX
    if: ${{ needs.GENERATE_MATRIX.outputs.branches != '[]' }}
    strategy:
      fail-fast: false
      matrix:
        branch: ${{ fromJson(needs.GENERATE_MATRIX.outputs.branches) }}
    name: "${{ matrix.branch.name }}_OPCACHE_VARIATION"
    runs-on: ubuntu-20.04
    steps:
      - name: git checkout
        uses: actions/checkout@v3
        with:
          ref: ${{ matrix.branch.ref }}
      - name: Create MSSQL container
        uses: ./.github/actions/setup-mssql
      - name: Create Oracle container
        uses: ./.github/actions/setup-oracle
      - name: apt
        uses: ./.github/actions/apt-x64
      - name: ./configure
        uses: ./.github/actions/configure-x64
        with:
          configurationParameters: >-
            --enable-debug --disable-zts
      - name: make
        run: make -j$(/usr/bin/nproc) >/dev/null
      - name: make install
        uses: ./.github/actions/install-linux
      - name: Setup
        uses: ./.github/actions/setup-x64
      - name: Test File Cache (prime shm)
        uses: ./.github/actions/test-linux
        with:
          runTestsParameters: >-
            -d zend_extension=opcache.so
            -d opcache.enable_cli=1
            --file-cache-prime
      - name: Test File Cache (prime shm, use shm)
        uses: ./.github/actions/test-linux
        with:
          runTestsParameters: >-
            -d zend_extension=opcache.so
            -d opcache.enable_cli=1
            --file-cache-use
      - name: Test File Cache (prime shm, use file)
        uses: ./.github/actions/test-linux
        with:
          runTestsParameters: >-
            -d zend_extension=opcache.so
            -d opcache.enable_cli=1
            --file-cache-use
            -d opcache.file_cache_only=1
      - name: Test File Cache Only (prime)
        uses: ./.github/actions/test-linux
        with:
          runTestsParameters: >-
            -d zend_extension=opcache.so
            -d opcache.enable_cli=1
            --file-cache-prime
            -d opcache.file_cache_only=1
      - name: Test File Cache Only (use)
        uses: ./.github/actions/test-linux
        with:
          runTestsParameters: >-
            -d zend_extension=opcache.so
            -d opcache.enable_cli=1
            --file-cache-use
            -d opcache.file_cache_only=1
      - name: Verify generated files are up to date
        uses: ./.github/actions/verify-generated-files
  MSAN:
    needs: GENERATE_MATRIX
    if: ${{ needs.GENERATE_MATRIX.outputs.branches != '[]' }}
    strategy:
      fail-fast: false
      matrix:
        branch: ${{ fromJson(needs.GENERATE_MATRIX.outputs.branches) }}
    name: "${{ matrix.branch.name }}_MSAN"
    runs-on: ubuntu-22.04
    steps:
      - name: git checkout
        uses: actions/checkout@v3
        with:
          ref: ${{ matrix.branch.ref }}
      - name: apt
        uses: ./.github/actions/apt-x64
      - name: ./configure
        run: |
          export CC=clang
          export CXX=clang++
          export CFLAGS="-DZEND_TRACK_ARENA_ALLOC"
          ./buildconf --force
          # msan requires all used libraries to be instrumented,
          # so we should avoiding linking against anything but libc here
          ./configure \
            --enable-debug \
            --enable-zts \
            --enable-option-checking=fatal \
            --prefix=/usr \
            --without-sqlite3 \
            --without-pdo-sqlite \
            --without-libxml \
            --disable-dom \
            --disable-simplexml \
            --disable-xml \
            --disable-xmlreader \
            --disable-xmlwriter \
            --without-pcre-jit \
            --disable-opcache-jit \
            --enable-phpdbg \
            --enable-fpm \
            --with-pdo-mysql=mysqlnd \
            --with-mysqli=mysqlnd \
            --disable-mysqlnd-compression-support \
            --without-pear \
            --enable-exif \
            --enable-sysvsem \
            --enable-sysvshm \
            --enable-shmop \
            --enable-pcntl \
            --enable-mbstring \
            --disable-mbregex \
            --enable-sockets \
            --enable-bcmath \
            --enable-calendar \
            --enable-ftp \
            --enable-zend-test \
            --enable-werror \
            --enable-memory-sanitizer \
            --with-config-file-path=/etc \
            --with-config-file-scan-dir=/etc/php.d
      - name: make
        run: make -j$(/usr/bin/nproc) >/dev/null
      - name: make install
        run: |
          sudo make install
          sudo mkdir     /etc/php.d
          sudo chmod 777 /etc/php.d
          echo mysqli.default_socket=/var/run/mysqld/mysqld.sock    > /etc/php.d/mysqli.ini
          echo pdo_mysql.default_socket=/var/run/mysqld/mysqld.sock > /etc/php.d/pdo_mysql.ini
      - name: Setup
        run: |
          set -x
          sudo service mysql start
          mysql -uroot -proot -e "CREATE DATABASE IF NOT EXISTS test"
          # Ensure local_infile tests can run.
          mysql -uroot -proot -e "SET GLOBAL local_infile = true"
          sudo locale-gen de_DE
      - name: Test
        uses: ./.github/actions/test-linux
        with:
          runTestsParameters: >-
            --msan
      - name: Test Opcache
        uses: ./.github/actions/test-linux
        with:
          runTestsParameters: >-
            --msan
            -d zend_extension=opcache.so
            -d opcache.enable_cli=1
      - name: Verify generated files are up to date
        uses: ./.github/actions/verify-generated-files
