name: Release on: push: tags: - "v*" workflow_dispatch: inputs: version: description: "Version to build (e.g. 1.1.4). Overrides tag when set." required: true type: string concurrency: group: release-${{ github.ref }}-${{ inputs.version || github.ref_name }} cancel-in-progress: true env: GRADLE_OPTS: -Dorg.gradle.jvmargs=-Xmx6g -Dkotlin.daemon.jvm.options=-Xmx6g jobs: resolve-version: runs-on: ubuntu-latest outputs: version: ${{ steps.ver.outputs.version }} tag: ${{ steps.ver.outputs.tag }} steps: - id: ver shell: bash run: | if [ "${{ github.event_name }}" = "workflow_dispatch" ]; then V="${{ inputs.version }}" else V="${GITHUB_REF_NAME#v}" fi if [[ ! "$V" =~ ^[0-9]+\.[0-9]+\.[0-9]+([.-].*)?$ ]]; then echo "Invalid version: $V" >&2 exit 1 fi echo "version=$V" >> "$GITHUB_OUTPUT" echo "tag=v$V" >> "$GITHUB_OUTPUT" macos-arm64: needs: resolve-version runs-on: macos-latest steps: - uses: actions/checkout@v4 - uses: actions/setup-java@v4 with: distribution: temurin java-version: "17" - name: Set version run: bash scripts/ci-set-version.sh "${{ needs.resolve-version.outputs.version }}" - name: Install create-dmg run: brew install create-dmg - name: Package macOS Apple Silicon run: | export FROMCHAT_PACKAGING_JDK="$JAVA_HOME" ./gradlew :app:desktop:packageReleaseMac -PdesktopArch=arm64 --no-daemon - uses: actions/upload-artifact@v4 with: name: macos-arm64 path: app/desktop/build/distributions/release/*-macOS-arm64.dmg if-no-files-found: error macos-x64: needs: resolve-version runs-on: macos-latest steps: - uses: actions/checkout@v4 - uses: actions/setup-java@v4 with: distribution: temurin java-version: "17" architecture: x64 - name: Set version run: bash scripts/ci-set-version.sh "${{ needs.resolve-version.outputs.version }}" - name: Install create-dmg run: brew install create-dmg - name: Package macOS Intel run: | export FROMCHAT_PACKAGING_JDK="$JAVA_HOME" ./gradlew :app:desktop:packageReleaseMac -PdesktopArch=x64 --no-daemon - uses: actions/upload-artifact@v4 with: name: macos-x64 path: app/desktop/build/distributions/release/*-macOS-x64.dmg if-no-files-found: error linux-x64: needs: resolve-version runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - uses: actions/setup-java@v4 with: distribution: temurin java-version: "17" - name: Install packaging tools run: | sudo apt-get update sudo apt-get install -y fakeroot rpm binutils libfuse2 wget wget -q https://github.com/AppImage/appimagetool/releases/download/continuous/appimagetool-x86_64.AppImage -O /tmp/appimagetool chmod +x /tmp/appimagetool echo "APPIMAGETOOL=/tmp/appimagetool" >> "$GITHUB_ENV" - name: Set version run: bash scripts/ci-set-version.sh "${{ needs.resolve-version.outputs.version }}" - name: Package Linux x64 run: | export FROMCHAT_PACKAGING_JDK="$JAVA_HOME" ./gradlew :app:desktop:packageReleaseLinux -PdesktopArch=x64 --no-daemon - uses: actions/upload-artifact@v4 with: name: linux-x64 path: | app/desktop/build/distributions/release/*-linux-x64.deb app/desktop/build/distributions/release/*-linux-x64.rpm app/desktop/build/distributions/release/*-linux-x64.AppImage if-no-files-found: error linux-arm64: needs: resolve-version runs-on: ubuntu-24.04-arm steps: - uses: actions/checkout@v4 - uses: actions/setup-java@v4 with: distribution: temurin java-version: "17" - name: Install packaging tools run: | sudo apt-get update sudo apt-get install -y fakeroot rpm binutils libfuse2 wget wget -q https://github.com/AppImage/appimagetool/releases/download/continuous/appimagetool-aarch64.AppImage -O /tmp/appimagetool chmod +x /tmp/appimagetool echo "APPIMAGETOOL=/tmp/appimagetool" >> "$GITHUB_ENV" - name: Set version run: bash scripts/ci-set-version.sh "${{ needs.resolve-version.outputs.version }}" - name: Package Linux ARM64 run: | export FROMCHAT_PACKAGING_JDK="$JAVA_HOME" ./gradlew :app:desktop:packageReleaseLinux -PdesktopArch=arm64 --no-daemon - uses: actions/upload-artifact@v4 with: name: linux-arm64 path: | app/desktop/build/distributions/release/*-linux-arm64.deb app/desktop/build/distributions/release/*-linux-arm64.rpm app/desktop/build/distributions/release/*-linux-arm64.AppImage if-no-files-found: error windows-x64: needs: resolve-version runs-on: windows-latest steps: - uses: actions/checkout@v4 - uses: actions/setup-java@v4 with: distribution: temurin java-version: "17" - uses: dtolnay/rust-toolchain@stable with: targets: x86_64-pc-windows-msvc - name: Set version shell: bash run: bash scripts/ci-set-version.sh "${{ needs.resolve-version.outputs.version }}" - name: Package Windows x64 shell: bash run: | export FROMCHAT_PACKAGING_JDK="$JAVA_HOME" ./gradlew :app:desktop:packageReleaseWindows -PdesktopArch=x64 --no-daemon - uses: actions/upload-artifact@v4 with: name: windows-x64 path: app/desktop/build/distributions/release/*-windows-x64.exe if-no-files-found: error - uses: actions/upload-artifact@v4 with: name: windows-x64-app-image path: app/desktop/build/compose/binaries/main-release/app/FromChat if-no-files-found: error windows-arm64: needs: resolve-version runs-on: windows-11-arm steps: - uses: actions/checkout@v4 - uses: actions/setup-java@v4 with: distribution: temurin java-version: "17" - uses: dtolnay/rust-toolchain@stable - name: Set version shell: bash run: bash scripts/ci-set-version.sh "${{ needs.resolve-version.outputs.version }}" - name: Package Windows ARM64 shell: bash run: | export FROMCHAT_PACKAGING_JDK="$JAVA_HOME" ./gradlew :app:desktop:packageReleaseWindows -PdesktopArch=arm64 --no-daemon - uses: actions/upload-artifact@v4 with: name: windows-arm64 path: app/desktop/build/distributions/release/*-windows-arm64.exe if-no-files-found: error - uses: actions/upload-artifact@v4 with: name: windows-arm64-app-image path: app/desktop/build/compose/binaries/main-release/app/FromChat if-no-files-found: error android: needs: resolve-version runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - uses: actions/setup-java@v4 with: distribution: temurin java-version: "17" - uses: android-actions/setup-android@v3 - name: Set version run: bash scripts/ci-set-version.sh "${{ needs.resolve-version.outputs.version }}" - name: Prepare Android signing env: KEYSTORE_BASE64: ${{ secrets.ANDROID_KEYSTORE_BASE64 }} GOOGLE_SERVICES_JSON: ${{ secrets.ANDROID_GOOGLE_SERVICES_JSON }} RELEASE_STORE_PASSWORD: ${{ secrets.ANDROID_RELEASE_STORE_PASSWORD }} RELEASE_KEY_PASSWORD: ${{ secrets.ANDROID_RELEASE_KEY_PASSWORD }} run: | if [[ -z "$KEYSTORE_BASE64" || -z "$GOOGLE_SERVICES_JSON" ]]; then echo "Missing ANDROID_KEYSTORE_BASE64 or ANDROID_GOOGLE_SERVICES_JSON secrets" >&2 exit 1 fi mkdir -p app/android/keys printf '%s' "$KEYSTORE_BASE64" | base64 -d > app/android/keys/release.jks keytool -genkeypair -noprompt \ -alias key0 -keyalg RSA -keysize 2048 -validity 10000 \ -dname "CN=FromChat Debug" \ -keystore app/android/keys/debug.jks \ -storepass android -keypass android cat > app/android/keys/keystore.properties < app/android/google-services.json - name: Build universal Android APK run: ./gradlew :app:android:assembleRelease --no-daemon - name: Stage APK run: | mkdir -p release-staging APK="$(find app/android/build/outputs/apk/release -name '*release*.apk' | head -n 1)" cp "$APK" "release-staging/FromChat-${{ needs.resolve-version.outputs.version }}-android-universal.apk" - uses: actions/upload-artifact@v4 with: name: android path: release-staging/*.apk if-no-files-found: error ios: needs: resolve-version runs-on: macos-latest steps: - uses: actions/checkout@v4 - uses: actions/setup-java@v4 with: distribution: temurin java-version: "17" - name: Set version run: bash scripts/ci-set-version.sh "${{ needs.resolve-version.outputs.version }}" - name: Package iOS IPA run: | mkdir -p release-staging bash scripts/package-ios-ipa.sh "${{ needs.resolve-version.outputs.version }}" release-staging - uses: actions/upload-artifact@v4 with: name: ios path: release-staging/*.ipa if-no-files-found: error publish: needs: - resolve-version - macos-arm64 - macos-x64 - linux-x64 - linux-arm64 - windows-x64 - windows-arm64 - android - ios runs-on: ubuntu-latest permissions: contents: write steps: - uses: actions/checkout@v4 - uses: actions/download-artifact@v4 with: path: artifacts - name: Collect release assets run: | mkdir -p release-assets find artifacts -type f \( \ -name '*.dmg' -o \ -name '*.deb' -o \ -name '*.rpm' -o \ -name '*.AppImage' -o \ -name '*.exe' -o \ -name '*.apk' -o \ -name '*.ipa' \ \) -exec cp {} release-assets/ \; ls -la release-assets for pattern in \ '*-windows-x64.exe' \ '*-windows-arm64.exe' \ '*-macOS-x64.dmg' \ '*-macOS-arm64.dmg' \ '*-linux-x64.deb' \ '*-linux-arm64.deb' \ '*-linux-x64.rpm' \ '*-linux-arm64.rpm' \ '*-linux-x64.AppImage' \ '*-linux-arm64.AppImage' \ '*-android-universal.apk' \ '*-ios.ipa' do if ! compgen -G "release-assets/$pattern" > /dev/null; then echo "Missing release asset: $pattern" >&2 exit 1 fi done - name: Publish GitHub Release uses: softprops/action-gh-release@v2 with: tag_name: ${{ needs.resolve-version.outputs.tag }} name: FromChat ${{ needs.resolve-version.outputs.version }} draft: false generate_release_notes: true files: release-assets/* env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}