Since 2.10.0 the whole app sits behind one all-or-nothing initialization gate, and that gate discarded the only evidence of its own failure. It caught the error, logged nothing but `error.runtimeType`, rendered an icon plus the word "Error" plus Retry, and never reported the error because catching it kept the crash reporter from ever seeing it. There is no log file on any platform, the buffer is in memory only, a double-clicked Windows release build has no console, and the log viewer lives in Settings, behind the gate that just failed. #1732 is the result: a Windows 11 user whose app will not boot and who cannot produce a single byte of diagnostic detail. The gate now names its phases. Each step is wrapped so a throw carries the phase it came from, replacing a `Future.wait` that discarded every error but the first and could not attribute it to any of four concurrent steps. The failure screen renders the phase, the exception type, the message and an expandable stack, plus copy and upload actions that reuse the existing log-relay flow. The record is persisted next to the database so the next successful launch can surface it in Settings > Logs, and it is reported to the crash reporter explicitly. Only preferences and the database still gate the launch. Window chrome, locale, crash-reporting init, TV/performance detection, the image-cache budget and download storage are best-effort and time-bounded, so a stalled platform thread degrades instead of holding the splash forever. Sentry no longer receives the startup work as its `appRunner`: that made a startup failure indistinguishable from a Sentry failure, and the guard would then have re-run migrations and the database open a second time. The two remaining fatal steps become recoverable. Preference reads tolerate a value whose stored type no longer matches, dropping the key and defaulting instead of failing the boot. A store that cannot be parsed is detected before either desktop plugin backend can memoise it, which is what makes an in-process repair possible at all. Repair is never automatic: it states what it will cost, salvages the credential-vault key and every tracker and Seerr session it can validate out of the damaged bytes, reseeds them, and moves the original aside rather than deleting it. Servers and profiles survive a salvaged key because their tokens are ciphertext in the database; tracker and Seerr sessions are plaintext preference entries, so the copy says they may still need reconnecting. Nothing derived from the store reaches a diagnostic. `FormatException` prints an excerpt of whatever it failed to parse, and during startup that document holds the vault key, refresh tokens and session cookies while the redaction manager still has nothing registered, so the wrapper keeps only the cause's type and offset and the record is an allowlist of already-redacted fields. The quarantined copy is labelled as containing credentials, is never offered for upload, and can be deleted from the dialog. Also self-heals orphaned WAL/SHM sidecars on desktop rather than only tvOS, makes every `createTable` migration step idempotent, keeps MSVC link by-products out of the Windows bundle, and asserts bundle contents in CI. Refs #1732
1016 lines
40 KiB
YAML
1016 lines
40 KiB
YAML
name: Build
|
|
|
|
on:
|
|
workflow_dispatch:
|
|
inputs:
|
|
build_android:
|
|
description: Build Android
|
|
default: true
|
|
type: boolean
|
|
build_ios:
|
|
description: Build iOS
|
|
default: true
|
|
type: boolean
|
|
build_macos:
|
|
description: Build macOS
|
|
default: true
|
|
type: boolean
|
|
build_windows:
|
|
description: Build Windows
|
|
default: true
|
|
type: boolean
|
|
build_linux:
|
|
description: Build Linux
|
|
default: true
|
|
type: boolean
|
|
|
|
env:
|
|
# Only place this workflow names the SDK; .github/actions/setup-flutter-git pins the same release.
|
|
FLUTTER_VERSION: "3.44.0"
|
|
# Shared by every release build command; SENTRY_DIST stays per-platform.
|
|
RELEASE_DART_DEFINES: --dart-define=ENABLE_UPDATE_CHECK=true ${{ github.repository == 'edde746/plezy' && '--dart-define=ENABLE_SENTRY=true' || '' }} --dart-define=GIT_COMMIT=${{ github.sha }} --dart-define=SENTRY_ENVIRONMENT=github --dart-define=ENABLE_DONATIONS=true
|
|
TRUSTED_BUILD_CACHE_VERSION: trusted-build-v1
|
|
LINUX_APT_PACKAGES: >
|
|
clang cmake meson ninja-build pkg-config nasm libgtk-3-dev libevdev-dev liblzma-dev
|
|
libstdc++-12-dev libasound2-dev libass-dev libfreetype-dev libfontconfig-dev libfribidi-dev
|
|
libharfbuzz-dev libepoxy-dev libegl-dev libgl-dev libgnutls28-dev libpipewire-0.3-dev
|
|
libva-dev libvdpau-dev libx11-dev libxext-dev libxrandr-dev libxcursor-dev libxi-dev
|
|
libxss-dev libxpresent-dev libxkbcommon-dev libpulse-dev libdbus-1-dev libdrm-dev
|
|
libgbm-dev libwayland-dev wayland-protocols liblcms2-dev libmujs-dev liblua5.2-dev
|
|
ruby ruby-dev rubygems build-essential rpm libarchive-tools imagemagick libcurl4-openssl-dev
|
|
|
|
jobs:
|
|
validate-trusted-ref:
|
|
name: Validate trusted build ref
|
|
runs-on: ubuntu-latest
|
|
permissions: {}
|
|
steps:
|
|
- name: Require the protected main branch
|
|
shell: bash
|
|
run: |
|
|
if [[ "$GITHUB_REF" != "refs/heads/main" ]]; then
|
|
echo "Release builds may only run from refs/heads/main." >&2
|
|
exit 1
|
|
fi
|
|
|
|
build-android:
|
|
needs: validate-trusted-ref
|
|
if: ${{ inputs.build_android }}
|
|
runs-on: ubuntu-latest
|
|
permissions:
|
|
id-token: write
|
|
attestations: write
|
|
contents: read
|
|
steps:
|
|
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
|
|
with:
|
|
persist-credentials: false
|
|
|
|
- name: Setup Java
|
|
uses: actions/setup-java@03ad4de0992f5dab5e18fcb136590ce7c4a0ac95 # v5
|
|
with:
|
|
distribution: "temurin"
|
|
java-version: "21"
|
|
|
|
- name: Setup Flutter
|
|
uses: subosito/flutter-action@1a449444c387b1966244ae4d4f8c696479add0b2 # v2
|
|
with:
|
|
channel: "stable"
|
|
flutter-version: ${{ env.FLUTTER_VERSION }}
|
|
cache: true
|
|
cache-key: "${{ env.TRUSTED_BUILD_CACHE_VERSION }}-flutter-:os:-:channel:-:version:-:arch:-:hash:"
|
|
pub-cache: false
|
|
|
|
- name: Cache Pub dependencies
|
|
uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6
|
|
with:
|
|
path: |
|
|
~/.pub-cache
|
|
key: ${{ env.TRUSTED_BUILD_CACHE_VERSION }}-${{ runner.os }}-${{ runner.arch }}-pub-${{ hashFiles('pubspec.yaml', 'pubspec.lock') }}
|
|
|
|
- name: Cache Gradle
|
|
uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6
|
|
with:
|
|
path: |
|
|
~/.gradle/caches
|
|
~/.gradle/wrapper
|
|
key: ${{ env.TRUSTED_BUILD_CACHE_VERSION }}-${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle*', '**/gradle-wrapper.properties') }}
|
|
|
|
- name: Install dependencies
|
|
run: flutter pub get --enforce-lockfile --no-example
|
|
|
|
- name: Configure Android signing
|
|
run: |
|
|
echo "${{ secrets.ANDROID_KEYSTORE_BASE64 }}" | base64 --decode > android/app/upload-keystore.jks
|
|
cat > android/key.properties << EOF
|
|
storePassword=${{ secrets.ANDROID_STORE_PASSWORD }}
|
|
keyPassword=${{ secrets.ANDROID_KEY_PASSWORD }}
|
|
keyAlias=${{ secrets.ANDROID_KEY_ALIAS }}
|
|
storeFile=upload-keystore.jks
|
|
EOF
|
|
|
|
- name: Build APKs
|
|
run: flutter build apk --release --split-per-abi ${{ env.RELEASE_DART_DEFINES }} --dart-define=SENTRY_DIST=github-android-apk --obfuscate --split-debug-info=debug-info/android-apk --extra-gen-snapshot-options=--save-obfuscation-map=debug-info/android-apk/obfuscation.map.json
|
|
|
|
- name: Upload symbols to bugs.plezy.app
|
|
if: github.repository == 'edde746/plezy'
|
|
env:
|
|
BUGS_ADMIN_TOKEN: ${{ secrets.BUGS_ADMIN_TOKEN }}
|
|
SENTRY_DIST: github-android-apk
|
|
run: ./scripts/upload-symbols.sh android-apk
|
|
|
|
- name: Clean up keystore
|
|
if: always()
|
|
run: rm -f android/app/upload-keystore.jks android/key.properties
|
|
|
|
- name: Package APKs
|
|
run: |
|
|
tar -czf plezy-android-arm64-v8a.tar.gz -C build/app/outputs/flutter-apk app-arm64-v8a-release.apk --transform 's/app-arm64-v8a-release.apk/plezy.apk/'
|
|
tar -czf plezy-android-armeabi-v7a.tar.gz -C build/app/outputs/flutter-apk app-armeabi-v7a-release.apk --transform 's/app-armeabi-v7a-release.apk/plezy.apk/'
|
|
tar -czf plezy-android-x86_64.tar.gz -C build/app/outputs/flutter-apk app-x86_64-release.apk --transform 's/app-x86_64-release.apk/plezy.apk/'
|
|
|
|
- name: Attest APKs
|
|
uses: actions/attest-build-provenance@0f67c3f4856b2e3261c31976d6725780e5e4c373 # v4
|
|
with:
|
|
subject-path: |
|
|
plezy-android-arm64-v8a.tar.gz
|
|
plezy-android-armeabi-v7a.tar.gz
|
|
plezy-android-x86_64.tar.gz
|
|
|
|
- name: Upload APKs
|
|
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7
|
|
with:
|
|
name: android-apk
|
|
path: |
|
|
plezy-android-arm64-v8a.tar.gz
|
|
plezy-android-armeabi-v7a.tar.gz
|
|
plezy-android-x86_64.tar.gz
|
|
|
|
build-ios:
|
|
needs: validate-trusted-ref
|
|
if: ${{ inputs.build_ios }}
|
|
runs-on: macos-26
|
|
permissions:
|
|
id-token: write
|
|
attestations: write
|
|
contents: read
|
|
steps:
|
|
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
|
|
with:
|
|
persist-credentials: false
|
|
|
|
- name: Setup Flutter
|
|
uses: subosito/flutter-action@1a449444c387b1966244ae4d4f8c696479add0b2 # v2
|
|
with:
|
|
channel: "stable"
|
|
flutter-version: ${{ env.FLUTTER_VERSION }}
|
|
cache: true
|
|
cache-key: "${{ env.TRUSTED_BUILD_CACHE_VERSION }}-flutter-:os:-:channel:-:version:-:arch:-:hash:"
|
|
pub-cache: false
|
|
|
|
- name: Cache Pub dependencies
|
|
uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6
|
|
with:
|
|
path: |
|
|
~/.pub-cache
|
|
key: ${{ env.TRUSTED_BUILD_CACHE_VERSION }}-${{ runner.os }}-${{ runner.arch }}-pub-${{ hashFiles('pubspec.yaml', 'pubspec.lock') }}
|
|
|
|
- name: Cache CocoaPods
|
|
uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6
|
|
with:
|
|
path: |
|
|
ios/Pods
|
|
~/Library/Caches/CocoaPods
|
|
~/.cocoapods
|
|
key: ${{ env.TRUSTED_BUILD_CACHE_VERSION }}-${{ runner.os }}-ios-pods-${{ hashFiles('**/Podfile.lock') }}
|
|
|
|
- name: Install dependencies
|
|
run: flutter pub get --enforce-lockfile --no-example
|
|
|
|
- name: Build iOS (no codesign)
|
|
run: flutter build ios --release --no-codesign ${{ env.RELEASE_DART_DEFINES }} --dart-define=SENTRY_DIST=github-ios --split-debug-info=debug-info/ios
|
|
|
|
- name: Upload symbols to bugs.plezy.app
|
|
if: github.repository == 'edde746/plezy'
|
|
env:
|
|
BUGS_ADMIN_TOKEN: ${{ secrets.BUGS_ADMIN_TOKEN }}
|
|
SENTRY_DIST: github-ios
|
|
run: ./scripts/upload-symbols.sh ios
|
|
|
|
- name: Create IPA
|
|
run: |
|
|
mkdir -p Payload
|
|
cp -r build/ios/iphoneos/Runner.app Payload/
|
|
zip -r plezy-ios.ipa Payload
|
|
|
|
- name: Attest IPA
|
|
uses: actions/attest-build-provenance@0f67c3f4856b2e3261c31976d6725780e5e4c373 # v4
|
|
with:
|
|
subject-path: plezy-ios.ipa
|
|
|
|
- name: Upload IPA
|
|
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7
|
|
with:
|
|
name: ios-ipa
|
|
path: plezy-ios.ipa
|
|
|
|
build-macos:
|
|
needs: validate-trusted-ref
|
|
if: ${{ inputs.build_macos }}
|
|
runs-on: macos-26
|
|
permissions:
|
|
id-token: write
|
|
attestations: write
|
|
contents: read
|
|
steps:
|
|
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
|
|
with:
|
|
persist-credentials: false
|
|
|
|
- name: Setup Flutter
|
|
uses: subosito/flutter-action@1a449444c387b1966244ae4d4f8c696479add0b2 # v2
|
|
with:
|
|
channel: "stable"
|
|
flutter-version: ${{ env.FLUTTER_VERSION }}
|
|
cache: true
|
|
cache-key: "${{ env.TRUSTED_BUILD_CACHE_VERSION }}-flutter-:os:-:channel:-:version:-:arch:-:hash:"
|
|
pub-cache: false
|
|
|
|
- name: Cache Pub dependencies
|
|
uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6
|
|
with:
|
|
path: |
|
|
~/.pub-cache
|
|
key: ${{ env.TRUSTED_BUILD_CACHE_VERSION }}-${{ runner.os }}-${{ runner.arch }}-pub-${{ hashFiles('pubspec.yaml', 'pubspec.lock') }}
|
|
|
|
- name: Cache CocoaPods
|
|
uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6
|
|
with:
|
|
path: |
|
|
macos/Pods
|
|
~/Library/Caches/CocoaPods
|
|
~/.cocoapods
|
|
key: ${{ env.TRUSTED_BUILD_CACHE_VERSION }}-${{ runner.os }}-macos-pods-${{ hashFiles('**/Podfile.lock') }}
|
|
|
|
- name: Install dependencies
|
|
run: flutter pub get --enforce-lockfile --no-example
|
|
|
|
- name: Build macOS
|
|
run: flutter build macos --release ${{ env.RELEASE_DART_DEFINES }} --dart-define=SENTRY_DIST=github-macos --split-debug-info=debug-info/macos
|
|
|
|
- name: Upload symbols to bugs.plezy.app
|
|
if: github.repository == 'edde746/plezy'
|
|
env:
|
|
BUGS_ADMIN_TOKEN: ${{ secrets.BUGS_ADMIN_TOKEN }}
|
|
SENTRY_DIST: github-macos
|
|
run: ./scripts/upload-symbols.sh macos
|
|
|
|
- name: Import Code Signing Certificate
|
|
env:
|
|
MACOS_CERTIFICATE_BASE64: ${{ secrets.MACOS_CERTIFICATE_BASE64 }}
|
|
MACOS_CERTIFICATE_PASSWORD: ${{ secrets.MACOS_CERTIFICATE_PASSWORD }}
|
|
KEYCHAIN_PASSWORD: ${{ secrets.KEYCHAIN_PASSWORD }}
|
|
run: |
|
|
# Create temporary keychain
|
|
KEYCHAIN_PATH=$RUNNER_TEMP/build.keychain
|
|
security create-keychain -p "$KEYCHAIN_PASSWORD" $KEYCHAIN_PATH
|
|
security set-keychain-settings -lut 21600 $KEYCHAIN_PATH
|
|
security unlock-keychain -p "$KEYCHAIN_PASSWORD" $KEYCHAIN_PATH
|
|
|
|
# Import certificate to keychain
|
|
CERTIFICATE_PATH=$RUNNER_TEMP/certificate.p12
|
|
echo "$MACOS_CERTIFICATE_BASE64" | base64 --decode -o $CERTIFICATE_PATH
|
|
security import $CERTIFICATE_PATH -k $KEYCHAIN_PATH -P "$MACOS_CERTIFICATE_PASSWORD" -T /usr/bin/codesign
|
|
security set-key-partition-list -S apple-tool:,apple:,codesign: -s -k "$KEYCHAIN_PASSWORD" $KEYCHAIN_PATH
|
|
|
|
# Add keychain to search list
|
|
security list-keychains -d user -s $KEYCHAIN_PATH login.keychain
|
|
|
|
- name: Sign Application
|
|
env:
|
|
APPLE_TEAM_ID: ${{ secrets.APPLE_TEAM_ID }}
|
|
run: |
|
|
# Find the identity
|
|
IDENTITY=$(security find-identity -v -p codesigning | grep "Developer ID Application" | head -1 | grep -o '".*"' | tr -d '"')
|
|
echo "Signing with identity: $IDENTITY"
|
|
|
|
APP_PATH="build/macos/Build/Products/Release/Plezy.app"
|
|
|
|
# Deep sign everything inside-out: executables, dylibs, XPC services, app bundles, frameworks
|
|
find "$APP_PATH/Contents/Frameworks" \( -name "*.xpc" -o -name "*.app" -o -name "*.framework" -o -name "*.dylib" \) -print0 \
|
|
| sort -zr \
|
|
| while IFS= read -r -d '' item; do
|
|
echo "Signing: $item"
|
|
codesign --force --sign "$IDENTITY" --timestamp --options runtime "$item"
|
|
done
|
|
|
|
# Sign any remaining bare executables (e.g. Sparkle's Autoupdate)
|
|
find "$APP_PATH/Contents/Frameworks" -type f -perm +111 ! -name "*.dylib" ! -path "*/Headers/*" ! -path "*/Modules/*" -print0 \
|
|
| while IFS= read -r -d '' exe; do
|
|
codesign --force --sign "$IDENTITY" --timestamp --options runtime "$exe" 2>/dev/null || true
|
|
done
|
|
|
|
# Sign the app bundle itself
|
|
echo "Signing app bundle: $APP_PATH"
|
|
codesign --force --sign "$IDENTITY" --timestamp --options runtime --entitlements macos/Runner/Release.entitlements "$APP_PATH"
|
|
|
|
- name: Verify Signature
|
|
run: |
|
|
APP_PATH="build/macos/Build/Products/Release/Plezy.app"
|
|
echo "Verifying signature..."
|
|
codesign -dvvv "$APP_PATH"
|
|
echo "Verifying signed entitlements..."
|
|
codesign -d --entitlements :- "$APP_PATH" > "$RUNNER_TEMP/macos-entitlements.plist"
|
|
/usr/libexec/PlistBuddy -c "Print" "$RUNNER_TEMP/macos-entitlements.plist"
|
|
/usr/libexec/PlistBuddy -c "Print :com.apple.security.cs.allow-jit" "$RUNNER_TEMP/macos-entitlements.plist"
|
|
/usr/libexec/PlistBuddy -c "Print :com.apple.security.cs.allow-unsigned-executable-memory" "$RUNNER_TEMP/macos-entitlements.plist"
|
|
codesign --verify --deep --strict --verbose=2 "$APP_PATH"
|
|
|
|
- name: Notarize Application
|
|
env:
|
|
APPLE_ID: ${{ secrets.APPLE_ID }}
|
|
APPLE_APP_SPECIFIC_PASSWORD: ${{ secrets.APPLE_APP_SPECIFIC_PASSWORD }}
|
|
APPLE_TEAM_ID: ${{ secrets.APPLE_TEAM_ID }}
|
|
run: |
|
|
APP_PATH="build/macos/Build/Products/Release/Plezy.app"
|
|
|
|
# Create a temporary ZIP for notarization submission
|
|
echo "Creating ZIP for notarization..."
|
|
ditto -c -k --keepParent "$APP_PATH" notarization.zip
|
|
|
|
# Submit for notarization
|
|
echo "Submitting to Apple's notary service..."
|
|
xcrun notarytool submit notarization.zip \
|
|
--apple-id "$APPLE_ID" \
|
|
--password "$APPLE_APP_SPECIFIC_PASSWORD" \
|
|
--team-id "$APPLE_TEAM_ID" \
|
|
--wait
|
|
|
|
# Staple the notarization ticket to the app
|
|
echo "Stapling notarization ticket..."
|
|
xcrun stapler staple "$APP_PATH"
|
|
|
|
# Verify stapling
|
|
echo "Verifying notarization..."
|
|
xcrun stapler validate "$APP_PATH"
|
|
|
|
- name: Create DMG
|
|
run: |
|
|
mkdir -p dmg-staging
|
|
cp -R build/macos/Build/Products/Release/Plezy.app dmg-staging/
|
|
ln -s /Applications dmg-staging/Applications
|
|
hdiutil create -format ULMO -srcfolder dmg-staging -volname "Plezy" plezy-macos.dmg
|
|
|
|
- name: Sign DMG for Sparkle (EdDSA)
|
|
if: env.SPARKLE_PRIVATE_KEY != ''
|
|
env:
|
|
SPARKLE_PRIVATE_KEY: ${{ secrets.SPARKLE_PRIVATE_KEY }}
|
|
run: |
|
|
printf -- "-----BEGIN ED25519 PRIVATE KEY-----\n%s\n-----END ED25519 PRIVATE KEY-----\n" "$SPARKLE_PRIVATE_KEY" > ed25519_key.pem
|
|
OUTPUT=$(dart run auto_updater:sign_update plezy-macos.dmg ed25519_key.pem)
|
|
rm ed25519_key.pem
|
|
# Extract edSignature value from output like: sparkle:edSignature="..." length="..."
|
|
SIGNATURE=$(echo "$OUTPUT" | grep -o 'edSignature="[^"]*"' | sed 's/edSignature="//;s/"//')
|
|
echo "MACOS_ED_SIGNATURE=$SIGNATURE" >> $GITHUB_ENV
|
|
echo "MACOS_DMG_SIZE=$(stat -f%z plezy-macos.dmg)" >> $GITHUB_ENV
|
|
|
|
- name: Attest macOS DMG
|
|
uses: actions/attest-build-provenance@0f67c3f4856b2e3261c31976d6725780e5e4c373 # v4
|
|
with:
|
|
subject-path: plezy-macos.dmg
|
|
|
|
- name: Write macOS signature metadata
|
|
run: |
|
|
echo "${{ env.MACOS_ED_SIGNATURE }}" > macos-ed-signature.txt
|
|
echo "${{ env.MACOS_DMG_SIZE }}" > macos-dmg-size.txt
|
|
|
|
- name: Upload macOS DMG
|
|
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7
|
|
with:
|
|
name: macos-dmg
|
|
path: |
|
|
plezy-macos.dmg
|
|
macos-ed-signature.txt
|
|
macos-dmg-size.txt
|
|
|
|
build-windows:
|
|
needs: validate-trusted-ref
|
|
name: Build Windows (${{ matrix.arch }})
|
|
if: ${{ inputs.build_windows }}
|
|
runs-on: ${{ matrix.runner }}
|
|
permissions:
|
|
contents: read
|
|
strategy:
|
|
fail-fast: false
|
|
matrix:
|
|
include:
|
|
- arch: x64
|
|
runner: windows-latest
|
|
flutter_setup: action
|
|
native_cache_path: build/windows/x64/_deps
|
|
- arch: arm64
|
|
runner: windows-11-arm
|
|
flutter_setup: git
|
|
native_cache_path: |
|
|
build/windows/arm64/_deps
|
|
build/windows/arm64/mpv-dev-arm64
|
|
steps:
|
|
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
|
|
with:
|
|
persist-credentials: false
|
|
|
|
- name: Cache Windows native dependencies
|
|
id: windows-native-cache
|
|
uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6
|
|
with:
|
|
path: ${{ matrix.native_cache_path }}
|
|
key: ${{ env.TRUSTED_BUILD_CACHE_VERSION }}-windows-native-${{ matrix.arch }}-${{ hashFiles('windows/CMakeLists.txt') }}
|
|
|
|
- name: Install 7-Zip
|
|
if: matrix.arch == 'arm64' && steps.windows-native-cache.outputs.cache-hit != 'true'
|
|
shell: pwsh
|
|
run: choco install 7zip -y
|
|
|
|
- name: Setup Flutter
|
|
if: matrix.flutter_setup == 'action'
|
|
uses: subosito/flutter-action@1a449444c387b1966244ae4d4f8c696479add0b2 # v2
|
|
with:
|
|
channel: "stable"
|
|
flutter-version: ${{ env.FLUTTER_VERSION }}
|
|
cache: true
|
|
cache-key: "${{ env.TRUSTED_BUILD_CACHE_VERSION }}-flutter-:os:-:channel:-:version:-:arch:-:hash:"
|
|
pub-cache: false
|
|
|
|
- name: Set up Flutter from its pinned commit
|
|
if: matrix.flutter_setup == 'git'
|
|
uses: ./.github/actions/setup-flutter-git
|
|
|
|
- name: Cache Pub dependencies
|
|
uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6
|
|
with:
|
|
path: |
|
|
~\AppData\Local\Pub\Cache
|
|
key: ${{ env.TRUSTED_BUILD_CACHE_VERSION }}-${{ runner.os }}-${{ runner.arch }}-pub-${{ hashFiles('pubspec.yaml', 'pubspec.lock') }}
|
|
|
|
- name: Install dependencies
|
|
shell: pwsh
|
|
run: flutter pub get --enforce-lockfile --no-example
|
|
|
|
- name: Install patched Flutter engine (DComp)
|
|
shell: pwsh
|
|
run: |
|
|
flutter precache --windows
|
|
.\windows\tool\install-patched-engine.ps1
|
|
|
|
- name: Build Windows ${{ matrix.arch }}
|
|
shell: pwsh
|
|
run: flutter build windows --release ${{ env.RELEASE_DART_DEFINES }} --dart-define=SENTRY_DIST=github-windows-${{ matrix.arch }} --split-debug-info=debug-info/windows-${{ matrix.arch }}
|
|
|
|
- name: Verify Windows bundle contents
|
|
shell: pwsh
|
|
run: |
|
|
$bundleDir = "build/windows/${{ matrix.arch }}/runner/Release"
|
|
if (-not (Test-Path -LiteralPath $bundleDir -PathType Container)) {
|
|
throw "Windows bundle directory does not exist: $bundleDir"
|
|
}
|
|
|
|
$bundlePath = (Resolve-Path -LiteralPath $bundleDir).Path
|
|
$foundFiles = @(
|
|
Get-ChildItem -LiteralPath $bundlePath -File -Recurse |
|
|
ForEach-Object {
|
|
$_.FullName.Substring($bundlePath.Length + 1).Replace('\', '/')
|
|
} |
|
|
Sort-Object
|
|
)
|
|
|
|
Write-Host "Files found in ${bundleDir}:"
|
|
$foundFiles | ForEach-Object { Write-Host " $_" }
|
|
|
|
$requiredFiles = @(
|
|
"plezy.exe"
|
|
"flutter_windows.dll"
|
|
"sqlite3.dll"
|
|
"libmpv-2.dll"
|
|
"data/app.so"
|
|
"data/icudtl.dat"
|
|
"data/flutter_assets/NativeAssetsManifest.json"
|
|
)
|
|
$forbiddenFiles = @(
|
|
"plezy.lib"
|
|
"plezy.exp"
|
|
"simdutf.lib"
|
|
)
|
|
|
|
$bundleErrors = @()
|
|
foreach ($file in $requiredFiles) {
|
|
if ($foundFiles -notcontains $file) {
|
|
Write-Output "::error::Required Windows bundle file is missing: $file"
|
|
$bundleErrors += "missing $file"
|
|
}
|
|
}
|
|
foreach ($file in $forbiddenFiles) {
|
|
if ($foundFiles -contains $file) {
|
|
Write-Output "::error::Forbidden link by-product is present in the Windows bundle: $file"
|
|
$bundleErrors += "present $file"
|
|
}
|
|
}
|
|
|
|
# sentry.dll is the inproc-backend native SDK; crashpad_handler.exe is
|
|
# intentionally absent (windows/CMakeLists.txt sets
|
|
# SENTRY_NATIVE_BACKEND=inproc), so do not assert on it here.
|
|
|
|
if ($bundleErrors.Count -gt 0) {
|
|
throw "Windows bundle verification failed: $($bundleErrors -join '; ')"
|
|
}
|
|
|
|
- name: Upload symbols to bugs.plezy.app
|
|
if: github.repository == 'edde746/plezy'
|
|
shell: pwsh
|
|
env:
|
|
BUGS_ADMIN_TOKEN: ${{ secrets.BUGS_ADMIN_TOKEN }}
|
|
SENTRY_DIST: github-windows-${{ matrix.arch }}
|
|
run: .\scripts\upload-symbols.ps1 windows-${{ matrix.arch }}
|
|
|
|
- name: Upload ${{ matrix.arch }} build
|
|
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7
|
|
with:
|
|
name: windows-${{ matrix.arch }}-build
|
|
path: build/windows/${{ matrix.arch }}/runner/Release/
|
|
|
|
package-windows:
|
|
needs: build-windows
|
|
if: ${{ inputs.build_windows }}
|
|
runs-on: windows-latest
|
|
permissions:
|
|
id-token: write
|
|
attestations: write
|
|
contents: read
|
|
steps:
|
|
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
|
|
with:
|
|
persist-credentials: false
|
|
|
|
- name: Setup Flutter
|
|
uses: subosito/flutter-action@1a449444c387b1966244ae4d4f8c696479add0b2 # v2
|
|
with:
|
|
channel: "stable"
|
|
flutter-version: ${{ env.FLUTTER_VERSION }}
|
|
cache: true
|
|
cache-key: "${{ env.TRUSTED_BUILD_CACHE_VERSION }}-flutter-:os:-:channel:-:version:-:arch:-:hash:"
|
|
pub-cache: false
|
|
|
|
- name: Install dependencies
|
|
shell: pwsh
|
|
run: flutter pub get --enforce-lockfile --no-example
|
|
|
|
- name: Download x64 build
|
|
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8
|
|
with:
|
|
name: windows-x64-build
|
|
path: build-x64
|
|
|
|
- name: Download arm64 build
|
|
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8
|
|
with:
|
|
name: windows-arm64-build
|
|
path: build-arm64
|
|
|
|
- name: Read version from pubspec
|
|
id: version
|
|
shell: pwsh
|
|
run: |
|
|
$v = (Select-String -Path pubspec.yaml -Pattern '^version:\s*(\S+)').Matches[0].Groups[1].Value -replace '\+.*'
|
|
echo "version=$v" >> $env:GITHUB_OUTPUT
|
|
|
|
- name: Build installer and portables
|
|
run: .\windows\build-installer.ps1 -X64BuildDir "build-x64" -Arm64BuildDir "build-arm64" -Version "${{ steps.version.outputs.version }}"
|
|
|
|
# Unsigned on purpose: the Store re-signs the bundle during
|
|
# certification. See windows/build-msix.ps1.
|
|
- name: Build Store package (MSIX)
|
|
run: .\windows\build-msix.ps1 -X64BuildDir "build-x64" -Arm64BuildDir "build-arm64" -Version "${{ steps.version.outputs.version }}"
|
|
|
|
- name: Sign installer for WinSparkle (EdDSA)
|
|
if: env.SPARKLE_PRIVATE_KEY != ''
|
|
env:
|
|
SPARKLE_PRIVATE_KEY: ${{ secrets.SPARKLE_PRIVATE_KEY }}
|
|
shell: pwsh
|
|
run: |
|
|
$keyPath = Join-Path $env:RUNNER_TEMP "plezy-winsparkle-ed25519.pem"
|
|
try {
|
|
Set-Content -Path $keyPath -Value $env:SPARKLE_PRIVATE_KEY -Encoding ascii -NoNewline
|
|
$output = & dart run auto_updater:sign_update plezy-windows-installer.exe $keyPath
|
|
if ($LASTEXITCODE -ne 0) {
|
|
throw "WinSparkle signer failed with exit code $LASTEXITCODE"
|
|
}
|
|
$match = [regex]::Match($output, 'edSignature="([^"]*)"')
|
|
if (-not $match.Success) {
|
|
throw "WinSparkle signer returned no EdDSA signature"
|
|
}
|
|
Set-Content -Path win-ed-signature.txt -Value $match.Groups[1].Value -Encoding ascii -NoNewline
|
|
Set-Content -Path win-installer-size.txt -Value (Get-Item plezy-windows-installer.exe).Length.ToString() -Encoding ascii -NoNewline
|
|
} finally {
|
|
Remove-Item -Path $keyPath -Force -ErrorAction SilentlyContinue
|
|
}
|
|
|
|
- name: Attest Windows artifacts
|
|
uses: actions/attest-build-provenance@0f67c3f4856b2e3261c31976d6725780e5e4c373 # v4
|
|
with:
|
|
subject-path: |
|
|
plezy-windows-x64-portable.7z
|
|
plezy-windows-arm64-portable.7z
|
|
plezy-windows-installer.exe
|
|
plezy-windows.msixbundle
|
|
|
|
- name: Upload x64 portable
|
|
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7
|
|
with:
|
|
name: windows-x64-portable
|
|
path: plezy-windows-x64-portable.7z
|
|
|
|
- name: Upload arm64 portable
|
|
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7
|
|
with:
|
|
name: windows-arm64-portable
|
|
path: plezy-windows-arm64-portable.7z
|
|
|
|
- name: Upload installer
|
|
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7
|
|
with:
|
|
name: windows-installer
|
|
path: |
|
|
plezy-windows-installer.exe
|
|
win-ed-signature.txt
|
|
win-installer-size.txt
|
|
|
|
# Deliberately not attached to the GitHub release in create-release: a
|
|
# Store-identity package cannot be installed without the Store's
|
|
# certificate, so it is only useful as a Partner Center upload.
|
|
- name: Upload Store package
|
|
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7
|
|
with:
|
|
name: windows-msix
|
|
path: plezy-windows.msixbundle
|
|
|
|
build-linux:
|
|
needs: validate-trusted-ref
|
|
name: Build Linux (${{ matrix.arch }})
|
|
if: ${{ inputs.build_linux }}
|
|
runs-on: ${{ matrix.runner }}
|
|
permissions:
|
|
id-token: write
|
|
attestations: write
|
|
contents: read
|
|
strategy:
|
|
fail-fast: false
|
|
matrix:
|
|
include:
|
|
- arch: x64
|
|
runner: ubuntu-latest
|
|
flutter_channel: stable
|
|
pkg_config_arch: x86_64-linux-gnu
|
|
- arch: arm64
|
|
runner: ubuntu-24.04-arm
|
|
flutter_channel: master
|
|
pkg_config_arch: aarch64-linux-gnu
|
|
steps:
|
|
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
|
|
with:
|
|
persist-credentials: false
|
|
|
|
- name: Setup Flutter
|
|
uses: subosito/flutter-action@1a449444c387b1966244ae4d4f8c696479add0b2 # v2
|
|
with:
|
|
channel: ${{ matrix.flutter_channel }}
|
|
flutter-version: ${{ env.FLUTTER_VERSION }}
|
|
cache: true
|
|
cache-key: "${{ env.TRUSTED_BUILD_CACHE_VERSION }}-flutter-:os:-:channel:-:version:-:arch:-:hash:"
|
|
pub-cache: false
|
|
|
|
- name: Cache Pub dependencies
|
|
uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6
|
|
with:
|
|
path: |
|
|
~/.pub-cache
|
|
key: ${{ env.TRUSTED_BUILD_CACHE_VERSION }}-${{ runner.os }}-${{ runner.arch }}-pub-${{ hashFiles('pubspec.yaml', 'pubspec.lock') }}
|
|
|
|
- name: Cache APT packages
|
|
uses: awalsh128/cache-apt-pkgs-action@553a35bb8ebd9fcabcb1c9451aa4c98e1b4ca8a9 # latest
|
|
with:
|
|
packages: ${{ env.LINUX_APT_PACKAGES }}
|
|
version: trusted-build-v1.1
|
|
|
|
- name: Install Linux dependencies
|
|
shell: bash
|
|
run: |
|
|
read -r -a packages <<< "$LINUX_APT_PACKAGES"
|
|
|
|
for attempt in 1 2 3; do
|
|
if sudo apt-get update -o Acquire::Retries=3 && sudo apt-get install -y -o Acquire::Retries=3 "${packages[@]}"; then
|
|
exit 0
|
|
fi
|
|
|
|
sudo apt-get clean
|
|
sudo rm -rf /var/lib/apt/lists/*
|
|
sleep $((attempt * 15))
|
|
done
|
|
|
|
exit 1
|
|
|
|
- name: Cache libmpv build
|
|
id: libmpv-cache
|
|
uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6
|
|
with:
|
|
path: libmpv-prefix
|
|
key: ${{ env.TRUSTED_BUILD_CACHE_VERSION }}-libmpv-${{ runner.arch }}-${{ hashFiles('linux/packaging/build-libmpv.sh', 'linux/packaging/native-inputs.json') }}
|
|
|
|
- name: Build libmpv
|
|
if: steps.libmpv-cache.outputs.cache-hit != 'true'
|
|
shell: bash
|
|
run: bash linux/packaging/build-libmpv.sh
|
|
|
|
- name: Install fpm
|
|
shell: bash
|
|
run: sudo gem install fpm --version 1.17.0 --no-document
|
|
|
|
- name: Install dependencies
|
|
shell: bash
|
|
run: flutter pub get --enforce-lockfile --no-example
|
|
|
|
- name: Build Linux ${{ matrix.arch }}
|
|
shell: bash
|
|
run: flutter build linux --release ${{ env.RELEASE_DART_DEFINES }} --dart-define=SENTRY_DIST=github-linux-${{ matrix.arch }} --split-debug-info=debug-info/linux-${{ matrix.arch }}
|
|
env:
|
|
PKG_CONFIG_PATH: ${{ github.workspace }}/libmpv-prefix/lib/pkgconfig:${{ github.workspace }}/libmpv-prefix/lib/${{ matrix.pkg_config_arch }}/pkgconfig
|
|
|
|
- name: Upload symbols to bugs.plezy.app
|
|
if: github.repository == 'edde746/plezy'
|
|
shell: bash
|
|
env:
|
|
BUGS_ADMIN_TOKEN: ${{ secrets.BUGS_ADMIN_TOKEN }}
|
|
SENTRY_DIST: github-linux-${{ matrix.arch }}
|
|
run: ./scripts/upload-symbols.sh linux-${{ matrix.arch }}
|
|
|
|
- name: Resolve bundle directory
|
|
shell: bash
|
|
run: |
|
|
if [[ "${{ matrix.arch }}" == "x64" ]]; then
|
|
bundle_dir=build/linux/x64/release/bundle
|
|
else
|
|
bundle_dir=$(find build/linux -path "*/release/bundle" -type d | head -1)
|
|
fi
|
|
if [[ -z "$bundle_dir" || ! -d "$bundle_dir" ]]; then
|
|
echo "ERROR: Linux bundle directory not found" >&2
|
|
exit 1
|
|
fi
|
|
echo "BUNDLE_DIR=$bundle_dir" >> "$GITHUB_ENV"
|
|
|
|
- name: Build Linux Packages
|
|
shell: bash
|
|
run: |
|
|
BUILD_DIR="$BUNDLE_DIR" \
|
|
ARCH_SUFFIX=${{ matrix.arch }} \
|
|
OUTPUT_DIR="$GITHUB_WORKSPACE" \
|
|
python3 linux/packaging/build-packages.py
|
|
|
|
- name: Copy libmpv into bundle
|
|
shell: bash
|
|
run: |
|
|
BUNDLE_LIB="$BUNDLE_DIR/lib"
|
|
LIBMPV_DIR=$(dirname "$(find libmpv-prefix -name 'libmpv.so' | head -1)")
|
|
cp -a "$LIBMPV_DIR"/libmpv.so* "$BUNDLE_LIB/"
|
|
cp -a libmpv-prefix/lib/libshaderc_shared.so* "$BUNDLE_LIB/"
|
|
|
|
- name: Bundle shared libraries for portable tarball
|
|
shell: bash
|
|
run: bash linux/packaging/bundle-libs.sh "$BUNDLE_DIR"
|
|
|
|
- name: Copy wrapper script into bundle
|
|
shell: bash
|
|
run: cp linux/packaging/plezy.sh "$BUNDLE_DIR/plezy.sh"
|
|
|
|
- name: Verify no missing dependencies
|
|
shell: bash
|
|
run: |
|
|
cd "$BUNDLE_DIR"
|
|
MISSING=$(LD_LIBRARY_PATH=lib ldd ./plezy 2>&1 | grep "not found" || true)
|
|
if [[ -n "$MISSING" ]]; then
|
|
echo "ERROR: Unresolved dependencies found:" >&2
|
|
echo "$MISSING" >&2
|
|
exit 1
|
|
fi
|
|
echo "All dependencies resolved."
|
|
|
|
- name: Create tarball
|
|
shell: bash
|
|
run: |
|
|
cd "$BUNDLE_DIR"
|
|
tar -czf "$GITHUB_WORKSPACE/plezy-linux-${{ matrix.arch }}.tar.gz" *
|
|
|
|
- name: Attest Linux ${{ matrix.arch }} artifacts
|
|
uses: actions/attest-build-provenance@0f67c3f4856b2e3261c31976d6725780e5e4c373 # v4
|
|
with:
|
|
subject-path: |
|
|
plezy-linux-${{ matrix.arch }}.tar.gz
|
|
plezy-linux-${{ matrix.arch }}.deb
|
|
plezy-linux-${{ matrix.arch }}.rpm
|
|
plezy-linux-${{ matrix.arch }}.pkg.tar.zst
|
|
|
|
- name: Upload Linux ${{ matrix.arch }} artifacts
|
|
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7
|
|
with:
|
|
name: linux-${{ matrix.arch }}
|
|
path: |
|
|
plezy-linux-${{ matrix.arch }}.tar.gz
|
|
plezy-linux-${{ matrix.arch }}.deb
|
|
plezy-linux-${{ matrix.arch }}.rpm
|
|
plezy-linux-${{ matrix.arch }}.pkg.tar.zst
|
|
|
|
create-release:
|
|
needs: [validate-trusted-ref, build-android, build-ios, build-macos, build-windows, package-windows, build-linux]
|
|
if: ${{ always() && needs.validate-trusted-ref.result == 'success' && !contains(needs.*.result, 'failure') && !contains(needs.*.result, 'cancelled') && inputs.build_android && inputs.build_ios && inputs.build_macos && inputs.build_windows && inputs.build_linux }}
|
|
runs-on: ubuntu-latest
|
|
permissions:
|
|
contents: write
|
|
steps:
|
|
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
|
|
with:
|
|
sparse-checkout: pubspec.yaml
|
|
sparse-checkout-cone-mode: false
|
|
persist-credentials: false
|
|
|
|
- name: Read version from pubspec.yaml
|
|
id: version
|
|
run: |
|
|
VERSION=$(grep '^version:' pubspec.yaml | sed 's/version: //' | sed 's/+.*//')
|
|
BUILD_NUMBER=$(grep '^version:' pubspec.yaml | sed 's/.*+//')
|
|
echo "version=$VERSION" >> $GITHUB_OUTPUT
|
|
echo "build_number=$BUILD_NUMBER" >> $GITHUB_OUTPUT
|
|
|
|
- name: Download Android artifacts
|
|
if: ${{ inputs.build_android }}
|
|
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8
|
|
with:
|
|
name: android-apk
|
|
path: artifacts/android-apk
|
|
|
|
- name: Download iOS artifact
|
|
if: ${{ inputs.build_ios }}
|
|
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8
|
|
with:
|
|
name: ios-ipa
|
|
path: artifacts/ios-ipa
|
|
|
|
- name: Download macOS artifact
|
|
if: ${{ inputs.build_macos }}
|
|
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8
|
|
with:
|
|
name: macos-dmg
|
|
path: artifacts/macos-dmg
|
|
|
|
- name: Download Windows x64 artifact
|
|
if: ${{ inputs.build_windows }}
|
|
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8
|
|
with:
|
|
name: windows-x64-portable
|
|
path: artifacts/windows-x64-portable
|
|
|
|
- name: Download Windows arm64 artifact
|
|
if: ${{ inputs.build_windows }}
|
|
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8
|
|
with:
|
|
name: windows-arm64-portable
|
|
path: artifacts/windows-arm64-portable
|
|
|
|
- name: Download Windows installer artifact
|
|
if: ${{ inputs.build_windows }}
|
|
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8
|
|
with:
|
|
name: windows-installer
|
|
path: artifacts/windows-installer
|
|
|
|
- name: Download Linux x64 artifacts
|
|
if: ${{ inputs.build_linux }}
|
|
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8
|
|
with:
|
|
name: linux-x64
|
|
path: artifacts/linux-x64
|
|
|
|
- name: Download Linux arm64 artifacts
|
|
if: ${{ inputs.build_linux }}
|
|
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8
|
|
with:
|
|
name: linux-arm64
|
|
path: artifacts/linux-arm64
|
|
|
|
- name: Display structure of downloaded files
|
|
run: ls -R artifacts
|
|
|
|
- name: Generate appcast.xml
|
|
run: |
|
|
VERSION="${{ steps.version.outputs.version }}"
|
|
BUILD_NUMBER="${{ steps.version.outputs.build_number }}"
|
|
|
|
# Read macOS signature metadata (may be empty if secrets not configured)
|
|
MACOS_ED_SIG=""
|
|
MACOS_DMG_SIZE="0"
|
|
if [ -f artifacts/macos-dmg/macos-ed-signature.txt ]; then
|
|
MACOS_ED_SIG=$(cat artifacts/macos-dmg/macos-ed-signature.txt)
|
|
fi
|
|
if [ -f artifacts/macos-dmg/macos-dmg-size.txt ]; then
|
|
MACOS_DMG_SIZE=$(cat artifacts/macos-dmg/macos-dmg-size.txt)
|
|
fi
|
|
|
|
# Read Windows signature metadata (may be empty if secrets not configured)
|
|
WIN_ED_SIG=""
|
|
WIN_INSTALLER_SIZE="0"
|
|
if [ -f artifacts/windows-installer/win-ed-signature.txt ]; then
|
|
WIN_ED_SIG=$(cat artifacts/windows-installer/win-ed-signature.txt)
|
|
fi
|
|
if [ -f artifacts/windows-installer/win-installer-size.txt ]; then
|
|
WIN_INSTALLER_SIZE=$(cat artifacts/windows-installer/win-installer-size.txt)
|
|
fi
|
|
|
|
cat > appcast.xml << XMLEOF
|
|
<?xml version="1.0" encoding="utf-8"?>
|
|
<rss version="2.0" xmlns:sparkle="http://www.andymatuschak.org/xml-namespaces/sparkle">
|
|
<channel>
|
|
<title>Plezy Updates</title>
|
|
<item>
|
|
<title>Version ${VERSION}</title>
|
|
<sparkle:version>${BUILD_NUMBER}</sparkle:version>
|
|
<sparkle:shortVersionString>${VERSION}</sparkle:shortVersionString>
|
|
<sparkle:releaseNotesLink>https://gh-html.edde746.dev/edde746/plezy/${VERSION}</sparkle:releaseNotesLink>
|
|
XMLEOF
|
|
|
|
# macOS enclosure
|
|
if [ -n "$MACOS_ED_SIG" ]; then
|
|
cat >> appcast.xml << XMLEOF
|
|
<enclosure url="https://github.com/edde746/plezy/releases/download/${VERSION}/plezy-macos.dmg"
|
|
length="${MACOS_DMG_SIZE}" type="application/octet-stream"
|
|
sparkle:edSignature="${MACOS_ED_SIG}"
|
|
sparkle:os="macos" />
|
|
XMLEOF
|
|
fi
|
|
|
|
# Windows enclosure
|
|
if [ -n "$WIN_ED_SIG" ]; then
|
|
cat >> appcast.xml << XMLEOF
|
|
<enclosure url="https://github.com/edde746/plezy/releases/download/${VERSION}/plezy-windows-installer.exe"
|
|
length="${WIN_INSTALLER_SIZE}" type="application/octet-stream"
|
|
sparkle:edSignature="${WIN_ED_SIG}"
|
|
sparkle:installerArguments="/SILENT /SP-"
|
|
sparkle:os="windows" />
|
|
XMLEOF
|
|
fi
|
|
|
|
cat >> appcast.xml << 'XMLEOF'
|
|
</item>
|
|
</channel>
|
|
</rss>
|
|
XMLEOF
|
|
|
|
# Clean up leading whitespace from heredoc indentation
|
|
sed -i 's/^ //' appcast.xml
|
|
|
|
echo "Generated appcast.xml:"
|
|
cat appcast.xml
|
|
|
|
- name: Collect release files
|
|
id: release-files
|
|
run: |
|
|
{
|
|
echo 'files<<EOF'
|
|
if [ "${{ inputs.build_android }}" = "true" ]; then
|
|
echo artifacts/android-apk/plezy-android-arm64-v8a.tar.gz
|
|
echo artifacts/android-apk/plezy-android-armeabi-v7a.tar.gz
|
|
echo artifacts/android-apk/plezy-android-x86_64.tar.gz
|
|
fi
|
|
if [ "${{ inputs.build_ios }}" = "true" ]; then
|
|
echo artifacts/ios-ipa/plezy-ios.ipa
|
|
fi
|
|
if [ "${{ inputs.build_macos }}" = "true" ]; then
|
|
echo artifacts/macos-dmg/plezy-macos.dmg
|
|
fi
|
|
if [ "${{ inputs.build_windows }}" = "true" ]; then
|
|
echo artifacts/windows-x64-portable/plezy-windows-x64-portable.7z
|
|
echo artifacts/windows-arm64-portable/plezy-windows-arm64-portable.7z
|
|
echo artifacts/windows-installer/plezy-windows-installer.exe
|
|
fi
|
|
if [ "${{ inputs.build_linux }}" = "true" ]; then
|
|
echo 'artifacts/linux-x64/*'
|
|
echo 'artifacts/linux-arm64/*'
|
|
fi
|
|
echo appcast.xml
|
|
echo EOF
|
|
} >> "$GITHUB_OUTPUT"
|
|
|
|
- name: Create Release
|
|
uses: softprops/action-gh-release@3d0d9888cb7fd7b750713d6e236d1fcb99157228 # v3
|
|
with:
|
|
files: ${{ steps.release-files.outputs.files }}
|
|
draft: true
|
|
prerelease: false
|
|
env:
|
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|