name: macOS

on:
  workflow_call:
  workflow_dispatch:

jobs:
  # This job is mainly to make sure Notes will compile with Qt from homebrew's repository.
  # So it doesn't make much sense to have different build types other than 'debug' here.
  # The release dmg is built using aqtinstall instead (the job below this one).
  build-homebrew:
    name: Build (${{ matrix.build-type }}, homebrew (qt${{ matrix.qt-version-major }}), ${{ matrix.os }})
    runs-on: ${{ matrix.os }}
    strategy:
      fail-fast: false
      matrix:
        include:
          - os: macos-12
            qt-version-major: 5
            build-type: debug

          - os: macos-12
            qt-version-major: 6
            build-type: debug
    steps:
      - name: Checkout code
        uses: actions/checkout@v4
        with:
          submodules: recursive

      - name: Install Qt ${{ matrix.qt-version-major }} (homebrew)
        env:
          # TODO: remove once https://github.com/actions/setup-python/issues/577 gets fixed.
          HOMEBREW_NO_INSTALLED_DEPENDENTS_CHECK: 1
        run: |
          brew update
          brew install ninja qt@${{ matrix.qt-version-major }} 

      - name: Configure Qt ${{ matrix.qt-version-major }} (homebrew)
        run: |
          brew link qt@${{ matrix.qt-version-major }}
          cat << EOF
          LDFLAGS="-L/usr/local/opt/qt@${{ matrix.qt-version-major }}/lib"
          export CPPFLAGS="-I/usr/local/opt/qt@${{ matrix.qt-version-major }}/include"
          export PATH="/usr/local/opt/qt@${{ matrix.qt-version-major }}/bin:$PATH"
          EOF >> ~/.bashrc

      - name: Setup CLang problem matcher
        # Technically, this action only supports GCC, but it seems to work well for Clang too.
        if: matrix.build-type == 'debug'
        uses: ammaraskar/gcc-problem-matcher@0.3.0

      - name: Build (${{ matrix.build-type }})
        env:
          VERBOSE: 1
        run: |
          export CMAKE_BUILD_PARALLEL_LEVEL=$(sysctl -n hw.logicalcpu)
          cmake . --warn-uninitialized --warn-unused-vars \
              -G Ninja -B build \
              -DCMAKE_BUILD_TYPE=${{ matrix.build-type }} \
              -DCMAKE_PREFIX_PATH="$(brew --prefix qt@${{ matrix.qt-version-major }})" \
              -DPRO_VERSION=OFF
          cmake --build build

  # Build the dmg disk image using the official Qt 5 release downloaded by aqtinstall.
  # This is also done for Linux 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.
  dmg-aqtinstall:
    name: dmg (${{ matrix.build-type }}, Qt ${{ matrix.qt-version }}, ${{ matrix.os }})
    runs-on: ${{ matrix.os }}
    strategy:
      fail-fast: false
      matrix:
        include:
          - os: macos-11
            qt-version: 5.15.2
            build-type: release

          - os: macos-11
            qt-version: 6.5.2
            build-type: release
    steps:
      - name: Checkout code
        uses: actions/checkout@v4
        with:
          submodules: recursive

      - name: Setup variables
        id: vars
        run: |
          set -x
          version=$(grep -Em1 '\bAPP_VERSION' CMakeLists.txt | sed -r 's/.*APP_VERSION +//; s/ *)//')
          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
          arches='x86_64'
          if [[ '${{ matrix.qt-version }}' == 6.* ]]
          then
              arches+='-arm64'
          fi
          artifact_name="Notes_${version}-Qt${{ matrix.qt-version }}-${arches}"
          if [ '${{ matrix.build-type }}' == 'debug' ]
          then
              file_name="${artifact_name}-debug.dmg"
          else
              file_name="${artifact_name}.dmg"
          fi
          echo "version=${version}" >> "${GITHUB_OUTPUT}"
          echo "artifact_name=${artifact_name}" >> "${GITHUB_OUTPUT}"
          echo "file_name=${file_name}" >> "${GITHUB_OUTPUT}"

      - name: Install Qt ${{ matrix.qt-version }} (aqtinstall)
        uses: jurplel/install-qt-action@v3
        with:
          version: ${{ matrix.qt-version }}
          cache: true

      - name: Install dependencies
        run: |
          brew update
          brew install create-dmg ninja

      - name: Build (${{ matrix.build-type }})
        env:
          # Only commercial Qt 5 supports targeting Apple Silicon at the moment:
          # https://www.qt.io/blog/qt-on-apple-silicon
          TARGET_ARCH: ${{ startsWith(matrix.qt-version, '6.') && 'x86_64;arm64' || 'x86_64' }}
          VERBOSE: 1
        run: |
          export CMAKE_BUILD_PARALLEL_LEVEL=$(sysctl -n hw.logicalcpu)
          cmake . --warn-uninitialized --warn-unused-vars \
              -B build -G Ninja \
              -DCMAKE_BUILD_TYPE=${{ matrix.build-type }} \
              -DGIT_REVISION=${{ github.ref_type != 'tag' && 'ON' || 'OFF' }} \
              -DCMAKE_OSX_ARCHITECTURES="${{ env.TARGET_ARCH }}" \
              -DPRO_VERSION=OFF
          cmake --build build

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

      - name: Install (${{ matrix.build-type }})
        run: |
          cmake --install build --prefix .

      - name: Deploy (${{ matrix.build-type }})
        run: |
          cd build
          plutil -insert NSRequiresAquaSystemAppearance -bool true Notes.app/Contents/Info.plist
          # Rename the app folder to "Notes Better", so it doesn't conflict with macOS' "Notes" app.
          mv Notes.app 'Notes Better.app'
          macdeployqt 'Notes Better.app' -qmldir=../src/qml -appstore-compliant

      - name: Remove unnecessary Qt plugins and libraries
        run: |
          set -x
          set -e
          cd 'build/Notes Better.app'
          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 Contents/PlugIns/bearer
          fi

      - name: Import signing certificate
        if: github.repository == 'nuttyartist/notes' && github.event_name != 'pull_request'
        run: |
          openssl base64 -d -out cert.p12 <<< '${{ secrets.MACOS_CERTIFICATE }}'
          security create-keychain -p '${{ secrets.KEYCHAIN_PWD }}' nuttyartist/notes
          security default-keychain -s nuttyartist/notes
          security unlock-keychain -p '${{ secrets.KEYCHAIN_PWD }}' nuttyartist/notes
          security -q import cert.p12 -f pkcs12 -k nuttyartist/notes -P '${{ secrets.MACOS_CERTIFICATE_PWD }}' -T /usr/bin/codesign -x
          security set-key-partition-list -S 'apple-tool:,apple:' -s -k '${{ secrets.KEYCHAIN_PWD }}' nuttyartist/notes

      - name: Sign
        if: github.repository == 'nuttyartist/notes' && github.event_name != 'pull_request'
        run: |
          codesign --deep --force --verify --verbose --sign Mamistvalove --options runtime 'build/Notes Better.app'

      - name: Build dmg (${{ matrix.build-type }})
        run: |
          cd build
          create-dmg \
              --no-internet-enable \
              --format ULFO \
              --background ../packaging/macos/dmg-background.png \
              --hide-extension 'Notes Better.app' \
              --icon 'Notes Better.app' 180 170 \
              --icon-size 160 \
              --text-size 12 \
              --volname Notes \
              --volicon ../src/images/notes_icon.icns \
              --window-size 660 400 \
              --app-drop-link 480 170 \
              '${{ steps.vars.outputs.file_name }}' \
              'Notes Better.app'

      - name: Notarize
        if: github.repository == 'nuttyartist/notes' && github.event_name != 'pull_request'
        run: |
          xcrun notarytool submit \
              --apple-id '${{ secrets.NOTARIZATION_USERNAME }}' \
              --password '${{ secrets.NOTARIZATION_PASSWORD }}' \
              --team-id '${{ secrets.NOTARIZATION_TEAM }}' \
              --wait \
              'build/${{ steps.vars.outputs.file_name }}'

      - name: Staple
        if: github.repository == 'nuttyartist/notes' && github.event_name != 'pull_request'
        run: |
          xcrun stapler staple 'build/${{ steps.vars.outputs.file_name }}'

      - name: Upload dmg 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 }}
