name: C/C++ CI

on:
  push:
    branches: [ master, release/v8.* ]
  pull_request:
    branches: [ master, release/v8.* ]

# https://docs.github.com/en/actions/writing-workflows/workflow-syntax-for-github-actions#concurrency
# Ensure that only one commit will be running tests at a time on each PR
concurrency:
  group: ${{ github.ref }}-${{ github.workflow }} 
  cancel-in-progress: true

jobs:
  build-ubuntu:
    if: ${{ github.event_name != 'pull_request' || github.repository != github.event.pull_request.head.repo.full_name }}
    runs-on: ubuntu-24.04
    strategy:
      fail-fast: false
      matrix:
        # A valid option parameter to the cmake file.
        # See BUILD_OPTIONS in tests/CMakeLists.txt.
        build_option: ['OPTIONS_NORMAL_8BIT',
                       'OPTIONS_16BIT',
                       'OPTIONS_24BIT',
                       'OPTIONS_FULL_32BIT',
                       'OPTIONS_SDL']
    name: Build ${{ matrix.build_option }} - Ubuntu
    steps:
    - uses: actions/checkout@v6
    - uses: ammaraskar/gcc-problem-matcher@master
    - name: Setup Python
      uses: actions/setup-python@v6
      with:
        python-version: '3.12'
    - name: Install prerequisites
      run: scripts/install-prerequisites.sh
    - name: Install pngquant
      run:  scripts/install_pngquant.sh
    - name: Verify the environment dependency installation
      run: scripts/run_tests.sh --skip-tests
    - name: Building ${{ matrix.build_option }}
      run: python tests/main.py --build-option=${{ matrix.build_option }} build --auto-clean

  build-windows:
    strategy:
      fail-fast: false
      matrix:
        # A valid option parameter to the cmake file.
        # See BUILD_OPTIONS in tests/CMakeLists.txt.
        build_option: ['OPTIONS_16BIT',
                       'OPTIONS_24BIT',
                       'OPTIONS_FULL_32BIT']
        compiler: [gcc, cl]

    name: Build ${{ matrix.build_option }} - ${{matrix.compiler }} - Windows
    runs-on: windows-2022
    steps:
    - name: patch freetype vcpkg URL
      run: (Get-Content C:\vcpkg\ports\freetype\portfile.cmake) -replace 'freedesktop.org', 'com' | Out-File -encoding ASCII C:\vcpkg\ports\freetype\portfile.cmake

    - uses: actions/checkout@v6

    - name: Install prerequisites
      run: scripts\install-prerequisites.bat

    - if: matrix.compiler == 'gcc'
      uses: ammaraskar/gcc-problem-matcher@master

    - if: matrix.compiler == 'cl'
      uses: ilammy/msvc-dev-cmd@v1
      with:
        arch: x64

    - if: matrix.compiler == 'cl'
      uses: ruby/setup-ruby@v1
      with:
        ruby-version: 'mswin'

    - name: Build
      run: python tests/main.py --build-option=${{ matrix.build_option }} build
      env:
        CC: ${{ matrix.compiler }}

  build-esp32s3:
    runs-on: ubuntu-24.04
    name: Build ESP IDF ESP32S3
    container: espressif/idf:v5.3.1
    steps:
    - name: Setup Python
      uses: actions/setup-python@v6
      with:
        python-version: '3.12'
    - name: Clone LVGL as a Component
      uses: actions/checkout@v6
      with:
        path: components/lvgl
    - name: Copy IDF Project Example
      run: . /opt/esp/idf/export.sh && cp -r $IDF_PATH/examples/get-started/hello_world/* .
    - name: Set Target ESP32S3
      run: . /opt/esp/idf/export.sh && idf.py set-target esp32s3
    - name: Build
      run: . /opt/esp/idf/export.sh && idf.py build

  test-native:
    runs-on: ubuntu-24.04
    strategy:
     matrix:
       # A valid option parameter to the cmake file.
       # See BUILD_OPTIONS in tests/CMakeLists.txt.
       build_config: ['64bit build',
                      '32bit build']
    name: Run tests with ${{ matrix.build_config }}
    steps:
    - uses: actions/checkout@v6
    - uses: ammaraskar/gcc-problem-matcher@master
    - name: Setup Python
      uses: actions/setup-python@v6
      with:
        python-version: '3.12'
    - name: Install prerequisites
      run: scripts/install-prerequisites.sh
    - name: Install pngquant
      run: scripts/install_pngquant.sh
    - name: Verify the environment dependency installation
      run: scripts/run_tests.sh --skip-tests
    - name: Fix kernel mmap rnd bits
      # Asan in llvm 14 provided in ubuntu 22.04 is incompatible with
      # high-entropy ASLR in much newer kernels that GitHub runners are
      # using leading to random crashes: https://reviews.llvm.org/D148280
      run: sudo sysctl vm.mmap_rnd_bits=28
    - name: Set environment variables for 32-bit build
      if: matrix.build_config == '32bit build'
      run: echo "NON_AMD64_BUILD=1" >> $GITHUB_ENV
    - name: Run tests
      run: python tests/main.py --report --update-image test --auto-clean --keep-report
    - name: Code coverage analysis
      run: |
        if [ "${{ github.event_name }}" = "pull_request" ]; then
          git fetch --no-tags --prune origin ${{ github.event.pull_request.base.sha }} ${{ github.event.pull_request.head.sha }}
          MB=$(git merge-base ${{ github.event.pull_request.base.sha }} ${{ github.event.pull_request.head.sha }})
          echo "Merge-base: $MB"
          python scripts/check_gcov_coverage.py --commit="${MB}...${{ github.event.pull_request.head.sha }}"
        else
          echo "Not a pull request, skipping code coverage analysis."
        fi
    - name: Archive screenshot errors
      if: failure()
      uses: actions/upload-artifact@v6
      with:
        name: screenshot-errors-amd64
        path: |
             tests/ref_imgs*/**/*_err.png
             test_screenshot_error.h
    - id: check_untracked_ref_imgs
      name: Check for new files and upload them as artifacts if found
      run: |
        NEW_REF_IMGS=$(git status --porcelain -- tests/ref_imgs* | grep '^??' | awk '{print $2}')

        if [ -n "$NEW_REF_IMGS" ]; then
          echo "New files were added during the build process."
          echo "Uploading untracked ref. images as artifacts..."
          for file in $NEW_REF_IMGS; do
            echo "Found new file: $file"
          done
          zip -r untracked_ref_imgs.zip $NEW_REF_IMGS
          echo "::set-output name=new_ref_imgs_found::true"
        else
          echo "No new files were found."
          echo "::set-output name=new_ref_imgs_found::false"
        fi

    - name: Upload untracked reference images
      if: steps.check_untracked_ref_imgs.outputs.new_ref_imgs_found == 'true'
      uses: actions/upload-artifact@v6
      with:
        name: Untracked Reference Images
        path: untracked_ref_imgs.zip

    - name: Fail the build if new files were found
      if: steps.check_untracked_ref_imgs.outputs.new_ref_imgs_found == 'true'
      run: |
        echo "Failing the build due to newly generated reference images."
        exit 1

    - name: Upload coverage reports as artifacts
      if: always()
      uses: actions/upload-artifact@v6
      with:
        name: coverage-reports-${{ matrix.build_config }}
        path: tests/report/
