diff --git a/.github/workflows/ios.yml b/.github/workflows/ios.yml index 9035ee1532..6199734334 100644 --- a/.github/workflows/ios.yml +++ b/.github/workflows/ios.yml @@ -99,7 +99,7 @@ jobs: xcode-version: latest-stable - name: 🍮 ccache - uses: hendrikmuhs/ccache-action@v1.2.11 + uses: hendrikmuhs/ccache-action@v1 if: ${{ env.SENTRY_AUTH_TOKEN != '' }} with: key: ccache-ios diff --git a/.github/workflows/macos.yml b/.github/workflows/macos.yml index ee853d7a88..34c9ad0e16 100644 --- a/.github/workflows/macos.yml +++ b/.github/workflows/macos.yml @@ -55,26 +55,12 @@ jobs: with: ssh-private-key: ${{ secrets.SSH_KEY_DEPLOYMENT_CERTIFICATES }} - - name: 💎 Setup ruby - uses: ruby/setup-ruby@v1 - with: - ruby-version: '3.2' # Not needed with a .ruby-version file - bundler-cache: true # runs 'bundle install' and caches installed gems automatically - - - name: 🔏 Setup code signing - if: ${{ env.SENTRY_AUTH_TOKEN != '' }} - env: - MATCH_PASSWORD: ${{ secrets.MATCH_PASSWORD }} - run: | - bundle install - bundle exec fastlane ios setup_signing type:development app_identifier:ch.opengis.qfield # --verbose - - name: 🐩 Install CMake and Ninja uses: lukka/get-cmake@latest - name: 🔨 Prepare build env run: | - brew install automake bison flex gnu-sed create-dmg autoconf-archive nasm libtool + brew install automake bison flex gnu-sed autoconf-archive nasm libtool xcbeautify echo $(brew --prefix bison)/bin >> $GITHUB_PATH echo $(brew --prefix flex)/bin >> $GITHUB_PATH echo $(brew --prefix libtool)/bin >> $GITHUB_PATH @@ -89,7 +75,7 @@ jobs: xcode-version: latest-stable - name: 🍮 ccache - uses: hendrikmuhs/ccache-action@v1.2.11 + uses: hendrikmuhs/ccache-action@v1 with: key: ccache-${{ matrix.triplet }}-qt6 max-size: 200M @@ -128,7 +114,8 @@ jobs: run: | # https://www.reddit.com/r/MacOS/comments/f37ybt/osascript_cant_open_default_scripting_component/?utm_medium=android_app&utm_source=share sudo rm -rf /Library/Audio/Plug-Ins/Components - cmake --build "${{ env.CMAKE_BUILD_DIR }}" --config ${{ env.BUILD_TYPE }} + set -o pipefail + cmake --build "${{ env.CMAKE_BUILD_DIR }}" --config ${{ env.BUILD_TYPE }} | xcbeautify - name: 🧫 Test env: @@ -139,20 +126,15 @@ jobs: cd "${{ env.CMAKE_BUILD_DIR }}" ctest --output-on-failure -R smoke -C ${{ env.BUILD_TYPE }} - - name: 📦 Package - env: - MATCH_PASSWORD: ${{ secrets.MATCH_PASSWORD }} + - name: 📦 Prepackage run: | - echo "Killing XProtect..."; sudo pkill -9 XProtect >/dev/null || true; # see https://github.com/actions/runner-images/issues/7522 - cmake --build "${{ env.CMAKE_BUILD_DIR }}" --target bundle --config ${{ env.BUILD_TYPE }} - echo "ARTIFACT_PATHNAME=${{ env.CMAKE_BUILD_DIR }}/QField-Installer.dmg" >> $GITHUB_ENV - echo "ARTIFACT_NAME=qfield-${{ env.CI_PACKAGE_FILE_SUFFIX }}-${{ matrix.triplet }}.dmg" >> $GITHUB_ENV + DESTDIR=staging cmake --install "${{ env.CMAKE_BUILD_DIR }}" --config ${{ env.BUILD_TYPE }} - name: 📦 Upload package uses: actions/upload-artifact@v4 with: - name: "QField-dev-${{ matrix.triplet }}-experimental-qt6" - path: ${{ env.CMAKE_BUILD_DIR }}/QField-Installer.dmg + name: "qfield-app-${{ matrix.triplet }}" + path: staging - name: 📊 Upload test report if: always() @@ -161,15 +143,6 @@ jobs: name: "test-report-${{ matrix.triplet }}-${{ env.BUILD_TYPE }}" path: "${{ env.CMAKE_BUILD_DIR }}/report" - - name: 🚀 Upload release asset - if: github.event_name == 'release' && startsWith(github.ref, 'refs/tags/v') && env.ARTIFACT_NAME != null - uses: shogo82148/actions-upload-release-asset@v1 - with: - upload_url: ${{ github.event.release.upload_url }} - asset_path: ${{ env.ARTIFACT_PATHNAME }} - asset_name: ${{ env.ARTIFACT_NAME }} - overwrite: true - - name: 📑 Upload logs uses: actions/upload-artifact@v4 if: failure() @@ -178,6 +151,12 @@ jobs: path: | ${{ env.CMAKE_BUILD_DIR }}/**/*.log + - name: 💎 Setup ruby + uses: ruby/setup-ruby@v1 + with: + ruby-version: '3.2' # Not needed with a .ruby-version file + bundler-cache: true # runs 'bundle install' and caches installed gems automatically + - name: 📮 Upload debug symbols if: ${{ env.SENTRY_AUTH_TOKEN != '' }} # if: release or labeled PR @@ -186,4 +165,61 @@ jobs: SENTRY_ORG_SLUG: opengisch SENTRY_PROJECT_SLUG: qfield run: | - bundle exec fastlane run sentry_debug_files_upload path:${{ env.CMAKE_BUILD_DIR }} + bundle exec fastlane run sentry_debug_files_upload path:${{ env.CMAKE_BUILD_DIR }}/output/bin/qfield.app + + create-dmg: + name: Create dmg + runs-on: macos-15 + needs: build + steps: + - name: 🐣 Checkout + uses: actions/checkout@v4 + + - name: 🔨 Prepare build env + run: | + brew install create-dmg + + - name: 📤 Download app + uses: actions/download-artifact@v4 + with: + pattern: qfield-app-* + path: | + artifacts + + - name: Create universal app + run: | + wget https://raw.githubusercontent.com/faaxm/lipo-dir-merge/refs/heads/main/lipo-dir-merge.py + python lipo-dir-merge.py ./artifacts/qfield-app-x64-osx ./artifacts/qfield-app-arm64-osx universal + + - name: Create dmg + run: | + if [[ "${{ github.event_name }}" == "release" && "${{ github.ref }}" == refs/tags/v* ]]; then + echo "${{ secrets.APPLE_DEVELOPER_ID_P12_BASE64 }}" | base64 --decode > cert.p12 + export P12_PATH=cert.p12 + export P12_PASSWORD=${{ secrets.APPLE_DEVELOPER_ID_P12_PASSWORD }} + export API_KEY_ID=${{ secrets.IOS_APPSTORE_KEY_ID }} + export API_KEY_ISSUER_ID=${{ secrets.IOS_APPSTORE_ISSUER_ID }} + echo "${{ secrets.IOS_APPSTORE_PRIVATE_KEY }}" > authkey.p8 + export API_KEY_PATH=authkey.p8 + fi + + export APP_PATH=$(pwd)/universal/usr/local/bin/qfield.app + export DMG_PATH=qfield.dmg + ./platform/macos/create_dmg.sh + + - name: 📤 Upload app + uses: actions/upload-artifact@v4 + id: artifact-mac-qt6 + with: + name: qfield-dmg + path: | + *.dmg + + - name: 🚀 Upload release asset + if: github.event_name == 'release' && startsWith(github.ref, 'refs/tags/v') + uses: shogo82148/actions-upload-release-asset@v1 + with: + upload_url: ${{ github.event.release.upload_url }} + asset_path: "qfield.dmg" + asset_name: qfield-${{ github.ref_name }}-macos.dmg + overwrite: true diff --git a/platform/macos/create_dmg.sh b/platform/macos/create_dmg.sh new file mode 100755 index 0000000000..ff4a1f9c85 --- /dev/null +++ b/platform/macos/create_dmg.sh @@ -0,0 +1,55 @@ +#!/bin/bash +set -euo pipefail + +# Required environment variables: +# APP_PATH: Path to your .app bundle +# DMG_PATH: Path to your .dmg file +# P12_PATH: Path to your .p12 certificate file +# P12_PASSWORD: Password for the .p12 file +# API_KEY_ID: App Store Connect API Key ID +# API_KEY_ISSUER_ID: App Store Connect API Key Issuer ID +# API_KEY_PATH: Path to the API key file (.p8) + +if [[ -n ${API_KEY_ID:-} ]]; then + KEYCHAIN_NAME="notary-keychain" + KEYCHAIN_PASSWORD="temp-password" + security create-keychain -p "$KEYCHAIN_PASSWORD" "$KEYCHAIN_NAME" + security unlock-keychain -p "$KEYCHAIN_PASSWORD" "$KEYCHAIN_NAME" + security import "$P12_PATH" -k "$KEYCHAIN_NAME" -P "$P12_PASSWORD" -T /usr/bin/codesign + security set-keychain-settings -t 3600 -l "$KEYCHAIN_NAME" + security list-keychains -d user -s "$KEYCHAIN_NAME" $(security list-keychains -d user | tr -d '"') + security set-key-partition-list -S apple-tool:,apple:,codesign: -s -k "$KEYCHAIN_PASSWORD" "$KEYCHAIN_NAME" + + # Sign the .app bundle + codesign --force --options runtime --sign "Developer ID Application" --deep --keychain "$KEYCHAIN_NAME" "$APP_PATH" +fi + +create-dmg --volname "QField Installer" \ + --hide-extension "qfield.app" \ + --volicon "./platform/macos/installer.icns" \ + --background "./platform/macos/installer_background.png" \ + --window-pos 200 120 \ + --window-size 512 320 \ + --icon-size 100 \ + --icon "qfield.app" 130 160 \ + --app-drop-link 400 155 \ + "$DMG_PATH" "$APP_PATH" + +if [[ -n ${API_KEY_ID:-} ]]; then + codesign --force --options runtime --sign "Developer ID Application" --keychain "$KEYCHAIN_NAME" "$DMG_PATH" + + echo "Submitting for notarization..." + xcrun notarytool submit "$DMG_PATH" \ + --key "$API_KEY_PATH" \ + --key-id "$API_KEY_ID" \ + --issuer "$API_KEY_ISSUER_ID" \ + --wait + + # Staple the notarization ticket + xcrun stapler staple "$DMG_PATH" + + # Clean up keychain + security delete-keychain "$KEYCHAIN_NAME" + + echo "Notarization and stapling complete!" +fi