ci: fix notarization picking up CPack's temp.dmg instead of final DMG #65
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: CI (Linux/macOS/Windows) | |
| on: | |
| push: | |
| branches: [ main ] | |
| tags: ['v*'] | |
| release: | |
| types: [published] | |
| pull_request: | |
| permissions: | |
| contents: write | |
| jobs: | |
| build: | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| include: | |
| - os: ubuntu-latest | |
| arch: x86_64 | |
| qt_host: linux | |
| qt_arch: linux_gcc_64 | |
| - os: macos-latest | |
| arch: arm64 | |
| qt_host: mac | |
| qt_arch: clang_64 | |
| - os: windows-latest | |
| arch: x64 | |
| qt_host: windows | |
| qt_arch: win64_msvc2022_64 | |
| runs-on: ${{ matrix.os }} | |
| steps: | |
| - uses: actions/checkout@v4 | |
| with: | |
| submodules: recursive | |
| fetch-depth: 0 | |
| # Prep | |
| - name: Prep Linux | |
| if: startsWith(matrix.os, 'ubuntu-') | |
| run: | | |
| sudo apt-get update | |
| sudo apt-get install -y ninja-build | |
| - name: Prep macOS | |
| if: startsWith(matrix.os, 'macos-') | |
| run: | | |
| brew update | |
| brew install ninja || true | |
| - name: Set up MSVC (Windows) | |
| if: startsWith(matrix.os, 'windows-') | |
| uses: ilammy/msvc-dev-cmd@v1 | |
| - name: Ensure Ninja (Windows) | |
| if: startsWith(matrix.os, 'windows-') | |
| run: choco install ninja -y || echo "Ninja already present" | |
| shell: pwsh | |
| # Install OpenSSL on each platform so Qt/CMake can link against it | |
| #- name: Install OpenSSL (Linux) | |
| # if: startsWith(matrix.os, 'ubuntu-') | |
| # run: | | |
| # sudo apt-get update | |
| # # dev headers are needed for linking | |
| # sudo apt-get install -y libssl-dev openssl | |
| # # Common location for libssl headers/libs is /usr | |
| # echo "OPENSSL_ROOT=/usr" >> $GITHUB_ENV | |
| - name: Install OpenSSL (macOS) | |
| if: startsWith(matrix.os, 'macos-') | |
| run: | | |
| brew update | |
| brew install openssl@3 || true | |
| # Export prefix for use by later steps | |
| echo "OPENSSL_ROOT=$(brew --prefix openssl@3)" >> $GITHUB_ENV | |
| - name: Install OpenSSL (Windows) | |
| if: startsWith(matrix.os, 'windows-') | |
| run: | | |
| choco install openssl.light -y --params "/InstallDir:C:\OpenSSL" || echo "OpenSSL may already be installed" | |
| # Persist OPENSSL_ROOT for later CMake configure step | |
| Write-Output "OPENSSL_ROOT=C:\OpenSSL" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append | |
| shell: pwsh | |
| # Qt | |
| - name: Install Qt 6.10.2 + QtIFW | |
| uses: jurplel/install-qt-action@v4 | |
| with: | |
| version: '6.10.2' | |
| host: ${{ matrix.qt_host }} | |
| target: desktop | |
| arch: ${{ matrix.qt_arch }} | |
| cache: true | |
| aqtversion: '==3.3.*' | |
| modules: 'qthttpserver qtwebsockets qtimageformats' | |
| tools: 'tools_ifw' | |
| - name: Show versions (Unix) | |
| if: matrix.os != 'windows-latest' | |
| run: | | |
| cmake --version | |
| qmake -v || true | |
| - name: Show versions (Windows) | |
| if: startsWith(matrix.os, 'windows-') | |
| run: | | |
| cmake --version | |
| qmake -v || Write-Host "qmake not on PATH (ok)" | |
| shell: pwsh | |
| # --- Import Developer ID cert into an ephemeral keychain --- | |
| - name: Create and unlock keychain | |
| if: startsWith(matrix.os, 'macos-') | |
| run: | | |
| security create-keychain -p "$MAC_KEYCHAIN_PASSWORD" build.keychain | |
| security set-keychain-settings -lut 21600 build.keychain | |
| security unlock-keychain -p "$MAC_KEYCHAIN_PASSWORD" build.keychain | |
| security list-keychains -s build.keychain login.keychain | |
| env: | |
| MAC_KEYCHAIN_PASSWORD: ${{ secrets.MAC_KEYCHAIN_PASSWORD }} | |
| - name: Import Developer ID certificate (macOS) | |
| if: startsWith(matrix.os, 'macos-') | |
| run: | | |
| base64 -d <<< "$MAC_CERT_P12" > dev.p12 | |
| security import dev.p12 -k build.keychain -P "$MAC_CERT_P12_PASSWORD" -T /usr/bin/codesign -T /usr/bin/security | |
| # Allow codesign to use the key non-interactively: | |
| security set-key-partition-list -S apple-tool:,apple:,codesign: -s -k "$MAC_KEYCHAIN_PASSWORD" build.keychain | |
| rm -f dev.p12 | |
| env: | |
| MAC_CERT_P12: ${{ secrets.MAC_CERT_P12 }} | |
| MAC_CERT_P12_PASSWORD: ${{ secrets.MAC_CERT_P12_PASSWORD }} | |
| MAC_KEYCHAIN_PASSWORD: ${{ secrets.MAC_KEYCHAIN_PASSWORD }} | |
| - name: Write App Store Connect API key (macOS) | |
| if: startsWith(matrix.os, 'macos-') | |
| run: | | |
| set -euo pipefail | |
| mkdir -p $HOME/.private_keys | |
| echo "$AC_API_KEY_P8" | base64 -d > $HOME/.private_keys/AuthKey_${AC_API_KEY_ID}.p8 | |
| chmod 600 $HOME/.private_keys/AuthKey_${AC_API_KEY_ID}.p8 | |
| env: | |
| AC_API_KEY_P8: ${{ secrets.AC_API_KEY_P8 }} | |
| AC_API_KEY_ID: ${{ secrets.AC_API_KEY_ID }} | |
| # Configure | |
| - name: Configure (Linux) | |
| if: startsWith(matrix.os, 'ubuntu-') | |
| run: | | |
| cmake -S src -B build-Release -G Ninja \ | |
| -DCMAKE_BUILD_TYPE=Release \ | |
| -DOPENSSL_ROOT_DIR="$OPENSSL_ROOT" | |
| env: | |
| OPENSSL_ROOT: ${{ env.OPENSSL_ROOT }} | |
| - name: Configure (macOS) | |
| if: startsWith(matrix.os, 'macos-') | |
| run: | | |
| cmake -S src -B build-Release -G Ninja \ | |
| -DCMAKE_BUILD_TYPE=Release \ | |
| -DCODESIGN_ID="$CODESIGN_ID" \ | |
| -DOPENSSL_ROOT_DIR="$OPENSSL_ROOT" | |
| env: | |
| CODESIGN_ID: ${{ secrets.CODESIGN_ID }} | |
| OPENSSL_ROOT: ${{ env.OPENSSL_ROOT }} | |
| - name: Configure (Windows) | |
| if: startsWith(matrix.os, 'windows-') | |
| run: | | |
| cmake -S src -B build-Release -G Ninja -DCMAKE_BUILD_TYPE=Release -DOPENSSL_ROOT_DIR="$env:OPENSSL_ROOT" | |
| shell: pwsh | |
| # Build | |
| - name: Build (Unix) | |
| if: matrix.os != 'windows-latest' | |
| run: cmake --build build-Release --target package --parallel | |
| - name: Build (Windows) | |
| if: startsWith(matrix.os, 'windows-') | |
| run: cmake --build build-Release --target package --parallel | |
| shell: pwsh | |
| # Notarize | |
| - name: Notarize DMG with notarytool (macOS) | |
| if: startsWith(matrix.os, 'macos-') | |
| run: | | |
| set -euo pipefail | |
| DMG="$(/usr/bin/find build-Release -maxdepth 1 -name '*.dmg' -print -quit)" | |
| echo "DMG: $DMG" | |
| JSON_OUT="$(mktemp)" | |
| xcrun notarytool submit "$DMG" \ | |
| --key "$HOME/.private_keys/AuthKey_${AC_API_KEY_ID}.p8" \ | |
| --key-id "$AC_API_KEY_ID" \ | |
| --issuer "$AC_API_ISSUER_ID" \ | |
| --wait --timeout 20m --output-format json > "$JSON_OUT" | |
| echo "Notarytool output:" | |
| cat "$JSON_OUT" | |
| # Extract submission id and status using plutil (built-in) | |
| SUBMISSION_ID=$(plutil -extract id raw -o - "$JSON_OUT") | |
| STATUS=$(plutil -extract status raw -o - "$JSON_OUT" 2>/dev/null || echo "") | |
| echo "Submission ID: $SUBMISSION_ID" | |
| echo "Status: $STATUS" | |
| # Always fetch and print the full log (super helpful when rejected) | |
| xcrun notarytool log "$SUBMISSION_ID" \ | |
| --key "$HOME/.private_keys/AuthKey_${AC_API_KEY_ID}.p8" \ | |
| --key-id "$AC_API_KEY_ID" \ | |
| --issuer "$AC_API_ISSUER_ID" || true | |
| # Hard fail unless Accepted | |
| if [[ "$STATUS" != "Accepted" ]]; then | |
| echo "Notarization did not succeed (status=$STATUS). Aborting before staple." | |
| exit 1 | |
| fi | |
| env: | |
| AC_API_KEY_ID: ${{ secrets.AC_API_KEY_ID }} | |
| AC_API_ISSUER_ID: ${{ secrets.AC_API_ISSUER_ID }} | |
| - name: macOS – staple | |
| if: startsWith(matrix.os, 'macos-') | |
| run: | | |
| set -euo pipefail | |
| DMG="$(/usr/bin/find build-Release -maxdepth 1 -name '*.dmg' -print -quit)" | |
| xcrun stapler staple "$DMG" | |
| # Optional: also staple the app (useful if you ever upload the .app directly) | |
| APP_BUNDLE="$(/usr/bin/find build-Release -name '*.app' -maxdepth 2 -print -quit)" | |
| xcrun stapler staple "$APP_BUNDLE" || true | |
| # Artifacts | |
| - name: Upload packages | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: ${{ github.event.repository.name }}-${{ matrix.os }}-${{ matrix.arch }}-packages | |
| path: | | |
| build-Release/${{ github.event.repository.name }}-*.deb | |
| build-Release/${{ github.event.repository.name }}-*.rpm | |
| build-Release/${{ github.event.repository.name }}-*.dmg | |
| build-Release/${{ github.event.repository.name }}-*.exe | |
| if-no-files-found: error | |
| release: | |
| name: Publish GitHub Release | |
| if: github.event_name == 'release' || startsWith(github.ref, 'refs/tags/') | |
| needs: [build] | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Download build artifacts | |
| uses: actions/download-artifact@v4 | |
| with: | |
| pattern: ${{ github.event.repository.name }}-*packages | |
| merge-multiple: true | |
| path: artifacts | |
| - name: List files | |
| run: ls -lah artifacts | |
| - name: Create Release & upload assets | |
| uses: softprops/action-gh-release@v2 | |
| with: | |
| # Mark RC/Beta as prerelease automatically (optional) | |
| prerelease: ${{ contains(github.ref_name, '-rc') || contains(github.ref_name, '-beta') }} | |
| files: artifacts/* | |
| - name: Prepare Range Cloud client key and certificate | |
| run: | | |
| set -euo pipefail | |
| mkdir -p $HOME/.private_keys | |
| echo "$RANGE_CLOUD_KEY_PEM" | base64 -d > $HOME/.private_keys/range_cloud_key.pem | |
| chmod 600 $HOME/.private_keys/range_cloud_key.pem | |
| echo "$RANGE_CLOUD_CERT_PEM" | base64 -d > $HOME/.private_keys/range_cloud_cert.pem | |
| chmod 600 $HOME/.private_keys/range_cloud_cert.pem | |
| env: | |
| RANGE_CLOUD_KEY_PEM: ${{ secrets.RANGE_CLOUD_KEY_PEM }} | |
| RANGE_CLOUD_CERT_PEM: ${{ secrets.RANGE_CLOUD_CERT_PEM }} | |
| - name: Publish on Range Cloud | |
| run: | | |
| set -euo pipefail | |
| for f in artifacts/*; do | |
| [ -f "$f" ] || continue | |
| fileName="$(basename $f)" | |
| fileInfo=${fileName#$REPO_NAME} | |
| fileVersion=$(echo $fileInfo | cut -d'-' -f2) | |
| fileOs=$(echo $fileInfo | cut -d'-' -f3) | |
| fileArch=$(echo $fileInfo | cut -d'-' -f4 | cut -d'.' -f1) | |
| echo "Uploading: $fileName" | |
| curl -X PUT --upload-file $f -o $HOME/response.json --key $HOME/.private_keys/range_cloud_key.pem --key-type PEM --pass 12345678 --cert $HOME/.private_keys/range_cloud_cert.pem https://range-software.com:4012/file-replace/?resource-name=$fileName | |
| fileId=$(jq -r '.upload.id' $HOME/response.json) | |
| echo "Updating file access mode: $fileName : 644" | |
| curl -X POST -d "{\"user\":6,\"group\":4,\"other\":4}" --key $HOME/.private_keys/range_cloud_key.pem --key-type PEM --pass 12345678 --cert $HOME/.private_keys/range_cloud_cert.pem https://range-software.com:4012/file-update-access-mode/?resource-id=$fileId | |
| echo "Updating file version: $fileName : $fileVersion" | |
| curl -X POST -d "$fileVersion" --key $HOME/.private_keys/range_cloud_key.pem --key-type PEM --pass 12345678 --cert $HOME/.private_keys/range_cloud_cert.pem https://range-software.com:4012/file-update-version/?resource-id=$fileId | |
| echo "Updating file tags: $fileName : $REPO_NAME,$fileOs,$fileArch" | |
| curl -X POST -d "$REPO_NAME,$fileOs,$fileArch" --key $HOME/.private_keys/range_cloud_key.pem --key-type PEM --pass 12345678 --cert $HOME/.private_keys/range_cloud_cert.pem https://range-software.com:4012/file-update-tags/?resource-id=$fileId | |
| done | |
| env: | |
| RANGE_CLOUD_KEY_PASSWORD: ${{ secrets.RANGE_CLOUD_KEY_PASSWORD }} | |
| REPO_NAME: ${{ github.event.repository.name }} |