Skip to content

build: align minimum Flutter toolchain #44

build: align minimum Flutter toolchain

build: align minimum Flutter toolchain #44

# Build and release multi-platform Flutter example app
# This workflow is reusable - just update the env variables at the top
name: Build All Platforms
on:
push:
branches: [main]
pull_request:
branches: [main]
workflow_dispatch:
permissions:
contents: read
#####################################
# PROJECT-SPECIFIC CONFIGURATION
# Update these values for your project
#####################################
env:
# Project Info
PROJECT_NAME: FJS Example
PROJECT_SLUG: fjs-example
PROJECT_PACKAGE: fjs_example
EXAMPLE_DIR: example
# Android signing configuration
ANDROID_KEYSTORE_FILE: keystore.jks
ANDROID_KEYSTORE_SECRET: fjs123456
ANDROID_KEY_ALIAS: release
ANDROID_KEY_PASSWORD: fjs123456
ANDROID_KEY_DNAME: 'CN=FJS Example Release,O=FlutterCandies,C=CN'
# Flutter configuration
FLUTTER_CHANNEL: stable
ANDROID_COMPAT_FLUTTER_VERSION: 3.44.0
jobs:
publish-precompiled:
needs: quality
if: github.event_name != 'pull_request'
uses: ./.github/workflows/precompile-binaries.yml
permissions:
contents: write
secrets: inherit
#####################################
# Production quality gates
#####################################
quality:
name: Production quality gates
runs-on: ubuntu-latest
timeout-minutes: 60
permissions:
contents: read
steps:
- name: Checkout
uses: actions/checkout@v7
- name: Setup Flutter
uses: subosito/flutter-action@v2
with:
flutter-version: ${{ env.ANDROID_COMPAT_FLUTTER_VERSION }}
cache: true
- name: Setup stable Rust with quality components
uses: dtolnay/rust-toolchain@stable
with:
components: rustfmt, clippy
- name: Install Linux build dependencies
run: |
sudo apt-get update
sudo apt-get install -y clang cmake ninja-build pkg-config libssl-dev
- name: Install cargo-audit
run: cargo install cargo-audit --version 0.22.2 --locked
- name: Resolve root dependencies
run: flutter pub get --no-example
- name: Resolve CargoKit dependencies
run: dart pub get
working-directory: cargokit/build_tool
- name: Resolve example dependencies
run: flutter pub get
working-directory: ${{ env.EXAMPLE_DIR }}
- name: Verify dependency resolution leaves tracked files unchanged
run: git diff HEAD --exit-code --
- name: Check Rust formatting
run: cargo fmt --manifest-path libfjs/Cargo.toml --check
- name: Lint all Rust targets and features
run: cargo clippy --manifest-path libfjs/Cargo.toml --all-targets --all-features -- -D warnings
- name: Test all Rust targets and features
run: cargo test --manifest-path libfjs/Cargo.toml --all-targets --all-features
- name: Check Rust documentation
run: cargo doc --manifest-path libfjs/Cargo.toml --all-features --no-deps
env:
RUSTDOCFLAGS: -D warnings
- name: Audit Rust lockfile with repository policy
run: cargo audit --file libfjs/Cargo.lock
- name: Test CargoKit
run: dart test
working-directory: cargokit/build_tool
- name: Test FRB content-hash validation
run: flutter test test/tool/check_frb_content_hash_test.dart
- name: Analyze production Dart and Flutter sources
run: flutter analyze --fatal-infos --fatal-warnings
#####################################
# Prepare validated Darwin package
#####################################
prepare-darwin:
name: Prepare Darwin release package
runs-on: macos-latest
needs: quality
timeout-minutes: 90
permissions:
contents: read
steps:
- name: Checkout
uses: actions/checkout@v7
- name: Setup Flutter 3.44.0
uses: subosito/flutter-action@v2
with:
flutter-version: ${{ env.ANDROID_COMPAT_FLUTTER_VERSION }}
cache: true
- name: Setup stable Rust
uses: dtolnay/rust-toolchain@stable
- name: Install nightly Rust with rustfmt
run: rustup toolchain install nightly --profile minimal --component rustfmt
- name: Install FRB codegen 2.12.0
run: cargo install flutter_rust_bridge_codegen --version 2.12.0 --locked
- name: Resolve root dependencies
run: flutter pub get --no-example
- name: Verify tracked release provenance
run: git diff HEAD --exit-code --
- name: Prepare and validate Darwin release package
run: tool/prepare_darwin_release.sh --configuration Release --artifact-dir build/darwin-release
- name: Upload validated Darwin release package
uses: actions/upload-artifact@v7
with:
name: darwin-release
path: |
build/darwin-release/fjs.xcframework.zip
build/darwin-release/fjs.xcframework.zip.checksum
retention-days: 30
if-no-files-found: error
#####################################
# Prepare release info
#####################################
prepare:
runs-on: ubuntu-latest
outputs:
release_tag: ${{ steps.tag.outputs.tag }}
release_name: ${{ steps.tag.outputs.name }}
project_version: ${{ steps.version.outputs.project_version }}
steps:
- name: Checkout
uses: actions/checkout@v7
with:
fetch-depth: 0
- name: Generate release tag
id: tag
run: |
DATE=$(date +'%Y%m%d')
SHORT_REF=$(git rev-parse --short HEAD)
echo "tag=$DATE-$SHORT_REF" >> $GITHUB_OUTPUT
echo "name=Release $DATE-$SHORT_REF" >> $GITHUB_OUTPUT
- name: Read project version
id: version
run: |
VERSION=$(grep '^version:' ${{ env.EXAMPLE_DIR }}/pubspec.yaml | head -n1 | awk '{print $2}' | cut -d'+' -f1)
echo "project_version=$VERSION" >> $GITHUB_OUTPUT
#####################################
# Android build (multi-architecture)
#####################################
build-android:
runs-on: ubuntu-latest
needs: [prepare, quality]
strategy:
matrix:
arch: [arm64, x64, universal]
steps:
- name: Checkout
uses: actions/checkout@v7
- name: Setup Flutter
uses: subosito/flutter-action@v2
with:
channel: ${{ env.FLUTTER_CHANNEL }}
cache: true
- name: Setup Java
uses: actions/setup-java@v5
with:
distribution: 'zulu'
java-version: '17'
- name: Get dependencies
run: flutter pub get
working-directory: ${{ env.EXAMPLE_DIR }}
- name: Generate Android keystore
run: |
cd ${{ env.EXAMPLE_DIR }}/android/app
if [ -n "$KEYSTORE_BASE64" ]; then
echo "$KEYSTORE_BASE64" | base64 -d > ${{ env.ANDROID_KEYSTORE_FILE }}
else
keytool -genkey -v -keystore ${{ env.ANDROID_KEYSTORE_FILE }} \
-alias ${{ env.ANDROID_KEY_ALIAS }} \
-keyalg RSA -keysize 2048 -validity 36135 \
-storepass '${{ env.ANDROID_KEYSTORE_SECRET }}' \
-keypass '${{ env.ANDROID_KEY_PASSWORD }}' \
-dname '${{ env.ANDROID_KEY_DNAME }}'
fi
if ! grep -q "${{ env.ANDROID_KEYSTORE_FILE }}" .gitignore 2>/dev/null; then
echo "${{ env.ANDROID_KEYSTORE_FILE }}" >> .gitignore
fi
env:
KEYSTORE_BASE64: ${{ secrets.ANDROID_KEYSTORE_BASE64 }}
- name: Configure Android signing
run: |
cd ${{ env.EXAMPLE_DIR }}/android/app
printf '\n# Signing config\n' >> gradle.properties
printf 'RELEASE_STORE_FILE=${{ env.ANDROID_KEYSTORE_FILE }}\n' >> gradle.properties
printf 'RELEASE_STORE_PASSWORD=${{ env.ANDROID_KEYSTORE_SECRET }}\n' >> gradle.properties
printf 'RELEASE_KEY_ALIAS=${{ env.ANDROID_KEY_ALIAS }}\n' >> gradle.properties
printf 'RELEASE_KEY_PASSWORD=${{ env.ANDROID_KEY_PASSWORD }}\n' >> gradle.properties
cp build.gradle build.gradle.orig
awk '
/^android \{/ {
print
print ""
print " signingConfigs {"
print " release {"
print " storeFile file(\"${{ env.ANDROID_KEYSTORE_FILE }}\")"
print " storePassword \"${{ env.ANDROID_KEYSTORE_SECRET }}\""
print " keyAlias \"${{ env.ANDROID_KEY_ALIAS }}\""
print " keyPassword \"${{ env.ANDROID_KEY_PASSWORD }}\""
print " }"
print " }"
next
}
/signingConfig = signingConfigs\.debug/ {
print " signingConfig signingConfigs.release"
next
}
{ print }
' build.gradle.orig > build.gradle
- name: Build APK for ${{ matrix.arch }}
run: |
cd ${{ env.EXAMPLE_DIR }}
if [ "${{ matrix.arch }}" = "universal" ]; then
flutter build apk --release --target-platform android-arm64,android-x64
else
flutter build apk --release --target-platform android-${{ matrix.arch }}
fi
- name: Rename APK
run: |
cd ${{ env.EXAMPLE_DIR }}/build/app/outputs/flutter-apk
if [ "${{ matrix.arch }}" = "universal" ]; then
mv app-release.apk ${{ env.PROJECT_SLUG }}-android-universal.apk
else
mv app-release.apk ${{ env.PROJECT_SLUG }}-android-${{ matrix.arch }}.apk
fi
- name: Enable Android emulator acceleration
if: matrix.arch == 'universal'
run: |
echo 'KERNEL=="kvm", GROUP="kvm", MODE="0666", OPTIONS+="static_node=kvm"' | sudo tee /etc/udev/rules.d/99-kvm4all.rules
sudo udevadm control --reload-rules
sudo udevadm trigger --name-match=kvm
- name: Run Android cockpit verification
if: matrix.arch == 'universal'
uses: reactivecircus/android-emulator-runner@v2
with:
api-level: 35
target: google_apis
arch: x86_64
profile: pixel_7_pro
script: >-
cd ${{ env.EXAMPLE_DIR }} &&
dart run tool/ci_cockpit_verify.dart
--platform android
--device-id emulator-5554
--output-dir .dart_tool/flutter_cockpit/ci-android
--launch-timeout-seconds 1200
- name: Upload Android cockpit evidence
if: always() && matrix.arch == 'universal'
uses: actions/upload-artifact@v7
with:
name: cockpit-android
path: ${{ env.EXAMPLE_DIR }}/.dart_tool/flutter_cockpit/ci-android
retention-days: 14
if-no-files-found: ignore
- name: Upload APK artifact
uses: actions/upload-artifact@v7
with:
name: android-${{ matrix.arch }}
path: |
${{ env.EXAMPLE_DIR }}/build/app/outputs/flutter-apk/${{ env.PROJECT_SLUG }}-android-${{ matrix.arch }}.apk
${{ env.EXAMPLE_DIR }}/build/app/outputs/flutter-apk/${{ env.PROJECT_SLUG }}-android-universal.apk
retention-days: 30
if-no-files-found: ignore
#####################################
# Android Gradle compatibility (issue 19)
#####################################
android-compatibility:
name: Android compatibility (${{ matrix.name }})
runs-on: ubuntu-latest
needs: quality
timeout-minutes: 60
permissions:
contents: read
strategy:
matrix:
include:
- name: Gradle 9.1 / AGP 9.0.1 / Kotlin 2.3.20
compatibility: committed
- name: Gradle 8.9 / AGP 8.7.3 / Kotlin 2.1.0
compatibility: legacy
steps:
- name: Checkout
uses: actions/checkout@v7
- name: Setup Flutter 3.44.0
uses: subosito/flutter-action@v2
with:
flutter-version: ${{ env.ANDROID_COMPAT_FLUTTER_VERSION }}
cache: true
- name: Setup Java
uses: actions/setup-java@v5
with:
distribution: zulu
java-version: '17'
- name: Setup stable Rust
uses: dtolnay/rust-toolchain@stable
- name: Select compatibility source
id: source
shell: bash
run: |
set -euo pipefail
flutter --version | grep -F "Flutter ${{ env.ANDROID_COMPAT_FLUTTER_VERSION }} "
if [ "${{ matrix.compatibility }}" = "committed" ]; then
grep -Fx 'distributionUrl=https\://services.gradle.org/distributions/gradle-9.1.0-all.zip' example/android/gradle/wrapper/gradle-wrapper.properties
grep -Fx ' id "com.android.application" version "9.0.1" apply false' example/android/settings.gradle
grep -Fx ' id "org.jetbrains.kotlin.android" version "2.3.20" apply false' example/android/settings.gradle
source_dir="$GITHUB_WORKSPACE"
else
source_dir="$RUNNER_TEMP/fjs-gradle-8"
mkdir -p "$source_dir"
git archive HEAD | tar -x -C "$source_dir"
sed -i 's/gradle-9\.1\.0-all\.zip/gradle-8.9-all.zip/' "$source_dir/example/android/gradle/wrapper/gradle-wrapper.properties"
sed -i 's/version "9\.0\.1"/version "8.7.3"/' "$source_dir/example/android/settings.gradle"
sed -i 's/version "2\.3\.20"/version "2.1.0"/' "$source_dir/example/android/settings.gradle"
sed -i '/compileSdk = 36/a\ ndkVersion = flutter.ndkVersion' "$source_dir/example/android/app/build.gradle"
grep -Fx 'distributionUrl=https\://services.gradle.org/distributions/gradle-8.9-all.zip' "$source_dir/example/android/gradle/wrapper/gradle-wrapper.properties"
grep -Fx ' id "com.android.application" version "8.7.3" apply false' "$source_dir/example/android/settings.gradle"
grep -Fx ' id "org.jetbrains.kotlin.android" version "2.1.0" apply false' "$source_dir/example/android/settings.gradle"
grep -Fx ' ndkVersion = flutter.ndkVersion' "$source_dir/example/android/app/build.gradle"
fi
echo "directory=$source_dir" >> "$GITHUB_OUTPUT"
- name: Resolve compatibility dependencies
run: flutter pub get
working-directory: ${{ steps.source.outputs.directory }}/example
- name: Build arm64 split release APK
shell: bash
run: |
set -euo pipefail
build_log="$RUNNER_TEMP/android-${{ matrix.compatibility }}.log"
flutter build apk --release --split-per-abi --target-platform android-arm64 2>&1 | tee "$build_log"
grep -F 'Environment variable CARGOKIT_CONFIGURATION: release' "$build_log"
grep -F 'INFO: Building fjs for aarch64-linux-android' "$build_log"
if awk '
BEGIN { RS = "" }
{
record = tolower($0)
if (record ~ /(warning|warn|deprecated|deprecation)/ &&
record ~ /(cargokit|plugin\.gradle|build_tool)/) {
print $0
found = 1
}
}
END { exit found ? 0 : 1 }
' "$build_log"; then
echo 'CargoKit emitted a compatibility warning or deprecation.' >&2
exit 1
fi
working-directory: ${{ steps.source.outputs.directory }}/example
env:
CI: 'true'
GRADLE_OPTS: -Dorg.gradle.warning.mode=all
- name: Verify arm64 split release APK
run: test -f build/app/outputs/flutter-apk/app-arm64-v8a-release.apk
working-directory: ${{ steps.source.outputs.directory }}/example
#####################################
# iOS build
#####################################
build-ios:
runs-on: macos-latest
needs: [prepare, quality, prepare-darwin]
steps:
- name: Checkout
uses: actions/checkout@v7
- name: Setup Flutter
uses: subosito/flutter-action@v2
with:
channel: ${{ env.FLUTTER_CHANNEL }}
cache: true
- name: Download validated Darwin release package
uses: actions/download-artifact@v8
with:
name: darwin-release
path: darwin/fjs/Binaries
- name: Validate downloaded Darwin release package
run: tool/check_darwin_package_support.sh --require-artifact
- name: Get dependencies
run: flutter pub get
working-directory: ${{ env.EXAMPLE_DIR }}
- name: Build iOS (no codesign)
run: |
cd ${{ env.EXAMPLE_DIR }}
flutter build ios --release --no-codesign
- name: Run iOS cockpit verification
run: |
xcrun simctl list devices available -j > /tmp/ios-devices.json
DEVICE_ID=$(python3 -c 'import json; data=json.load(open("/tmp/ios-devices.json", encoding="utf-8")); print(next(d["udid"] for runtime, devices in data["devices"].items() if "iOS" in runtime for d in devices if d.get("isAvailable") and d.get("name", "").startswith("iPhone")))')
xcrun simctl boot "$DEVICE_ID" || true
xcrun simctl bootstatus "$DEVICE_ID" -b
cd ${{ env.EXAMPLE_DIR }}
dart run tool/ci_cockpit_verify.dart \
--platform ios \
--device-id "$DEVICE_ID" \
--output-dir .dart_tool/flutter_cockpit/ci-ios \
--launch-timeout-seconds 1200
- name: Upload iOS cockpit evidence
if: always()
uses: actions/upload-artifact@v7
with:
name: cockpit-ios
path: ${{ env.EXAMPLE_DIR }}/.dart_tool/flutter_cockpit/ci-ios
retention-days: 14
if-no-files-found: ignore
- name: Create iOS bundle (zip)
run: |
cd ${{ env.EXAMPLE_DIR }}
mkdir -p build/ios-bundle/Runner.app
cp -r build/ios/iphoneos/Runner.app/* build/ios-bundle/Runner.app/
cd build/ios-bundle
zip -r ../../${{ env.PROJECT_SLUG }}-ios.zip .
cd ../..
- name: Create IPA
run: |
cd ${{ env.EXAMPLE_DIR }}
mkdir -p Payload
cp -r build/ios/iphoneos/Runner.app Payload/
zip -r ${{ env.PROJECT_SLUG }}-ios.ipa Payload
rm -rf Payload
- name: Upload iOS artifacts
uses: actions/upload-artifact@v7
with:
name: ios
path: |
${{ env.EXAMPLE_DIR }}/${{ env.PROJECT_SLUG }}-ios.zip
${{ env.EXAMPLE_DIR }}/${{ env.PROJECT_SLUG }}-ios.ipa
retention-days: 30
#####################################
# Windows build
#####################################
build-windows:
runs-on: windows-latest
needs: [prepare, quality]
steps:
- name: Checkout
uses: actions/checkout@v7
- name: Setup Flutter
uses: subosito/flutter-action@v2
with:
channel: ${{ env.FLUTTER_CHANNEL }}
cache: true
- name: Get dependencies
run: flutter pub get
working-directory: ${{ env.EXAMPLE_DIR }}
- name: Install Inno Setup
run: |
choco install innosetup -y
- name: Build Windows
run: |
cd ${{ env.EXAMPLE_DIR }}
flutter build windows --release
- name: Run Windows cockpit verification
run: |
cd ${{ env.EXAMPLE_DIR }}
dart run tool/ci_cockpit_verify.dart `
--platform windows `
--output-dir .dart_tool/flutter_cockpit/ci-windows `
--launch-timeout-seconds 1200
- name: Upload Windows cockpit evidence
if: always()
uses: actions/upload-artifact@v7
with:
name: cockpit-windows
path: ${{ env.EXAMPLE_DIR }}/.dart_tool/flutter_cockpit/ci-windows
retention-days: 14
if-no-files-found: ignore
- name: Create Inno Setup script
shell: pwsh
run: |
$script = @"
[Setup]
AppName=${{ env.PROJECT_NAME }}
AppVersion=${{ needs.prepare.outputs.project_version }}
DefaultDirName={pf}\${{ env.PROJECT_NAME }}
DefaultGroupName=${{ env.PROJECT_NAME }}
OutputBaseFilename=${{ env.PROJECT_SLUG }}-windows-setup
Compression=lzma2
SolidCompression=yes
OutputDir=.
[Files]
Source: "build\windows\x64\runner\Release\*"; DestDir: "{app}"; Flags: ignoreversion recursesubdirs createallsubdirs
[Icons]
Name: "{group}\${{ env.PROJECT_NAME }}"; Filename: "{app}\${{ env.PROJECT_PACKAGE }}.exe"
Name: "{commondesktop}\${{ env.PROJECT_NAME }}"; Filename: "{app}\${{ env.PROJECT_PACKAGE }}.exe"
"@
$script | Out-File -FilePath ${{ env.EXAMPLE_DIR }}\setup.iss -Encoding UTF8
- name: Create installer with Inno Setup
run: |
cd ${{ env.EXAMPLE_DIR }}
& "C:\Program Files (x86)\Inno Setup 6\ISCC.exe" setup.iss
- name: Create Windows zip
run: |
cd ${{ env.EXAMPLE_DIR }}
Compress-Archive -Path build\windows\x64\runner\Release\* -DestinationPath ${{ env.PROJECT_SLUG }}-windows.zip
- name: Upload Windows artifacts
uses: actions/upload-artifact@v7
with:
name: windows
path: |
${{ env.EXAMPLE_DIR }}/${{ env.PROJECT_SLUG }}-windows.zip
${{ env.EXAMPLE_DIR }}/${{ env.PROJECT_SLUG }}-windows-setup.exe
retention-days: 30
if-no-files-found: ignore
#####################################
# Linux build
#####################################
build-linux:
runs-on: ubuntu-latest
needs: [prepare, quality]
steps:
- name: Checkout
uses: actions/checkout@v7
- name: Setup Flutter
uses: subosito/flutter-action@v2
with:
channel: ${{ env.FLUTTER_CHANNEL }}
cache: true
- name: Install Linux dependencies
run: |
sudo apt-get update
sudo apt-get install -y clang cmake ninja-build pkg-config libgtk-3-dev liblzma-dev libgstreamer1.0-dev libgstreamer-plugins-base1.0-dev xvfb
- name: Get dependencies
run: flutter pub get
working-directory: ${{ env.EXAMPLE_DIR }}
- name: Build Linux
run: |
cd ${{ env.EXAMPLE_DIR }}
flutter build linux --release
- name: Run Linux smoke test
run: |
cd ${{ env.EXAMPLE_DIR }}
xvfb-run -a flutter test integration_test/smoke_test.dart -d linux
- name: Run Linux cockpit verification
run: |
cd ${{ env.EXAMPLE_DIR }}
xvfb-run -a dart run tool/ci_cockpit_verify.dart \
--platform linux \
--output-dir .dart_tool/flutter_cockpit/ci-linux \
--launch-timeout-seconds 1200
- name: Upload Linux cockpit evidence
if: always()
uses: actions/upload-artifact@v7
with:
name: cockpit-linux
path: ${{ env.EXAMPLE_DIR }}/.dart_tool/flutter_cockpit/ci-linux
retention-days: 14
if-no-files-found: ignore
- name: Create Linux tarball
run: |
cd ${{ env.EXAMPLE_DIR }}
tar -czf ${{ env.PROJECT_SLUG }}-linux.tar.gz -C build/linux/x64/release/bundle .
- name: Upload Linux artifact
uses: actions/upload-artifact@v7
with:
name: linux
path: ${{ env.EXAMPLE_DIR }}/${{ env.PROJECT_SLUG }}-linux.tar.gz
retention-days: 30
#####################################
# macOS build
#####################################
build-macos:
runs-on: macos-latest
needs: [prepare, quality, prepare-darwin]
steps:
- name: Checkout
uses: actions/checkout@v7
- name: Setup Flutter
uses: subosito/flutter-action@v2
with:
channel: ${{ env.FLUTTER_CHANNEL }}
cache: true
- name: Download validated Darwin release package
uses: actions/download-artifact@v8
with:
name: darwin-release
path: darwin/fjs/Binaries
- name: Validate downloaded Darwin release package
run: tool/check_darwin_package_support.sh --require-artifact
- name: Get dependencies
run: flutter pub get
working-directory: ${{ env.EXAMPLE_DIR }}
- name: Build macOS
run: |
cd ${{ env.EXAMPLE_DIR }}
flutter build macos --release
- name: Run macOS cockpit verification
run: |
cd ${{ env.EXAMPLE_DIR }}
dart run tool/ci_cockpit_verify.dart \
--platform macos \
--output-dir .dart_tool/flutter_cockpit/ci-macos \
--launch-timeout-seconds 1200
- name: Upload macOS cockpit evidence
if: always()
uses: actions/upload-artifact@v7
with:
name: cockpit-macos
path: ${{ env.EXAMPLE_DIR }}/.dart_tool/flutter_cockpit/ci-macos
retention-days: 14
if-no-files-found: ignore
- name: Create macOS zip
run: |
cd ${{ env.EXAMPLE_DIR }}
cd build/macos/Build/Products/Release
zip -r ../../../../../${{ env.PROJECT_SLUG }}-macos.zip .
- name: Create DMG
run: |
cd ${{ env.EXAMPLE_DIR }}
mkdir -p dmg/disk
cp -r build/macos/Build/Products/Release/*.app dmg/disk/
hdiutil create -volname "${{ env.PROJECT_NAME }}" -srcfolder dmg/disk -ov -format UDZO ${{ env.PROJECT_SLUG }}-macos.dmg
rm -rf dmg
- name: Upload macOS artifacts
uses: actions/upload-artifact@v7
with:
name: macos
path: |
${{ env.EXAMPLE_DIR }}/${{ env.PROJECT_SLUG }}-macos.zip
${{ env.EXAMPLE_DIR }}/${{ env.PROJECT_SLUG }}-macos.dmg
retention-days: 30
#####################################
# Release all builds
#####################################
release:
runs-on: ubuntu-latest
needs: [publish-precompiled, prepare, prepare-darwin, android-compatibility, build-android, build-ios, build-windows, build-linux, build-macos]
if: github.event_name == 'push' && github.ref == 'refs/heads/main'
permissions:
contents: write
id-token: write
steps:
- name: Checkout
uses: actions/checkout@v7
- name: Download all artifacts
uses: actions/download-artifact@v8
with:
path: artifacts
- name: List downloaded artifacts
run: |
echo "=== Artifact tree ==="
tree artifacts/ || ls -laR artifacts/
- name: Create Release
uses: softprops/action-gh-release@v3
with:
tag_name: ${{ needs.prepare.outputs.release_tag }}
name: ${{ needs.prepare.outputs.release_name }}
draft: false
prerelease: false
generate_release_notes: true
files: |
artifacts/android-arm64/*.apk
artifacts/android-x64/*.apk
artifacts/android-universal/*.apk
artifacts/ios/*.ipa
artifacts/ios/*.zip
artifacts/windows/*.exe
artifacts/windows/*.zip
artifacts/linux/*.tar.gz
artifacts/macos/*.dmg
artifacts/macos/*.zip
artifacts/darwin-release/fjs.xcframework.zip
artifacts/darwin-release/fjs.xcframework.zip.checksum
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Create release summary
run: |
cat >> $GITHUB_STEP_SUMMARY << 'SUMMARY'
# ✅ Release Created Successfully
## Tag: ${{ needs.prepare.outputs.release_tag }}
## Artifacts
| Platform | Format | File |
|----------|--------|------|
| Android (arm64) | .apk | ${{ env.PROJECT_SLUG }}-android-arm64.apk |
| Android (x64) | .apk | ${{ env.PROJECT_SLUG }}-android-x64.apk |
| Android (Universal) | .apk | ${{ env.PROJECT_SLUG }}-android-universal.apk |
| iOS | .ipa | ${{ env.PROJECT_SLUG }}-ios.ipa |
| iOS | .zip | ${{ env.PROJECT_SLUG }}-ios.zip |
| Windows | .exe | ${{ env.PROJECT_SLUG }}-windows-setup.exe |
| Windows | .zip | ${{ env.PROJECT_SLUG }}-windows.zip |
| Linux | .tar.gz | ${{ env.PROJECT_SLUG }}-linux.tar.gz |
| macOS | .dmg | ${{ env.PROJECT_SLUG }}-macos.dmg |
| macOS | .zip | ${{ env.PROJECT_SLUG }}-macos.zip |
SUMMARY