name: Linux

on:
  workflow_call:
  workflow_dispatch:

env:
  APP_ID: io.github.nuttyartist.notes

jobs:
  deb:
    name: deb (${{ matrix.build-type }}, Qt ${{ matrix.qt-version-major }}, ${{ matrix.image }})
    runs-on: ubuntu-latest
    container:
      image: zjeffer/notes:${{ matrix.image }}
    strategy:
      fail-fast: false
      matrix:
        include:
          # Ubuntu's release cycle: https://wiki.ubuntu.com/Releases
          - image: ubuntu-20_04
            qt-version-major: 5
            build-type: release

          - image: ubuntu-22_04
            qt-version-major: 6
            build-type: release

          - image: ubuntu-23_10
            qt-version-major: 6
            build-type: release
    steps:
      - name: Setup git configuration
        # workaround for "detected dubious ownership in repository" git error: https://github.com/actions/checkout/issues/1169
        run: git config --global --add safe.directory "${PWD}"

      - name: Checkout code
        uses: actions/checkout@v4
        with:
          submodules: recursive

      - name: Set up variables
        shell: bash
        id: vars
        run: |
          set -x
          distro_id=$(grep -oPm1 '^ID="?\K[^"]+' /etc/os-release)
          if [ -z "${distro_id}" ]
          then
              echo 'Fatal: Failed to extract distro ID from /etc/os-release'
              exit 1
          fi
          distro_codename=$(grep -oPm1 '^VERSION_CODENAME="?\K[^"]+' /etc/os-release)
          if [ -z "${distro_codename}" ]
          then
              echo 'Fatal: Failed to extract distro codename from /etc/os-release'
              exit 1
          fi
          echo "distro_name=${distro_id}-${distro_codename}" >> "${GITHUB_OUTPUT}"

      - name: Setup GCC problem matcher
        uses: ammaraskar/gcc-problem-matcher@0.3.0

      - name: Build (${{ matrix.build-type }})
        env:
          VERBOSE: 1
        run: |
          cmake --warn-uninitialized --warn-unused-vars \
              -B build \
              -DCMAKE_BUILD_TYPE=${{ matrix.build-type }} \
              -DGIT_REVISION=${{ github.ref_type != 'tag' && 'ON' || 'OFF' }} \
              -DCMAKE_INSTALL_PREFIX=/usr \
              -DPRO_VERSION=OFF
          cmake --build build --parallel $(nproc)

      - name: Create deb package
        run: |
          cd build
          cpack -G DEB

      - name: Grab deb package name
        id: deb
        shell: bash
        run: |
          set -x
          if ! path=$(find build/ -maxdepth 1 -name '*.deb' -print -quit)
          then
              echo 'Fatal: Unable to find deb package'
              exit 1;
          fi
          echo "name=$(basename "${path%.*}")" >> "${GITHUB_OUTPUT}"
          echo "path=${path}" >> "${GITHUB_OUTPUT}"

      - name: Run lintian
        run: |
          lintian '${{ steps.deb.outputs.path }}'

      - name: Upload deb package
        uses: actions/upload-artifact@v4
        with:
          if-no-files-found: error
          name: ${{ steps.deb.outputs.name }}-qt${{ matrix.qt-version-major }}-${{ steps.vars.outputs.distro_name }}-${{ matrix.build-type }}
          path: ${{ steps.deb.outputs.path }}

  rpm:
    name: rpm (${{ matrix.build-type }}, Qt ${{ matrix.qt-version-major }}, ${{ matrix.image }})
    runs-on: ubuntu-latest
    container: zjeffer/notes:${{ matrix.image }}
    strategy:
      fail-fast: false
      matrix:
        include:
          - # Fedora's release cycle: https://docs.fedoraproject.org/en-US/releases/lifecycle/
            image: fedora
            qt-version-major: 6
            build-type: release

          - image: opensuse
            qt-version-major: 6
            build-type: release
    steps:
      - name: Setup git configuration
        # workaround for "detected dubious ownership in repository" git error: https://github.com/actions/checkout/issues/1169
        run: git config --global --add safe.directory "${PWD}"

      - name: Checkout code
        uses: actions/checkout@v4
        with:
          submodules: recursive

      - name: Set up variables
        shell: bash
        id: vars
        run: |
          set -x
          distro_id=$(grep -oPm1 '^ID="?\K[^"]+' /etc/os-release)
          if [ -z "${distro_id}" ]
          then
              echo 'Failed to extract distro ID from /etc/os-release.'
              exit 1
          fi
          version_id=$(grep -oPm1 '^VERSION_ID="?\K[^"]+' /etc/os-release)
          if [ -z "${version_id}" ]
          then
              echo 'Failed to extract version id from /etc/os-release.'
              exit 1
          fi
          echo "distro_name=${distro_id}-${version_id}" >> "${GITHUB_OUTPUT}"

      - name: Setup GCC problem matcher
        uses: ammaraskar/gcc-problem-matcher@0.3.0

      - name: Build (${{ matrix.build-type }})
        env:
          VERBOSE: 1
          # openSUSE defaults to GCC 7, which doesn't support the filesystem library from C++17,
          # and causes trouble compiling for Qt 6. So we have to manully specify GCC 10 instead.
          CXX: ${{ startsWith(matrix.image, 'opensuse') && 'g++-10' || 'g++' }}
        run: |
          cmake --warn-uninitialized --warn-unused-vars \
              -B build \
              -DCMAKE_BUILD_TYPE=${{ matrix.build-type }} \
              -DGIT_REVISION=${{ github.ref_type != 'tag' && 'ON' || 'OFF' }} \
              -DCMAKE_POSITION_INDEPENDENT_CODE=TRUE \
              -DUPDATE_CHECKER=OFF \
              -DUSE_QT_VERSION=${{ matrix.qt-version-major }} \
              -DPRO_VERSION=OFF
          cmake --build build --parallel $(nproc)

      - name: Create rpm package
        run: |
          cd build
          cpack -G RPM

      - name: Grab rpm package name
        id: rpm
        shell: bash
        run: |
          set -x
          if ! path=$(find build/ -maxdepth 1 -name '*.rpm' -print -quit)
          then
              echo 'Fatal: Unable to find rpm package!'
              exit 1;
          fi
          echo "name=$(basename "${path%.*}")" >> "${GITHUB_OUTPUT}"
          echo "path=${path}" >> "${GITHUB_OUTPUT}"

      - name: Run rpmlint
        run: |
          rpmlint '${{ steps.rpm.outputs.path }}'

      - name: Upload rpm package
        uses: actions/upload-artifact@v4
        with:
          if-no-files-found: error
          name: ${{ steps.rpm.outputs.name }}-qt${{ matrix.qt-version-major }}-${{ steps.vars.outputs.distro_name }}-${{ matrix.build-type }}
          path: ${{ steps.rpm.outputs.path }}

  # Build the AppImage using official Qt releases, downloaded by aqtinstall.
  # This is also done for macOS and Windows, just to make sure we use the exact same Qt version across all three OSes.
  #
  # NOTE: This job uses a fixed Qt version (set in the 'qt-version' key below)!
  # So, remember to keep it updated whenever a new Qt version is available on aqtinstall.
  appimage-aqtinstall:
    name: AppImage (${{ matrix.build-type }}, Qt ${{ matrix.qt-version }}, ${{ matrix.image }})
    runs-on: ${{ matrix.os }}
    container:
      image: zjeffer/notes:${{ matrix.image }}
    strategy:
      fail-fast: false
      matrix:
        include:
          - os: ubuntu-22.04
            build-type: release
            qt-version: 5.15.2
            image: ubuntu-aqtinstall-5
          
          - os: ubuntu-22.04
            build-type: release
            qt-version: 6.4.3
            image: ubuntu-aqtinstall-6
    steps:
      - name: Checkout code
        uses: actions/checkout@v4
        with:
          submodules: recursive

      - name: Setup variables
        shell: bash
        id: vars
        run: |
          set -x
          version=$(grep -oPm1 '\bAPP_VERSION +\K[^)]+' CMakeLists.txt)
          if [ -z "${version}" ]
          then
              echo 'Failed to extract app version from CMakeLists.txt.'
              exit 1
          fi
          if [ '${{ github.ref_type }}' != 'tag' ]
          then
              version="${version}+g${GITHUB_SHA::7}"
          fi
          artifact_name="Notes_${version}-Qt${{ matrix.qt-version }}-x86_64"
          if [ '${{ matrix.build-type }}' == 'debug' ]
          then
              file_name="${artifact_name}-debug.AppImage"
          else
              file_name="${artifact_name}.AppImage"
          fi
          echo "version=${version}" >> "${GITHUB_OUTPUT}"
          echo "artifact_name=${artifact_name}" >> "${GITHUB_OUTPUT}"
          echo "file_name=${file_name}" >> "${GITHUB_OUTPUT}"

      # TODO: Figure out why this error only occurs on the Linux container when building with -DGIT_REVISION=ON
      # The error: fatal: detected dubious ownership in repository
      - name: Prevent git's dubious ownership message
        if: github.ref_type != 'tag'
        run: |
          git config --global --add safe.directory "${PWD}"

      - name: Build (${{ matrix.build-type }})
        env:
          VERBOSE: 1
        run: |
          cmake --warn-uninitialized --warn-unused-vars \
              -B build \
              -DCMAKE_BUILD_TYPE=${{ matrix.build-type }} \
              -DGIT_REVISION=${{ github.ref_type != 'tag' && 'ON' || 'OFF' }} \
              -DCMAKE_INSTALL_PREFIX=/usr \
              -DPRO_VERSION=OFF
          cmake --build build --parallel $(nproc)

      - name: (FIXME) Run qmllint
        if: startsWith(matrix.qt-version, '6.')
        run: |
          cmake --build build --target all_qmllint || true

      - name: Install (${{ matrix.build-type }})
        run: |
          make -C build DESTDIR=Notes install

      - name: Setup linuxdeploy
        run: |
          cd build
          curl -fLO --retry 10 https://github.com/linuxdeploy/linuxdeploy/releases/download/continuous/linuxdeploy-x86_64.AppImage
          chmod +x linuxdeploy-x86_64.AppImage

      - name: Setup Qt plugin for linuxdeploy
        run: |
          cd build
          curl -fLO --retry 10 https://github.com/linuxdeploy/linuxdeploy-plugin-qt/releases/download/continuous/linuxdeploy-plugin-qt-x86_64.AppImage
          chmod +x linuxdeploy-plugin-qt-x86_64.AppImage

      - name: Deploy (${{ matrix.build-type }})
        env:
          APPIMAGE_EXTRACT_AND_RUN: 1
        run: |
          export QML_SOURCES_PATHS="${PWD}/src/qml"
          cd build
          ./linuxdeploy-x86_64.AppImage --appdir Notes --plugin qt

      - name: Remove unnecessary Qt plugins and libraries
        shell: bash
        run: |
          set -x
          set -e
          cd build/Notes
          if [[ '${{ matrix.qt-version }}' == 5.* ]]
          then
              # The bearer plugin has caused problems for us in the past. Plus, it was removed altogether in Qt 6.
              rm -rv usr/plugins/bearer
          fi
          # We only use the SQLite Qt driver, so it's fine to delete others.
          rm -v usr/plugins/sqldrivers/libqsqlodbc.so
          rm -v usr/plugins/sqldrivers/libqsqlpsql.so
          if [[ '${{ matrix.qt-version }}' == 6.* ]]
          then
              # The Qt 6 build also has a MySQL Qt driver we don't use.
              rm -v usr/plugins/sqldrivers/libqsqlmysql.so
              rm -v usr/lib/libmysqlclient.so.*
          fi

      - name: Validate AppStream metadata
        if: matrix.image != 'ubuntu:20.04'
        run: |
          cd build/Notes
          appstreamcli validate --verbose 'usr/share/metainfo/${{ env.APP_ID }}.metainfo.xml'

      - name: Validate desktop file
        run: |
          cd build/Notes
          desktop-file-validate 'usr/share/applications/${{ env.APP_ID }}.desktop'

      - name: Build AppImage (${{ matrix.build-type }})
        env:
          APPIMAGE_EXTRACT_AND_RUN: 1
        run: |
          cd build
          export VERSION='${{ steps.vars.outputs.version }}'
          ./linuxdeploy-x86_64.AppImage --appdir Notes --output appimage
          mv -v Notes*.AppImage '${{ steps.vars.outputs.file_name }}'

      - name: Upload AppImage artifact (${{ matrix.build-type }})
        uses: actions/upload-artifact@v4
        with:
          if-no-files-found: error
          name: ${{ steps.vars.outputs.artifact_name }}-${{ runner.os }}-${{ matrix.build-type }}
          path: build/${{ steps.vars.outputs.file_name }}

  snap:
    name: snap
    runs-on: ubuntu-latest
    steps:
      - name: Checkout code
        uses: actions/checkout@v4
        with:
          submodules: recursive

      - name: Install snapcraft
        run: |
          sudo snap install snapcraft --classic

      - name: Set up LXD
        run: |
          sudo usermod -a -G lxd "${USER}"
          sudo lxd init --auto
          sudo iptables -P FORWARD ACCEPT

      - name: Build
        run: |
          sg lxd -c 'snap run snapcraft -v'

      - name: Grab snap package name
        id: snap
        shell: bash
        run: |
          set -x
          if ! path=$(find . -maxdepth 1 -name '*.snap' -print -quit)
          then
              echo 'Fatal: Unable to find snap package'
              exit 1
          fi
          echo "name=$(basename "${path%.*}")" >> "${GITHUB_OUTPUT}"
          echo "path=${path}" >> "${GITHUB_OUTPUT}"

      - name: Upload snap package
        uses: actions/upload-artifact@v4
        with:
          if-no-files-found: error
          name: ${{ steps.snap.outputs.name }}.snap
          path: ${{ steps.snap.outputs.path }}
