name: CI

on:
  push:
    branches: [main]
    tags: ["v*.*.*"]
  pull_request:
    branches: [main]
  release:
    types:
      - published
  workflow_dispatch:
    inputs:
      debug_enabled:
        type: boolean
        description: 'Run the build with tmate debugging enabled (https://github.com/marketplace/actions/debugging-with-tmate)'
        required: false
        default: false

jobs:
  build_sdist:
    name: Build Source Distribution
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
        with:
          submodules: recursive
          fetch-depth: 0
      - uses: actions/setup-python@v5
        with:
          python-version: "3.x"
      - name: Build sdist
        run: pipx run build --sdist
      - name: Check metadata
        run: pipx run twine check dist/*.tar.gz
      - uses: actions/upload-artifact@v4
        with:
          path: dist/*.tar.gz
          name: sdist

  build_wheels:
    name: Build wheel ${{ matrix.os }}
    runs-on: ${{ matrix.os }}
    strategy:
      fail-fast: false
      # macos-13 runners are still x86_64, macos-14 (latest) are arm64; we want to build
      # the x86_64 wheel on/for x86_64 macs
      matrix:
        os: [ "ubuntu-latest", "macos-13", "windows-latest" ]
    env:
      CIBW_ENVIRONMENT: TTFAUTOHINTPY_BUNDLE_EXE=1
      CIBW_ENVIRONMENT_WINDOWS: "TTFAUTOHINTPY_BUNDLE_EXE=1 MINGWROOT=C:\\mingw-win32"
      CIBW_BEFORE_ALL_LINUX: sh ci/docker-fixes.sh
      CIBW_BEFORE_ALL_MACOS: sh ci/osx-fixes.sh
      # on windows cibuildwheel builds both 32 and 64 bit one after the other so
      # it's necessary to clean the build dir between builds
      CIBW_BEFORE_BUILD_WINDOWS: "python -m pip install setuptools_scm && python setup.py clean -a"
      CIBW_BUILD_FRONTEND: "pip"
      CIBW_ARCHS_LINUX: x86_64
      CIBW_ARCHS_MACOS: universal2
      CIBW_MANYLINUX_X86_64_IMAGE: manylinux2014
      # Building for one python version is enough, since this is a
      # 'universal binary wheel' (py3-none-*) not
      # linked to a specific python version or implementation.
      CIBW_BUILD: "cp39-*"
      CIBW_SKIP: "*-musllinux*"
      CIBW_BUILD_VERBOSITY: 1
      CIBW_TEST_REQUIRES: -rtest-requirements.txt
      CIBW_TEST_COMMAND: cd {project} && coverage run --parallel-mode -m pytest
      # on Windows I need '/d' flag to change both drive and directory at once
      CIBW_TEST_COMMAND_WINDOWS: cd /d {project} && coverage run --parallel-mode -m pytest
    steps:
      # https://github.com/msys2/setup-msys2?tab=readme-ov-file#actionscheckout-and-line-endings
      - name: "Configure Git for Windows to leave line endings alone"
        if: startsWith(matrix.os, 'windows')
        run: git config --global core.autocrlf input
      - uses: actions/checkout@v4
        with:
          submodules: recursive
          fetch-depth: 0
      # Enable tmate debugging of manually-triggered workflows if the input option was provided
      - name: Setup tmate session
        uses: mxschmitt/action-tmate@v3
        if: ${{ github.event_name == 'workflow_dispatch' && inputs.debug_enabled }}
        with:
          detached: true
      - name: "Set up MSYS2 (Windows)"
        uses: msys2/setup-msys2@v2
        if: startsWith(matrix.os, 'windows')
        with:
          release: false
          install: >-
            base-devel
            autotools
            git
            mingw-w64-i686-ragel
            mingw-w64-x86_64-ragel
      - uses: actions/setup-python@v5
        with:
          python-version: "3.x"
      - name: Set up environment
        shell: bash
        # applying patches makes the working directory 'dirty', which changes the
        # git-generated version, so we save the current version beforehand
        run: |
          python -m pip install setuptools_scm
          echo CIBW_ENVIRONMENT="$CIBW_ENVIRONMENT SETUPTOOLS_SCM_PRETEND_VERSION=$(python setup.py --version)" >> $GITHUB_ENV
      - name: "Install MinGW-w64 with win32 threads (Windows)"
        if: startsWith(matrix.os, 'windows')
        shell: bash
        run: |
          # Download MinGW-w64 with win32 threads (64-bit)
          curl -L -o mingw64.7z "https://github.com/niXman/mingw-builds-binaries/releases/download/15.1.0-rt_v12-rev0/x86_64-15.1.0-release-win32-seh-msvcrt-rt_v12-rev0.7z"
          7z x mingw64.7z -o/c/mingw-win32/

          # Download MinGW-w64 with win32 threads (32-bit)
          curl -L -o mingw32.7z "https://github.com/niXman/mingw-builds-binaries/releases/download/15.1.0-rt_v12-rev0/i686-15.1.0-release-win32-dwarf-msvcrt-rt_v12-rev0.7z"
          7z x mingw32.7z -o/c/mingw-win32/
      - name: Update path (Mac)
        if: startsWith(matrix.os, 'macos')
        run: |
          echo "/usr/local/opt/libtool/bin" >> $GITHUB_PATH
          echo "/usr/local/opt/ragel/bin" >> $GITHUB_PATH
          echo "/usr/local/opt/bison/bin" >> $GITHUB_PATH
          echo "/usr/local/opt/flex/bin" >> $GITHUB_PATH
          echo "/usr/local/opt/automake/bin" >> $GITHUB_PATH
      - name: Install cibuildwheel
        run: python -m pip install cibuildwheel
      - name: Build wheels
        run: python -m cibuildwheel --output-dir dist
      - name: Analyze DLL dependencies (Windows)
        if: startsWith(matrix.os, 'windows')
        shell: bash
        run: |
          # Download Dependencies.exe for DLL analysis
          curl -L -o dependencies.zip https://github.com/lucasg/Dependencies/releases/latest/download/Dependencies_x64_Release.zip
          unzip -q dependencies.zip
          # Analyze the built ttfautohint.exe binary
          ./Dependencies.exe -depth 1 -chain build/local/bin/ttfautohint.exe
          # Also check what DLLs it tries to load
          ./Dependencies.exe -imports build/local/bin/ttfautohint.exe
      - name: Check wheels metadata
        run: pipx run twine check dist/*.whl
      - uses: actions/upload-artifact@v4
        with:
          path: dist/*.whl
          name: wheels-${{ matrix.os }}
      - name: Generate coverage report
        # linux wheels are built inside docker container, I don't know how to extract
        # the .coverage file from there, so skip coverage/codacov from linux for now...
        if: ${{ !startsWith(matrix.os, 'ubuntu') }}
        run: |
          pip install coverage
          coverage combine
          coverage xml
      - name: Upload coverage to Codecov
        if: ${{ !startsWith(matrix.os, 'ubuntu') }}
        uses: codecov/codecov-action@v4
        with:
          file: coverage.xml

  deploy:
    name: Upload if release
    needs: [build_sdist, build_wheels]
    runs-on: ubuntu-latest
    if: github.event_name == 'release' && github.event.action == 'published'
    permissions:
      id-token: write  # IMPORTANT: this permission is mandatory for trusted publishing

    steps:
    - uses: actions/download-artifact@v4
      with:
        path: dist
        merge-multiple: true

    - uses: pypa/gh-action-pypi-publish@release/v1
