Publish snapshot builds #87
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: Publish (Snapshot) | |
| run-name: Publish snapshot builds | |
| on: | |
| # schedule: | |
| # - cron: '0 4 * * 1' | |
| workflow_dispatch: | |
| inputs: | |
| iteration: | |
| description: The iteration of the snapshot | |
| required: true | |
| default: 'a' | |
| defaults: | |
| run: | |
| shell: bash | |
| jobs: | |
| metadata: | |
| name: Retrieve metadata | |
| runs-on: ubuntu-22.04 | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@v6 | |
| - name: Specify version | |
| id: version | |
| run: echo "VERSION=$(jq -r '.version' package.json)" >> $GITHUB_OUTPUT | |
| - name: Specify current week | |
| id: current-week | |
| run: echo "CURRENT_WEEK=$(date +'%yw%V')" >> $GITHUB_OUTPUT | |
| outputs: | |
| version: ${{ steps.version.outputs.VERSION }} | |
| current-week: ${{ steps.current-week.outputs.CURRENT_WEEK }}${{ github.event.inputs.iteration || 'a' }} | |
| version-name: ${{ steps.version.outputs.VERSION }}_${{ steps.current-week.outputs.CURRENT_WEEK }}${{ github.event.inputs.iteration || 'a' }} | |
| publish-capacitor-android: | |
| name: Build for Android | |
| runs-on: ubuntu-22.04 | |
| needs: metadata | |
| permissions: | |
| contents: write | |
| steps: | |
| - name: Confirm build version and datetime | |
| run: | | |
| echo "Version: ${{ needs.metadata.outputs.version }}" | |
| echo "Build datetime: ${{ needs.metadata.outputs.current-week }}" | |
| - name: Checkout | |
| uses: actions/checkout@v6 | |
| - name: Setup Node.js | |
| uses: actions/setup-node@v6 | |
| with: | |
| node-version: lts/* | |
| - name: Setup pnpm | |
| uses: pnpm/action-setup@v4 | |
| - name: Setup Java | |
| uses: actions/setup-java@v5 | |
| with: | |
| distribution: 'zulu' | |
| java-version: '21' | |
| - name: Install dependencies | |
| run: pnpm i | |
| - name: Create build | |
| run: pnpm build | |
| env: | |
| PUBLIC_SENTRY_DSN: ${{ vars.PUBLIC_SENTRY_DSN }} | |
| - name: Generate icons and splash screen | |
| run: if [ -d "./resources" ]; then pnpm i -D @capacitor/assets && pnpm capacitor-assets generate --android; fi | |
| - name: Build app bundle | |
| run: cd android && chmod +x ./gradlew && ./gradlew bundle && ./gradlew assembleRelease | |
| - uses: kevin-david/zipalign-sign-android-release@v2 | |
| name: Sign APK | |
| id: sign-apk | |
| with: | |
| releaseDirectory: android/app/build/outputs/apk/release/ | |
| signingKeyBase64: ${{ secrets.RELEASE_KEYSTORE }} | |
| keyStorePassword: ${{ secrets.RELEASE_KEYSTORE_PASSWORD }} | |
| zipAlign: true | |
| env: | |
| BUILD_TOOLS_VERSION: '36.0.0' | |
| - name: Rename builds | |
| run: | | |
| mv android/app/build/outputs/bundle/release/app-release.aab android/app/build/outputs/bundle/release/PhiZone.Player_${{ needs.metadata.outputs.version-name }}.aab | |
| mv ${{ steps.sign-apk.outputs.signedReleaseFile }} android/app/build/outputs/apk/release/PhiZone.Player_${{ needs.metadata.outputs.version-name }}.apk | |
| cd build && zip -r ../PhiZone.Player_${{ needs.metadata.outputs.version-name }}.zip . | |
| - name: Publish release | |
| run: | | |
| gh release create "v${{ needs.metadata.outputs.version-name }}" \ | |
| --title "v${{ needs.metadata.outputs.version }} ${{ needs.metadata.outputs.current-week }}" \ | |
| --notes "Automated snapshot release. See the assets for downloads." --prerelease \ | |
| android/app/build/outputs/bundle/release/PhiZone.Player_${{ needs.metadata.outputs.version-name }}.aab \ | |
| android/app/build/outputs/apk/release/PhiZone.Player_${{ needs.metadata.outputs.version-name }}.apk \ | |
| PhiZone.Player_${{ needs.metadata.outputs.version-name }}.zip | |
| env: | |
| GITHUB_TOKEN: ${{ secrets.ACCESS_TOKEN }} | |
| publish-capacitor-ios: | |
| name: Build for iOS | |
| runs-on: macos-26 | |
| needs: [metadata, publish-capacitor-android] | |
| permissions: | |
| contents: write | |
| steps: | |
| - name: Confirm build version and datetime | |
| run: | | |
| echo "Version: ${{ needs.metadata.outputs.version }}" | |
| echo "Build datetime: ${{ needs.metadata.outputs.current-week }}" | |
| - name: Checkout | |
| uses: actions/checkout@v6 | |
| - name: Setup Node.js | |
| uses: actions/setup-node@v6 | |
| with: | |
| node-version: lts/* | |
| - name: Setup pnpm | |
| uses: pnpm/action-setup@v4 | |
| - name: Setup Ruby | |
| uses: ruby/setup-ruby@v1 | |
| with: | |
| ruby-version: '3.3' | |
| - name: Install dependencies | |
| run: pnpm i | |
| - name: Install iOS dependencies | |
| run: | | |
| cd ios/App | |
| pod install | |
| - name: Download iOS SDK | |
| run: | | |
| rm -rf ~/Library/Caches/com.apple.dt.Xcode | |
| rm -rf ~/Library/Developer/Xcode/DerivedData | |
| xcrun simctl delete all | |
| xcodebuild -downloadPlatform iOS | |
| - name: Create build | |
| run: pnpm build | |
| env: | |
| PUBLIC_SENTRY_DSN: ${{ vars.PUBLIC_SENTRY_DSN }} | |
| - name: Generate icons and splash screen | |
| run: if [ -d "./resources" ]; then pnpm i -D @capacitor/assets && pnpm capacitor-assets generate --ios; fi | |
| - name: Install code-signing certificate, provisioning profiles and API key | |
| env: | |
| BUILD_CERTIFICATE_BASE64: ${{ secrets.APPLE_CERTIFICATE }} | |
| P12_PASSWORD: ${{ secrets.APPLE_CERTIFICATE_PASSWORD }} | |
| PROVISIONING_PROFILE_BASE64: ${{ secrets.APPLE_PROVISIONING_PROFILE }} | |
| PROVISIONING_PROFILE_SE_BASE64: ${{ secrets.APPLE_PROVISIONING_PROFILE_SHARE_EXTENSION }} | |
| KEYCHAIN_PASSWORD: ${{ secrets.APPLE_KEYCHAIN_PASSWORD }} | |
| ASC_API_KEY_BASE64: ${{ secrets.APPLE_ASC_API_KEY }} | |
| ASC_API_KEY_ID: ${{ secrets.APPLE_ASC_API_KEY_ID }} | |
| run: | | |
| CERTIFICATE_PATH=$RUNNER_TEMP/build_certificate.p12 | |
| PP_PATH=$RUNNER_TEMP/app.mobileprovision | |
| PPSE_PATH=$RUNNER_TEMP/share-extension.mobileprovision | |
| KEYCHAIN_PATH=$RUNNER_TEMP/app-signing.keychain-db | |
| ASC_API_KEY_PATH=$RUNNER_TEMP/AuthKey_${ASC_API_KEY_ID}.p8 | |
| echo -n "$BUILD_CERTIFICATE_BASE64" | base64 --decode -o $CERTIFICATE_PATH | |
| echo -n "$PROVISIONING_PROFILE_BASE64" | base64 --decode -o $PP_PATH | |
| echo -n "$PROVISIONING_PROFILE_SE_BASE64" | base64 --decode -o $PPSE_PATH | |
| security create-keychain -p "$KEYCHAIN_PASSWORD" $KEYCHAIN_PATH | |
| security set-keychain-settings -lut 21600 $KEYCHAIN_PATH | |
| security unlock-keychain -p "$KEYCHAIN_PASSWORD" $KEYCHAIN_PATH | |
| security import $CERTIFICATE_PATH -P "$P12_PASSWORD" -A -t cert -f pkcs12 -k $KEYCHAIN_PATH | |
| security set-key-partition-list -S apple-tool:,apple: -k "$KEYCHAIN_PASSWORD" $KEYCHAIN_PATH | |
| security list-keychain -d user -s $KEYCHAIN_PATH | |
| mkdir -p ~/Library/MobileDevice/Provisioning\ Profiles | |
| cp $PP_PATH $PPSE_PATH ~/Library/MobileDevice/Provisioning\ Profiles | |
| echo -n "$ASC_API_KEY_BASE64" | base64 --decode -o $ASC_API_KEY_PATH | |
| - name: Build project | |
| run: | | |
| xcodebuild -workspace ios/App/App.xcworkspace -scheme App \ | |
| -archivePath $RUNNER_TEMP/App.xcarchive \ | |
| -destination generic/platform=iOS \ | |
| -sdk iphoneos \ | |
| clean archive | |
| - name: Assemble IPA | |
| env: | |
| EXPORT_OPTIONS_PLIST: ${{ secrets.APPLE_EXPORT_OPTIONS_IPA }} | |
| ASC_API_KEY_ID: ${{ secrets.APPLE_ASC_API_KEY_ID }} | |
| ASC_API_KEY_ISSUER_ID: ${{ secrets.APPLE_ASC_API_KEY_ISSUER_ID }} | |
| run: | | |
| EXPORT_OPTIONS_PATH=$RUNNER_TEMP/ExportOptionsIPA.plist | |
| ASC_API_KEY_PATH=$RUNNER_TEMP/AuthKey_${ASC_API_KEY_ID}.p8 | |
| echo -n "$EXPORT_OPTIONS_PLIST" | base64 --decode -o $EXPORT_OPTIONS_PATH | |
| xcodebuild archive -archivePath $RUNNER_TEMP/App.xcarchive \ | |
| -exportArchive -exportOptionsPlist $EXPORT_OPTIONS_PATH \ | |
| -exportPath $RUNNER_TEMP/build \ | |
| -allowProvisioningUpdates \ | |
| -authenticationKeyID $ASC_API_KEY_ID \ | |
| -authenticationKeyIssuerID $ASC_API_KEY_ISSUER_ID \ | |
| -authenticationKeyPath $ASC_API_KEY_PATH | |
| - name: Rename build | |
| run: mv $RUNNER_TEMP/build/App.ipa $RUNNER_TEMP/build/PhiZone.Player_${{ needs.metadata.outputs.version-name }}.ipa | |
| - name: Publish release | |
| run: | | |
| gh release upload "v${{ needs.metadata.outputs.version-name }}" \ | |
| $RUNNER_TEMP/build/PhiZone.Player_${{ needs.metadata.outputs.version-name }}.ipa | |
| env: | |
| GITHUB_TOKEN: ${{ secrets.ACCESS_TOKEN }} | |
| - name: Upload to App Store Connect | |
| env: | |
| EXPORT_OPTIONS_PLIST: ${{ secrets.APPLE_EXPORT_OPTIONS_ASC }} | |
| ASC_API_KEY_ID: ${{ secrets.APPLE_ASC_API_KEY_ID }} | |
| ASC_API_KEY_ISSUER_ID: ${{ secrets.APPLE_ASC_API_KEY_ISSUER_ID }} | |
| run: | | |
| EXPORT_OPTIONS_PATH=$RUNNER_TEMP/ExportOptionsASC.plist | |
| ASC_API_KEY_PATH=$RUNNER_TEMP/AuthKey_${ASC_API_KEY_ID}.p8 | |
| echo -n "$EXPORT_OPTIONS_PLIST" | base64 --decode -o $EXPORT_OPTIONS_PATH | |
| xcodebuild archive -archivePath $RUNNER_TEMP/App.xcarchive \ | |
| -exportArchive -exportOptionsPlist $EXPORT_OPTIONS_PATH \ | |
| -allowProvisioningUpdates \ | |
| -authenticationKeyID $ASC_API_KEY_ID \ | |
| -authenticationKeyIssuerID $ASC_API_KEY_ISSUER_ID \ | |
| -authenticationKeyPath $ASC_API_KEY_PATH | |
| - name: Clean up keychain and provisioning profiles | |
| if: ${{ always() }} | |
| run: | | |
| security delete-keychain $RUNNER_TEMP/app-signing.keychain-db | |
| rm ~/Library/MobileDevice/Provisioning\ Profiles/app.mobileprovision | |
| rm ~/Library/MobileDevice/Provisioning\ Profiles/share-extension.mobileprovision | |
| - name: Clean Xcode caches and derived data | |
| if: ${{ always() }} | |
| run: | | |
| rm -rf ~/Library/Caches/com.apple.dt.Xcode | |
| rm -rf ~/Library/Developer/Xcode/DerivedData | |
| xcrun simctl delete all | |
| publish-tauri: | |
| name: Build with Tauri | |
| needs: [metadata, publish-capacitor-android] | |
| permissions: | |
| contents: write | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| include: | |
| - platform: 'ubuntu-22.04' | |
| args: '' | |
| - platform: 'ubuntu-22.04-arm' | |
| args: '' | |
| - platform: 'windows-latest' | |
| args: '' | |
| - platform: 'windows-latest' | |
| args: '--target aarch64-pc-windows-msvc' | |
| - platform: 'macos-latest' | |
| args: '--target aarch64-apple-darwin' | |
| - platform: 'macos-latest' | |
| args: '--target x86_64-apple-darwin' | |
| runs-on: ${{ matrix.platform }} | |
| steps: | |
| - name: Confirm build version and datetime | |
| run: | | |
| echo "Version: ${{ needs.metadata.outputs.version }}" | |
| echo "Build datetime: ${{ needs.metadata.outputs.current-week }}" | |
| - name: Checkout | |
| uses: actions/checkout@v6 | |
| - name: Setup Node.js | |
| uses: actions/setup-node@v6 | |
| with: | |
| node-version: lts/* | |
| - name: Setup pnpm | |
| uses: pnpm/action-setup@v4 | |
| - name: Install Rust stable | |
| uses: dtolnay/rust-toolchain@stable | |
| with: | |
| targets: ${{ matrix.platform == 'macos-latest' && 'aarch64-apple-darwin,x86_64-apple-darwin' || (matrix.platform == 'windows-latest' && 'aarch64-pc-windows-msvc' || '') }} | |
| - name: Cache Cargo | |
| uses: Swatinem/rust-cache@v2 | |
| with: | |
| workspaces: 'src-tauri -> target' | |
| - name: Install dependencies (Ubuntu only) | |
| if: startsWith(matrix.platform, 'ubuntu-') | |
| run: | | |
| sudo apt-get update | |
| sudo apt-get install -y libwebkit2gtk-4.1-dev libappindicator3-dev librsvg2-dev patchelf xdg-utils libasound2-dev | |
| - name: Install frontend dependencies | |
| run: pnpm i | |
| - name: Install code-signing certificate and API key | |
| if: startsWith(matrix.platform, 'macos-') | |
| env: | |
| APPLE_CERTIFICATE: ${{ secrets.APPLE_DIA_CERTIFICATE }} | |
| APPLE_CERTIFICATE_PASSWORD: ${{ secrets.APPLE_DIA_CERTIFICATE_PASSWORD }} | |
| KEYCHAIN_PASSWORD: ${{ secrets.APPLE_KEYCHAIN_PASSWORD }} | |
| ASC_API_KEY_BASE64: ${{ secrets.APPLE_ASC_API_KEY }} | |
| ASC_API_KEY_ID: ${{ secrets.APPLE_ASC_API_KEY_ID }} | |
| run: | | |
| ASC_API_KEY_PATH=$RUNNER_TEMP/AuthKey_${ASC_API_KEY_ID}.p8 | |
| echo $APPLE_CERTIFICATE | base64 --decode > certificate.p12 | |
| security create-keychain -p "$KEYCHAIN_PASSWORD" build.keychain | |
| security default-keychain -s build.keychain | |
| security unlock-keychain -p "$KEYCHAIN_PASSWORD" build.keychain | |
| security import certificate.p12 -k build.keychain -P "$APPLE_CERTIFICATE_PASSWORD" -T /usr/bin/codesign | |
| security set-key-partition-list -S apple-tool:,apple:,codesign: -s -k "$KEYCHAIN_PASSWORD" build.keychain | |
| security find-identity -v -p codesigning build.keychain | |
| security set-keychain-settings -t 3600 -u build.keychain | |
| echo -n "$ASC_API_KEY_BASE64" | base64 --decode -o $ASC_API_KEY_PATH | |
| - name: Obtain certificate ID and API key path | |
| id: apple-signing | |
| if: startsWith(matrix.platform, 'macos-') | |
| env: | |
| ASC_API_KEY_ID: ${{ secrets.APPLE_ASC_API_KEY_ID }} | |
| run: | | |
| CERT_INFO=$(security find-identity -v -p codesigning build.keychain | grep "Developer ID Application") | |
| CERT_ID=$(echo "$CERT_INFO" | awk -F'"' '{print $2}') | |
| ASC_API_KEY_PATH=$RUNNER_TEMP/AuthKey_${ASC_API_KEY_ID}.p8 | |
| echo "CERT_ID=$CERT_ID" >> $GITHUB_OUTPUT | |
| echo "ASC_API_KEY_PATH=$ASC_API_KEY_PATH" >> $GITHUB_OUTPUT | |
| - name: Build | |
| id: build | |
| uses: tauri-apps/tauri-action@v0 | |
| env: | |
| GITHUB_TOKEN: ${{ secrets.ACCESS_TOKEN }} | |
| PUBLIC_SENTRY_DSN: ${{ vars.PUBLIC_SENTRY_DSN }} | |
| APPLE_CERTIFICATE: ${{ startsWith(matrix.platform, 'macos-') && secrets.APPLE_DIA_CERTIFICATE || '' }} | |
| APPLE_CERTIFICATE_PASSWORD: ${{ startsWith(matrix.platform, 'macos-') && secrets.APPLE_DIA_CERTIFICATE_PASSWORD || '' }} | |
| APPLE_SIGNING_IDENTITY: ${{ startsWith(matrix.platform, 'macos-') && steps.apple-signing.outputs.CERT_ID || '' }} | |
| APPLE_API_KEY: ${{ startsWith(matrix.platform, 'macos-') && secrets.APPLE_ASC_API_KEY_ID || '' }} | |
| APPLE_API_ISSUER: ${{ startsWith(matrix.platform, 'macos-') && secrets.APPLE_ASC_API_KEY_ISSUER_ID || '' }} | |
| APPLE_API_KEY_PATH: ${{ startsWith(matrix.platform, 'macos-') && steps.apple-signing.outputs.ASC_API_KEY_PATH || '' }} | |
| with: | |
| includeDebug: true | |
| args: ${{ matrix.args }} | |
| - name: Rename builds | |
| run: | | |
| IFS=',' | |
| SPACE='.SPACE_PLACEHOLDER.' | |
| artifact_paths=$(echo '${{ steps.build.outputs.artifactPaths }}' | sed -e 's/\[//g; s/\]//g' -e 's/["]//g' -e 's/ /$SPACE/g') | |
| renamed_paths="" | |
| for artifact_path in $artifact_paths; do | |
| original_path=$(echo "$artifact_path" | sed -e 's/$SPACE/ /g') | |
| if [[ "$original_path" == *.app ]]; then | |
| echo "Skipping $original_path" | |
| continue | |
| fi | |
| if [[ "$original_path" == *"/debug/"* || "$original_path" == *"\\debug\\"* ]]; then | |
| renamed_path=$(echo "$original_path" | sed -E "s/PhiZone Player[_-]${{ needs.metadata.outputs.version }}(-1)?/PhiZone.Player_${{ needs.metadata.outputs.version-name }}-debug/g") | |
| else | |
| renamed_path=$(echo "$original_path" | sed -E "s/PhiZone Player[_-]${{ needs.metadata.outputs.version }}(-1)?/PhiZone.Player_${{ needs.metadata.outputs.version-name }}/g") | |
| fi | |
| echo "Renaming: $original_path -> $renamed_path" | |
| mv "$original_path" "$renamed_path" | |
| renamed_paths="$renamed_paths $renamed_path" | |
| done | |
| # Add built binary to renamed_paths | |
| VERSION="${{ needs.metadata.outputs.version-name }}" | |
| PLATFORM="" | |
| BINARY="" | |
| DEST="" | |
| DEBUG_BINARY="" | |
| DEBUG_DEST="" | |
| if [[ "${{ startsWith(matrix.platform, 'ubuntu-') }}" == "true" ]]; then | |
| if [[ "${{ endsWith(matrix.platform, '-arm') }}" == "true" ]]; then | |
| PLATFORM="linux-arm64" | |
| else | |
| PLATFORM="linux-x86_64" | |
| fi | |
| BINARY="src-tauri/target/release/phizone-player" | |
| DEST="PhiZone.Player-${VERSION}-${PLATFORM}" | |
| elif [[ "${{ startsWith(matrix.platform, 'windows-') }}" == "true" && "${{ matrix.args }}" == "" ]]; then | |
| PLATFORM="windows-x86_64" | |
| BINARY="src-tauri/target/release/phizone-player.exe" | |
| DEST="PhiZone.Player-${VERSION}-${PLATFORM}.exe" | |
| elif [[ "${{ startsWith(matrix.platform, 'windows-') }}" == "true" && "${{ matrix.args }}" == "--target aarch64-pc-windows-msvc" ]]; then | |
| PLATFORM="windows-arm64" | |
| BINARY="src-tauri/target/aarch64-pc-windows-msvc/release/phizone-player.exe" | |
| DEST="PhiZone.Player-${VERSION}-${PLATFORM}.exe" | |
| elif [[ "${{ startsWith(matrix.platform, 'macos-') }}" == "true" && "${{ matrix.args }}" == "--target aarch64-apple-darwin" ]]; then | |
| PLATFORM="macos-arm64" | |
| BINARY="src-tauri/target/aarch64-apple-darwin/release/phizone-player" | |
| DEST="PhiZone.Player-${VERSION}-${PLATFORM}" | |
| elif [[ "${{ startsWith(matrix.platform, 'macos-') }}" == "true" && "${{ matrix.args }}" == "--target x86_64-apple-darwin" ]]; then | |
| PLATFORM="macos-x86_64" | |
| BINARY="src-tauri/target/x86_64-apple-darwin/release/phizone-player" | |
| DEST="PhiZone.Player-${VERSION}-${PLATFORM}" | |
| fi | |
| if [[ -n "$BINARY" ]]; then | |
| DEBUG_BINARY="${BINARY/release/debug}" | |
| if [[ "$DEST" == *.exe ]]; then | |
| DEBUG_DEST="${DEST/.exe/-debug.exe}" | |
| else | |
| DEBUG_DEST="${DEST}-debug" | |
| fi | |
| fi | |
| if [[ -f "$BINARY" ]]; then | |
| cp "$BINARY" "$DEST" | |
| renamed_paths="$renamed_paths $DEST" | |
| else | |
| echo "Binary not found for $PLATFORM at $BINARY" | |
| exit 1 | |
| fi | |
| if [[ -f "$DEBUG_BINARY" ]]; then | |
| cp "$DEBUG_BINARY" "$DEBUG_DEST" | |
| renamed_paths="$renamed_paths $DEBUG_DEST" | |
| elif [[ "$PLATFORM" == "windows-x86_64" && -f "src-tauri/debug/phizone-player.exe" ]]; then | |
| # Fallback for publish-debug.yml discrepancy | |
| cp "src-tauri/debug/phizone-player.exe" "$DEBUG_DEST" | |
| renamed_paths="$renamed_paths $DEBUG_DEST" | |
| else | |
| echo "Debug binary not found for $PLATFORM at $DEBUG_BINARY" | |
| exit 1 | |
| fi | |
| echo "RENAMED_PATHS=$renamed_paths" >> $GITHUB_ENV | |
| - name: Publish release | |
| run: | | |
| gh release upload "v${{ needs.metadata.outputs.version-name }}" $RENAMED_PATHS | |
| env: | |
| GITHUB_TOKEN: ${{ secrets.ACCESS_TOKEN }} |