Build Release Package for macOS #10
Workflow file for this run
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
| # Release workflow for macOS | |
| # Builds a universal binary on macOS. | |
| name: Build Release Package for macOS | |
| on: | |
| workflow_dispatch: | |
| workflow_call: | |
| secrets: | |
| MACOS_CERTIFICATE_APPLICATION: | |
| required: true | |
| MACOS_CERTIFICATE_INSTALLER: | |
| required: true | |
| MACOS_CERTIFICATE_PASSWORD: | |
| required: true | |
| MACOS_NOTARY_API_KEY: | |
| required: true | |
| MACOS_NOTARY_KEY_ID: | |
| required: true | |
| MACOS_NOTARY_ISSUER_ID: | |
| required: true | |
| jobs: | |
| build-pkg: | |
| name: ProductBuild Installer, macOS x86_64+arm64 | |
| runs-on: macos-latest | |
| steps: | |
| # We need to build third-party libraries (POCO, SDL2 and projectM) ourselves, as neither Homebrew | |
| # nor vcpkg support building universal binaries. | |
| - name: Checkout libSDL2 Sources | |
| uses: actions/checkout@v4 | |
| with: | |
| repository: libsdl-org/SDL | |
| path: libsdl2 | |
| ref: 'release-2.32.10' | |
| submodules: recursive | |
| - name: Build libSDL2 | |
| run: | | |
| mkdir cmake-build-libsdl2 | |
| cmake -G Ninja -S libsdl2 -B cmake-build-libsdl2 \ | |
| '-DCMAKE_OSX_ARCHITECTURES=x86_64;arm64' \ | |
| -DBUILD_SHARED_LIBS=ON \ | |
| -DCMAKE_BUILD_TYPE=Release \ | |
| -DCMAKE_INSTALL_PREFIX=${{ github.workspace }}/install-libsdl2 | |
| cmake --build cmake-build-libsdl2 --parallel | |
| cmake --install "${{ github.workspace }}/cmake-build-libsdl2" | |
| - name: Checkout Poco Sources | |
| uses: actions/checkout@v4 | |
| with: | |
| repository: pocoproject/poco | |
| path: poco | |
| ref: 'poco-1.14.1' | |
| submodules: recursive | |
| - name: Build Poco | |
| run: | | |
| mkdir cmake-build-poco | |
| cmake -G Ninja -S poco -B cmake-build-poco \ | |
| '-DCMAKE_OSX_ARCHITECTURES=x86_64;arm64' \ | |
| -DBUILD_SHARED_LIBS=ON \ | |
| -DCMAKE_BUILD_TYPE=Release \ | |
| -DCMAKE_INSTALL_PREFIX=${{ github.workspace }}/install-poco \ | |
| -DENABLE_CRYPTO=OFF \ | |
| -DENABLE_NET=OFF \ | |
| -DENABLE_NETSSL=OFF \ | |
| -DENABLE_ZIP=OFF \ | |
| -DENABLE_MONGODB=OFF \ | |
| -DENABLE_REDIS=OFF \ | |
| -DENABLE_PAGECOMPILER=OFF \ | |
| -DENABLE_PAGECOMPILER_FILE2PAGE=OFF \ | |
| -DENABLE_ACTIVERECORD=OFF \ | |
| -DENABLE_ACTIVERECORD_COMPILER=OFF \ | |
| -DENABLE_DATA_ODBC=OFF \ | |
| -DENABLE_DATA_POSTGRESQL=OFF \ | |
| -DENABLE_DATA_MYSQL=OFF \ | |
| -DENABLE_JWT=OFF \ | |
| -DENABLE_PROMETHEUS=OFF | |
| cmake --build cmake-build-poco --parallel | |
| cmake --install "${{ github.workspace }}/cmake-build-poco" | |
| - name: Checkout libprojectM Sources | |
| uses: actions/checkout@v4 | |
| with: | |
| repository: projectM-visualizer/projectm | |
| path: projectm | |
| submodules: recursive | |
| - name: Build/Install libprojectM | |
| run: | | |
| mkdir cmake-build-libprojectm | |
| cmake -G Ninja -S projectm -B cmake-build-libprojectm \ | |
| '-DCMAKE_OSX_ARCHITECTURES=x86_64;arm64' \ | |
| -DBUILD_SHARED_LIBS=OFF \ | |
| -DCMAKE_BUILD_TYPE=Release \ | |
| -DCMAKE_INSTALL_PREFIX=${{ github.workspace }}/install-libprojectm | |
| cmake --build cmake-build-libprojectm --parallel | |
| cmake --install "${{ github.workspace }}/cmake-build-libprojectm" | |
| - name: Checkout projectMSDL Sources | |
| uses: actions/checkout@v4 | |
| with: | |
| path: frontend-sdl2 | |
| submodules: recursive | |
| - name: Checkout Cream of the Crop preset pack | |
| uses: actions/checkout@v4 | |
| with: | |
| repository: projectM-visualizer/presets-cream-of-the-crop | |
| path: presets-cream-of-the-crop | |
| - name: Checkout Milkdrop Texture Pack | |
| uses: actions/checkout@v4 | |
| with: | |
| repository: projectM-visualizer/presets-milkdrop-texture-pack | |
| path: presets-milkdrop-texture-pack | |
| - name: Import Code Signing Certificates | |
| env: | |
| MACOS_CERTIFICATE_APPLICATION: ${{ secrets.MACOS_CERTIFICATE_APPLICATION }} | |
| MACOS_CERTIFICATE_INSTALLER: ${{ secrets.MACOS_CERTIFICATE_INSTALLER }} | |
| MACOS_CERTIFICATE_PASSWORD: ${{ secrets.MACOS_CERTIFICATE_PASSWORD }} | |
| run: | | |
| echo "$MACOS_CERTIFICATE_APPLICATION" | base64 --decode > app_cert.p12 && chmod 600 app_cert.p12 | |
| echo "$MACOS_CERTIFICATE_INSTALLER" | base64 --decode > installer_cert.p12 && chmod 600 installer_cert.p12 | |
| KEYCHAIN_PASSWORD=$(openssl rand -base64 32) | |
| security create-keychain -p "$KEYCHAIN_PASSWORD" build.keychain | |
| security default-keychain -s build.keychain | |
| security unlock-keychain -p "$KEYCHAIN_PASSWORD" build.keychain | |
| security import app_cert.p12 -k build.keychain -P "$MACOS_CERTIFICATE_PASSWORD" -T /usr/bin/codesign | |
| security import installer_cert.p12 -k build.keychain -P "$MACOS_CERTIFICATE_PASSWORD" -T /usr/bin/productsign | |
| security set-key-partition-list -S apple-tool:,apple:,codesign:,productbuild: -s -k "$KEYCHAIN_PASSWORD" build.keychain | |
| rm app_cert.p12 installer_cert.p12 | |
| - name: Build projectMSDL | |
| run: | | |
| mkdir cmake-build-frontend-sdl2 | |
| cmake -G Xcode -S frontend-sdl2 -B cmake-build-frontend-sdl2 \ | |
| '-DCMAKE_OSX_ARCHITECTURES=x86_64;arm64' \ | |
| -DCMAKE_BUILD_TYPE=Release \ | |
| -DENABLE_FREETYPE=OFF \ | |
| "-DCMAKE_PREFIX_PATH=${GITHUB_WORKSPACE}/install-libprojectm;${GITHUB_WORKSPACE}/install-poco;${GITHUB_WORKSPACE}/install-libsdl2" \ | |
| "-DPRESET_DIRS=${{ github.workspace }}/presets-cream-of-the-crop" \ | |
| "-DTEXTURE_DIRS=${{ github.workspace }}/presets-milkdrop-texture-pack/textures" \ | |
| -DENABLE_INSTALL_BDEPS=ON | |
| cmake --build cmake-build-frontend-sdl2 --parallel | |
| cmake --install cmake-build-frontend-sdl2 --prefix "${{ github.workspace }}/install" | |
| - name: Sign Application Bundle | |
| run: | | |
| APP_PATH="${{ github.workspace }}/install/projectM.app" | |
| IDENTITY="Developer ID Application: Mischa Spiegelmock (5926VBQM6Y)" | |
| ENTITLEMENTS="${{ github.workspace }}/frontend-sdl2/src/resources/projectMSDL.entitlements" | |
| # Sign frameworks first (SDL2, Poco, etc.) | |
| if [ -d "$APP_PATH/Contents/Frameworks" ]; then | |
| find "$APP_PATH/Contents/Frameworks" \( -name "*.dylib" -o -name "*.framework" \) -exec \ | |
| codesign --force --options runtime --sign "$IDENTITY" {} \; | |
| fi | |
| # Sign plugins if present | |
| if [ -d "$APP_PATH/Contents/PlugIns" ]; then | |
| find "$APP_PATH/Contents/PlugIns" -name "*.dylib" -exec \ | |
| codesign --force --options runtime --sign "$IDENTITY" {} \; | |
| fi | |
| # Sign the main executable with entitlements | |
| codesign --force --options runtime --entitlements "$ENTITLEMENTS" --sign "$IDENTITY" \ | |
| "$APP_PATH/Contents/MacOS/projectM" | |
| # Sign the entire bundle with entitlements | |
| codesign --force --options runtime --entitlements "$ENTITLEMENTS" --sign "$IDENTITY" "$APP_PATH" | |
| # Verify | |
| codesign --verify --deep --strict "$APP_PATH" | |
| - name: Notarize Application Bundle | |
| env: | |
| API_KEY_BASE64: ${{ secrets.MACOS_NOTARY_API_KEY }} | |
| API_KEY_ID: ${{ secrets.MACOS_NOTARY_KEY_ID }} | |
| API_ISSUER_ID: ${{ secrets.MACOS_NOTARY_ISSUER_ID }} | |
| run: | | |
| mkdir -p ~/.private_keys | |
| echo "$API_KEY_BASE64" | base64 --decode > ~/.private_keys/AuthKey_${API_KEY_ID}.p8 | |
| chmod 600 ~/.private_keys/AuthKey_${API_KEY_ID}.p8 | |
| ditto -c -k --keepParent \ | |
| "${{ github.workspace }}/install/projectM.app" \ | |
| "projectM-notarize.zip" | |
| xcrun notarytool submit "projectM-notarize.zip" \ | |
| --key ~/.private_keys/AuthKey_${API_KEY_ID}.p8 \ | |
| --key-id "$API_KEY_ID" \ | |
| --issuer "$API_ISSUER_ID" \ | |
| --wait | |
| xcrun stapler staple "${{ github.workspace }}/install/projectM.app" | |
| - name: Upload .app Bundle Artifact | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: projectMSDL-macOS-Universal-APP | |
| path: install/projectM.app/ | |
| - name: Create projectMSDL PKG Installer | |
| run: | | |
| # Get version from CMake cache | |
| VERSION=$(grep 'CMAKE_PROJECT_VERSION:STATIC=' cmake-build-frontend-sdl2/CMakeCache.txt | grep -Eo '([0-9.]+)') | |
| # Build component package from signed app | |
| pkgbuild \ | |
| --root "${{ github.workspace }}/install" \ | |
| --identifier "org.projectm-visualizer.projectmsdl" \ | |
| --version "$VERSION" \ | |
| --install-location "/Applications" \ | |
| --component-plist "frontend-sdl2/src/resources/projectMSDL-component.plist" \ | |
| "projectMSDL-component.pkg" | |
| # Build unsigned product archive | |
| productbuild \ | |
| --distribution "frontend-sdl2/src/resources/distribution.xml" \ | |
| --package-path "." \ | |
| --resources "frontend-sdl2/src/resources" \ | |
| "projectM-${VERSION}-macOS-universal-unsigned.pkg" | |
| # Sign the package with productsign | |
| productsign \ | |
| --sign "Developer ID Installer: Mischa Spiegelmock (5926VBQM6Y)" \ | |
| "projectM-${VERSION}-macOS-universal-unsigned.pkg" \ | |
| "projectM-${VERSION}-macOS-universal.pkg" | |
| rm "projectM-${VERSION}-macOS-universal-unsigned.pkg" | |
| - name: Notarize PKG Installer | |
| env: | |
| API_KEY_ID: ${{ secrets.MACOS_NOTARY_KEY_ID }} | |
| API_ISSUER_ID: ${{ secrets.MACOS_NOTARY_ISSUER_ID }} | |
| run: | | |
| PKG_FILE=$(ls projectM-*.pkg | head -1) | |
| xcrun notarytool submit "$PKG_FILE" \ | |
| --key ~/.private_keys/AuthKey_${API_KEY_ID}.p8 \ | |
| --key-id "$API_KEY_ID" \ | |
| --issuer "$API_ISSUER_ID" \ | |
| --wait | |
| xcrun stapler staple "$PKG_FILE" | |
| # Clean up API key | |
| rm -f ~/.private_keys/AuthKey_${API_KEY_ID}.p8 | |
| - name: Upload PKG Installer Artifact | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: projectMSDL-macOS-Universal-PKG | |
| path: projectM-*.pkg | |
| - name: Create projectMSDL DMG Image | |
| run: | | |
| # Get version from CMake cache | |
| VERSION=$(grep 'CMAKE_PROJECT_VERSION:STATIC=' cmake-build-frontend-sdl2/CMakeCache.txt | grep -Eo '([0-9.]+)') | |
| # Install create-dmg | |
| brew install create-dmg | |
| # Build and sign DMG image | |
| create-dmg \ | |
| --volname "projectM Installer" \ | |
| --volicon "frontend-sdl2/src/resources/icons/icon.icns" \ | |
| --background "frontend-sdl2/src/resources/dmg_background.png" \ | |
| --window-pos 200 120 \ | |
| --window-size 800 400 \ | |
| --icon-size 100 \ | |
| --icon "projectM.app" 200 190 \ | |
| --hide-extension "projectM.app" \ | |
| --app-drop-link 600 185 \ | |
| --codesign "Developer ID Application: Mischa Spiegelmock (5926VBQM6Y)" \ | |
| "projectM-${VERSION}-macOS-universal.dmg" \ | |
| "install/" | |
| - name: Notarize DMG Installer | |
| env: | |
| API_KEY_ID: ${{ secrets.MACOS_NOTARY_KEY_ID }} | |
| API_ISSUER_ID: ${{ secrets.MACOS_NOTARY_ISSUER_ID }} | |
| run: | | |
| DMG_FILE=$(ls projectM-*.dmg | head -1) | |
| xcrun notarytool submit "$DMG_FILE" \ | |
| --key ~/.private_keys/AuthKey_${API_KEY_ID}.p8 \ | |
| --key-id "$API_KEY_ID" \ | |
| --issuer "$API_ISSUER_ID" \ | |
| --wait | |
| xcrun stapler staple "$DMG_FILE" | |
| # Clean up API key | |
| rm -f ~/.private_keys/AuthKey_${API_KEY_ID}.p8 | |
| - name: Upload DMG Installer Artifact | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: projectMSDL-macOS-Universal-DMG | |
| path: projectM-*.dmg |