Skip to content

Build and Release

Build and Release #35

Workflow file for this run

name: Build and Release
on:
release:
types: [created]
workflow_dispatch:
inputs:
version:
description: "Version to build (e.g., 1.0.11, leave empty for pubspec.yaml)"
required: false
default: ""
build_android:
description: "Build Android APKs"
required: false
default: true
type: boolean
build_ios:
description: "Build iOS IPA"
required: false
default: true
type: boolean
build_windows:
description: "Build Windows EXE"
required: false
default: true
type: boolean
build_linux:
description: "Build Linux (tar.gz + AppImage)"
required: false
default: true
type: boolean
build_flatpak:
description: "Build Flatpak bundle"
required: false
default: false
type: boolean
skip_tests:
description: "Skip running tests"
required: false
default: false
type: boolean
upload_to_release:
description: "Upload artifacts to GitHub Release (if tag exists)"
required: false
default: false
type: boolean
env:
FLUTTER_VERSION: "3.38.6"
jobs:
prepare:
name: Prepare Build
runs-on: ubuntu-latest
outputs:
version: ${{ steps.version.outputs.version }}
build_number: ${{ steps.version.outputs.build_number }}
is_release: ${{ github.event_name == 'release' }}
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Determine version
id: version
run: |
if [[ "${{ github.event_name }}" == "release" ]]; then
TAG_VERSION=$(echo "${{ github.ref_name }}" | sed 's/^v//')
elif [[ -n "${{ inputs.version }}" ]]; then
TAG_VERSION="${{ inputs.version }}"
else
TAG_VERSION=$(grep "^version:" pubspec.yaml | sed 's/^version: //' | cut -d'+' -f1)
fi
# Ensure semantic version format
if [[ "$TAG_VERSION" =~ ^[0-9]+\.[0-9]+$ ]]; then
TAG_VERSION="${TAG_VERSION}.0"
fi
# Accept prereleases like 1.4.1-beta1
if [[ ! "$TAG_VERSION" =~ ^[0-9]+\.[0-9]+\.[0-9]+(-[a-zA-Z0-9]+)?$ ]]; then
echo "Error: Invalid version format: $TAG_VERSION"
exit 1
fi
BUILD_NUMBER=${{ github.run_number }}
echo "version=$TAG_VERSION" >> $GITHUB_OUTPUT
echo "build_number=$BUILD_NUMBER" >> $GITHUB_OUTPUT
echo "Version: $TAG_VERSION+$BUILD_NUMBER"
build-android:
name: Build Android
needs: prepare
if: ${{ github.event_name == 'release' || inputs.build_android }}
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Set up JDK 17
uses: actions/setup-java@v4
with:
distribution: "temurin"
java-version: "17"
- name: Set up Flutter
uses: subosito/flutter-action@v2
with:
flutter-version: ${{ env.FLUTTER_VERSION }}
channel: "stable"
cache: true
- name: Cache Gradle
uses: actions/cache@v4
with:
path: |
~/.gradle/caches
~/.gradle/wrapper
key: gradle-${{ runner.os }}-${{ hashFiles('android/**/*.gradle*', 'android/**/gradle-wrapper.properties') }}
restore-keys: |
gradle-${{ runner.os }}-
- name: Decode Keystore
env:
KEYSTORE_BASE64: ${{ secrets.KEYSTORE_BASE64 }}
KEY_ALIAS: ${{ secrets.KEY_ALIAS }}
STORE_PASSWORD: ${{ secrets.STORE_PASSWORD }}
KEY_PASSWORD: ${{ secrets.KEY_PASSWORD }}
run: |
if [ -n "$KEYSTORE_BASE64" ]; then
echo "$KEYSTORE_BASE64" | base64 --decode > android/app/upload-keystore.jks
echo "storeFile=$GITHUB_WORKSPACE/android/app/upload-keystore.jks" > android/key.properties
echo "keyAlias=$KEY_ALIAS" >> android/key.properties
echo "storePassword=$STORE_PASSWORD" >> android/key.properties
echo "keyPassword=$KEY_PASSWORD" >> android/key.properties
fi
- name: Get dependencies
run: flutter pub get
- name: Update version
run: |
sed -i "s/^version: .*/version: ${{ needs.prepare.outputs.version }}+${{ needs.prepare.outputs.build_number }}/" pubspec.yaml
- name: Build APKs
run: |
flutter build apk --release
flutter build apk --split-per-abi --release
- name: Prepare artifacts
run: |
mkdir -p artifacts
cp build/app/outputs/flutter-apk/app-release.apk artifacts/openlibextended-android-universal-${{ needs.prepare.outputs.version }}.apk
cp build/app/outputs/flutter-apk/app-arm64-v8a-release.apk artifacts/openlibextended-android-arm64-${{ needs.prepare.outputs.version }}.apk
cp build/app/outputs/flutter-apk/app-armeabi-v7a-release.apk artifacts/openlibextended-android-armeabi-v7a-${{ needs.prepare.outputs.version }}.apk
cp build/app/outputs/flutter-apk/app-x86_64-release.apk artifacts/openlibextended-android-x86_64-${{ needs.prepare.outputs.version }}.apk || true
- name: Upload artifacts
uses: actions/upload-artifact@v4
with:
name: android-builds
path: artifacts/*.apk
retention-days: 7
build-ios:
name: Build iOS
needs: prepare
if: ${{ github.event_name == 'release' || inputs.build_ios }}
runs-on: macos-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Set up Flutter
uses: subosito/flutter-action@v2
with:
flutter-version: ${{ env.FLUTTER_VERSION }}
channel: "stable"
cache: true
- name: Cache CocoaPods
uses: actions/cache@v4
with:
path: ios/Pods
key: pods-${{ runner.os }}-${{ hashFiles('ios/Podfile.lock') }}
restore-keys: |
pods-${{ runner.os }}-
- name: Get dependencies
run: flutter pub get
- name: Update version
run: |
sed -i '' "s/^version: .*/version: ${{ needs.prepare.outputs.version }}+${{ needs.prepare.outputs.build_number }}/" pubspec.yaml
- name: Build iOS (no codesign)
run: flutter build ios --release --no-codesign
- name: Create IPA
run: |
mkdir -p artifacts
mkdir -p Payload
cp -r build/ios/iphoneos/Runner.app Payload/
zip -r artifacts/openlibextended-ios-${{ needs.prepare.outputs.version }}.ipa Payload
rm -rf Payload
- name: Upload artifacts
uses: actions/upload-artifact@v4
with:
name: ios-builds
path: artifacts/*.ipa
retention-days: 7
build-windows:
name: Build Windows
needs: prepare
if: ${{ github.event_name == 'release' || inputs.build_windows }}
runs-on: windows-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Set up Flutter
uses: subosito/flutter-action@v2
with:
flutter-version: ${{ env.FLUTTER_VERSION }}
channel: "stable"
cache: true
- name: Get dependencies
run: flutter pub get
- name: Update version
run: |
(Get-Content pubspec.yaml) -replace '^version: .*', "version: ${{ needs.prepare.outputs.version }}+${{ needs.prepare.outputs.build_number }}" | Set-Content pubspec.yaml
- name: Build Windows
run: flutter build windows --release
- name: Create installer with Inno Setup
run: |
choco install innosetup -y
@"
[Setup]
AppName=OpenlibExtended
AppVersion=${{ needs.prepare.outputs.version }}
AppPublisher=warreth
DefaultDirName={autopf}\OpenlibExtended
DefaultGroupName=OpenlibExtended
OutputDir=artifacts
OutputBaseFilename=openlibextended-windows-x64-${{ needs.prepare.outputs.version }}
Compression=lzma
SolidCompression=yes
ArchitecturesInstallIn64BitMode=x64compatible
[Files]
Source: "build\windows\x64\runner\Release\*"; DestDir: "{app}"; Flags: ignoreversion recursesubdirs
[Icons]
Name: "{group}\OpenlibExtended"; Filename: "{app}\OpenlibExtended.exe"
Name: "{commondesktop}\OpenlibExtended"; Filename: "{app}\OpenlibExtended.exe"
[Run]
Filename: "{app}\OpenlibExtended.exe"; Description: "Launch OpenlibExtended"; Flags: nowait postinstall skipifsilent
"@ | Out-File -FilePath "installer.iss" -Encoding UTF8
mkdir artifacts
& "C:\Program Files (x86)\Inno Setup 6\ISCC.exe" installer.iss
- name: Upload artifacts
uses: actions/upload-artifact@v4
with:
name: windows-builds
path: artifacts/*.exe
retention-days: 7
build-linux:
name: Build Linux
needs: prepare
if: ${{ github.event_name == 'release' || inputs.build_linux }}
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Install dependencies
run: |
sudo apt-get update
sudo apt-get install -y clang cmake ninja-build pkg-config libgtk-3-dev liblzma-dev libstdc++-12-dev libfuse2 libwebkit2gtk-4.1-dev
- name: Set up Flutter
uses: subosito/flutter-action@v2
with:
flutter-version: ${{ env.FLUTTER_VERSION }}
channel: "stable"
cache: true
- name: Build Linux
run: |
flutter pub get
sed -i "s/^version: .*/version: ${{ needs.prepare.outputs.version }}+${{ needs.prepare.outputs.build_number }}/" pubspec.yaml
flutter build linux --release
- name: Create AppImage
run: |
mkdir -p artifacts
wget -q https://github.com/AppImage/AppImageKit/releases/download/continuous/appimagetool-x86_64.AppImage
chmod +x appimagetool-x86_64.AppImage
mkdir -p AppDir/usr/{bin,lib,share/applications,share/icons/hicolor/256x256/apps}
cp -r build/linux/x64/release/bundle/* AppDir/usr/bin/
if [ -f "AppDir/usr/bin/OpenlibExtended" ]; then
mv AppDir/usr/bin/OpenlibExtended AppDir/usr/bin/openlibextended
fi
cp assets/icons/appIcon_foreground.png AppDir/usr/share/icons/hicolor/256x256/apps/openlibextended.png
cp assets/icons/appIcon_foreground.png AppDir/openlibextended.png
echo "[Desktop Entry]" > AppDir/openlibextended.desktop
echo "Name=OpenlibExtended" >> AppDir/openlibextended.desktop
echo "Comment=Download and read books from shadow library" >> AppDir/openlibextended.desktop
echo "Exec=openlibextended" >> AppDir/openlibextended.desktop
echo "Icon=openlibextended" >> AppDir/openlibextended.desktop
echo "Type=Application" >> AppDir/openlibextended.desktop
echo "Categories=Education;Literature;" >> AppDir/openlibextended.desktop
echo "Keywords=books;library;epub;pdf;reader;" >> AppDir/openlibextended.desktop
echo "#!/bin/bash" > AppDir/AppRun
echo "SELF=\$(readlink -f \"\$0\")" >> AppDir/AppRun
echo "HERE=\${SELF%/*}" >> AppDir/AppRun
echo "export PATH=\"\${HERE}/usr/bin/:\${PATH}\"" >> AppDir/AppRun
echo "export LD_LIBRARY_PATH=\"\${HERE}/usr/lib/:\${LD_LIBRARY_PATH}\"" >> AppDir/AppRun
echo "exec \"\${HERE}/usr/bin/openlibextended\" \"\$@\"" >> AppDir/AppRun
chmod +x AppDir/AppRun
ARCH=x86_64 ./appimagetool-x86_64.AppImage --no-appstream AppDir artifacts/openlibextended-linux-x64-${{ needs.prepare.outputs.version }}.AppImage
- name: Create tar.gz archive
run: |
cd build/linux/x64/release/bundle
tar -czvf ${{ github.workspace }}/artifacts/openlibextended-linux-x64-${{ needs.prepare.outputs.version }}.tar.gz *
- name: Upload artifacts
uses: actions/upload-artifact@v4
with:
name: linux-builds
path: artifacts/*
retention-days: 7
build-flatpak:
name: Build Flatpak
needs: [prepare, build-linux]
if: ${{ inputs.build_flatpak == true && inputs.build_linux == true }}
runs-on: ubuntu-latest
container:
image: bilelmoussaoui/flatpak-github-actions:freedesktop-24.08
options: --privileged
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Download Linux build artifacts
uses: actions/download-artifact@v4
with:
name: linux-builds
path: linux-artifacts
- name: Extract Linux bundle
run: |
mkdir -p build/linux/x64/release/bundle
tar -xzf linux-artifacts/openlibextended-linux-x64-${{ needs.prepare.outputs.version }}.tar.gz -C build/linux/x64/release/bundle
- name: Create Flatpak manifest
run: |
echo "app-id: dev.wath.openlibextended" > dev.wath.openlibextended.yml
echo "runtime: org.freedesktop.Platform" >> dev.wath.openlibextended.yml
echo "runtime-version: '24.08'" >> dev.wath.openlibextended.yml
echo "sdk: org.freedesktop.Sdk" >> dev.wath.openlibextended.yml
echo "command: openlibextended" >> dev.wath.openlibextended.yml
echo "finish-args:" >> dev.wath.openlibextended.yml
echo " - --share=ipc" >> dev.wath.openlibextended.yml
echo " - --socket=fallback-x11" >> dev.wath.openlibextended.yml
echo " - --socket=wayland" >> dev.wath.openlibextended.yml
echo " - --device=dri" >> dev.wath.openlibextended.yml
echo " - --share=network" >> dev.wath.openlibextended.yml
echo " - --filesystem=home" >> dev.wath.openlibextended.yml
echo "modules:" >> dev.wath.openlibextended.yml
echo " - name: openlibextended" >> dev.wath.openlibextended.yml
echo " buildsystem: simple" >> dev.wath.openlibextended.yml
echo " build-commands:" >> dev.wath.openlibextended.yml
echo " - cp -r bundle /app/" >> dev.wath.openlibextended.yml
echo " - ln -s /app/bundle/OpenlibExtended /app/bin/openlibextended" >> dev.wath.openlibextended.yml
echo " sources:" >> dev.wath.openlibextended.yml
echo " - type: dir" >> dev.wath.openlibextended.yml
echo " path: build/linux/x64/release/bundle" >> dev.wath.openlibextended.yml
echo " dest: bundle" >> dev.wath.openlibextended.yml
- name: Build Flatpak
uses: flatpak/flatpak-github-actions/flatpak-builder@v6
with:
bundle: openlibextended-linux-${{ needs.prepare.outputs.version }}.flatpak
manifest-path: dev.wath.openlibextended.yml
cache-key: flatpak-builder-${{ github.sha }}
- name: Upload artifacts
uses: actions/upload-artifact@v4
with:
name: flatpak-builds
path: "*.flatpak"
retention-days: 7
release:
name: Upload to Release
needs: [prepare]
if: ${{ (github.event_name == 'release') || (inputs.upload_to_release == true) }}
runs-on: ubuntu-latest
permissions:
contents: write
steps:
- name: Download all artifacts
uses: actions/download-artifact@v4
with:
path: artifacts
merge-multiple: true
- name: List artifacts
run: ls -la artifacts/ || echo "No artifacts found"
- name: Check if tag exists
id: tagcheck
run: |
tag="v${{ needs.prepare.outputs.version }}"
if git ls-remote --tags origin | grep -q "refs/tags/$tag"; then
echo "upload_ok=true" >> $GITHUB_OUTPUT
else
echo "upload_ok=false" >> $GITHUB_OUTPUT
- name: Upload to Release
if: steps.tagcheck.outputs.upload_ok == 'true'
uses: softprops/action-gh-release@v2
with:
files: |
artifacts/*
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}