Repository navigation
Release Desktop v2.1 #7
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: Build & Release | |
| on: | |
| push: | |
| tags: | |
| - 'v*' | |
| workflow_dispatch: | |
| permissions: | |
| contents: write | |
| jobs: | |
| build: | |
| strategy: | |
| matrix: | |
| include: | |
| - os: windows-latest | |
| name: Windows | |
| artifact: BalMasque_Windows | |
| ext: .exe | |
| - os: ubuntu-22.04 | |
| name: Linux | |
| artifact: BalMasque_Linux | |
| ext: "" | |
| - os: macos-15-intel | |
| name: Mac_Intel | |
| artifact: BalMasque_Mac_Intel | |
| ext: "" | |
| - os: macos-14 | |
| name: Mac_AppleSilicon | |
| artifact: BalMasque_Mac_AppleSilicon | |
| ext: "" | |
| runs-on: ${{ matrix.os }} | |
| name: Build ${{ matrix.name }} | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@v6 | |
| - name: Set up Python | |
| uses: actions/setup-python@v6 | |
| with: | |
| python-version: '3.11' | |
| - name: Install Linux dependencies | |
| if: runner.os == 'Linux' | |
| run: | | |
| sudo apt-get update | |
| sudo apt-get install -y python3-tk python3-dev | |
| - name: Install Python dependencies | |
| run: | | |
| python -m pip install --upgrade pip | |
| pip install -r requirements.txt | |
| pip install pyinstaller | |
| - name: Build with PyInstaller | |
| run: | | |
| if [ "$RUNNER_OS" == "Windows" ]; then | |
| SEP=";" | |
| else | |
| SEP=":" | |
| fi | |
| pyinstaller --onefile --windowed --name "BalMasque" --add-data "logo.png${SEP}." --icon logo.png bal_masque.py | |
| shell: bash | |
| - name: Prepare artifact (Windows) | |
| if: runner.os == 'Windows' | |
| run: | | |
| mkdir release | |
| cp dist/BalMasque.exe release/BalMasque.exe | |
| cp README.md release/ | |
| cp LICENSE release/ | |
| cd release && 7z a -tzip ../${{ matrix.artifact }}.zip * | |
| shell: bash | |
| - name: Prepare artifact (Linux/Mac) | |
| if: runner.os != 'Windows' | |
| run: | | |
| mkdir release | |
| if [ -d "dist/BalMasque.app" ]; then | |
| cp -r dist/BalMasque.app release/ | |
| else | |
| cp dist/BalMasque release/BalMasque | |
| chmod +x release/BalMasque | |
| fi | |
| cp README.md release/ | |
| cp LICENSE release/ | |
| cd release && tar czf ../${{ matrix.artifact }}.tar.gz * | |
| - name: Upload artifact | |
| uses: actions/upload-artifact@v6 | |
| with: | |
| name: ${{ matrix.artifact }} | |
| path: | | |
| ${{ matrix.artifact }}.zip | |
| ${{ matrix.artifact }}.tar.gz | |
| if-no-files-found: ignore | |
| build-android: | |
| runs-on: ubuntu-latest | |
| name: Build Android APK | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@v6 | |
| - name: Set up Python | |
| uses: actions/setup-python@v6 | |
| with: | |
| python-version: '3.11' | |
| - name: Set up Java 17 | |
| uses: actions/setup-java@v5 | |
| with: | |
| distribution: 'temurin' | |
| java-version: '17' | |
| - name: Install system dependencies | |
| run: | | |
| sudo apt-get update | |
| sudo apt-get install -y \ | |
| build-essential \ | |
| git \ | |
| zip \ | |
| unzip \ | |
| autoconf \ | |
| libtool \ | |
| pkg-config \ | |
| zlib1g-dev \ | |
| libncurses-dev \ | |
| cmake \ | |
| libffi-dev \ | |
| libssl-dev \ | |
| automake \ | |
| libltdl-dev \ | |
| lld | |
| - name: Install build tools and dependencies | |
| run: | | |
| pip install --upgrade pip setuptools wheel | |
| pip install buildozer cython==3.0.11 virtualenv | |
| - name: Pre-build checks | |
| run: | | |
| echo "── Checking critical source files ──" | |
| for f in bal_masque_mobile.py buildozer.spec logo.png intent_filter.xml; do | |
| if [ ! -f "$f" ]; then | |
| echo "::error::Missing critical file: $f" | |
| exit 1 | |
| fi | |
| done | |
| echo "── Checking Python 3 syntax ──" | |
| python -m py_compile bal_masque_mobile.py | |
| echo "── Checking buildozer.spec requirements ──" | |
| grep -q 'pyjnius' buildozer.spec || { echo "::error::pyjnius missing from requirements"; exit 1; } | |
| grep -q 'cython' buildozer.spec || { echo "::error::cython missing from requirements"; exit 1; } | |
| echo "All pre-build checks passed." | |
| - name: Prepare Haar cascades for Android | |
| run: | | |
| mkdir -p cascades | |
| HAAR_DIR=$(python -c "import cv2; print(cv2.data.haarcascades)" 2>/dev/null || echo "") | |
| if [ -z "$HAAR_DIR" ]; then | |
| pip install opencv-python-headless | |
| HAAR_DIR=$(python -c "import cv2; print(cv2.data.haarcascades)") | |
| fi | |
| for xml in haarcascade_frontalface_default.xml haarcascade_frontalface_alt2.xml haarcascade_profileface.xml; do | |
| if [ ! -f "${HAAR_DIR}${xml}" ]; then | |
| echo "::error::Missing cascade file: ${xml}" | |
| exit 1 | |
| fi | |
| cp "${HAAR_DIR}${xml}" cascades/ | |
| done | |
| echo "Cascades prepared: $(ls cascades/)" | |
| - name: Build APK with Buildozer | |
| run: | | |
| buildozer --verbose android debug 2>&1 || { | |
| echo "::warning::Initial build failed. Applying compatibility patches..." | |
| # Patch 1: pyjnius 'long' type references (Python 2→3) | |
| # TODO: Supprimer lorsque p4a stable intégrera les correctifs Python 3.11. | |
| find .buildozer -type f \( -name '*.pxi' -o -name '*.pyx' \) | while IFS= read -r f; do | |
| if grep -q 'isinstance.*long' "$f" 2>/dev/null; then | |
| echo " Patching long→int in $f" | |
| sed -i 's/isinstance(\([^,]*\), long)/isinstance(\1, int)/g' "$f" | |
| fi | |
| done | |
| find .buildozer -type f -name '*.pyx' -exec cython {} \; 2>/dev/null || true | |
| # Patch 2: numpy C++ missing <unordered_map> header (NDK r25b) | |
| find .buildozer -type f -name 'unique.cpp' -path '*/numpy/*' | while IFS= read -r f; do | |
| if grep -q 'unordered_map' "$f" 2>/dev/null && ! grep -q '#include <unordered_map>' "$f" 2>/dev/null; then | |
| echo " Patching missing #include <unordered_map> in $f" | |
| sed -i '1i #include <unordered_map>' "$f" | |
| fi | |
| done | |
| echo "Retrying build after patches..." | |
| buildozer --verbose android debug | |
| } | |
| timeout-minutes: 90 | |
| - name: Verify APK was produced | |
| run: | | |
| APK_COUNT=$(find bin -name '*.apk' 2>/dev/null | wc -l) | |
| if [ "$APK_COUNT" -eq 0 ]; then | |
| echo "::error::No APK file found in bin/ directory" | |
| exit 1 | |
| fi | |
| echo "APK produced successfully:" | |
| ls -lh bin/*.apk | |
| - name: Prepare Android artifact | |
| run: | | |
| mkdir -p release-android | |
| cp bin/*.apk release-android/BalMasque.apk | |
| cp README.md release-android/ | |
| cp LICENSE release-android/ | |
| cd release-android && zip ../BalMasque_Android.zip * | |
| - name: Upload Android artifact | |
| uses: actions/upload-artifact@v6 | |
| with: | |
| name: BalMasque_Android | |
| path: BalMasque_Android.zip | |
| - name: Upload build logs on failure | |
| if: failure() | |
| uses: actions/upload-artifact@v6 | |
| with: | |
| name: buildozer-logs | |
| path: | | |
| .buildozer/android/platform/**/build.log | |
| .buildozer/android/logs/ | |
| if-no-files-found: ignore | |
| verify: | |
| needs: [build, build-android] | |
| runs-on: ubuntu-latest | |
| name: Verify Artifacts | |
| steps: | |
| - name: Download all artifacts | |
| uses: actions/download-artifact@v7 | |
| with: | |
| path: artifacts | |
| - name: Verify all platform artifacts exist | |
| run: | | |
| echo "── Artifact verification ──" | |
| MISSING=0 | |
| for artifact in BalMasque_Windows BalMasque_Linux BalMasque_Mac_Intel BalMasque_Mac_AppleSilicon BalMasque_Android; do | |
| DIR="artifacts/${artifact}" | |
| if [ ! -d "$DIR" ]; then | |
| echo "::error::Missing artifact directory: ${artifact}" | |
| MISSING=$((MISSING + 1)) | |
| continue | |
| fi | |
| FILE_COUNT=$(find "$DIR" -type f \( -name '*.zip' -o -name '*.tar.gz' \) | wc -l) | |
| if [ "$FILE_COUNT" -eq 0 ]; then | |
| echo "::error::No archive found in ${artifact}" | |
| MISSING=$((MISSING + 1)) | |
| else | |
| echo "✓ ${artifact}: $(find "$DIR" -type f \( -name '*.zip' -o -name '*.tar.gz' \) -exec basename {} \;)" | |
| fi | |
| done | |
| if [ "$MISSING" -gt 0 ]; then | |
| echo "::error::${MISSING} artifact(s) missing" | |
| exit 1 | |
| fi | |
| echo "All artifacts verified." | |
| - name: Verify Android APK integrity | |
| run: | | |
| cd artifacts/BalMasque_Android | |
| unzip -q BalMasque_Android.zip -d apk_check | |
| if [ ! -f apk_check/BalMasque.apk ]; then | |
| echo "::error::BalMasque.apk not found inside archive" | |
| exit 1 | |
| fi | |
| APK_SIZE=$(stat --printf="%s" apk_check/BalMasque.apk) | |
| echo "APK size: ${APK_SIZE} bytes" | |
| if [ "$APK_SIZE" -lt 1000000 ]; then | |
| echo "::error::APK is suspiciously small (${APK_SIZE} bytes), possibly corrupt" | |
| exit 1 | |
| fi | |
| echo "✓ Android APK integrity check passed" | |
| release: | |
| needs: [build, build-android, verify] | |
| runs-on: ubuntu-latest | |
| if: startsWith(github.ref, 'refs/tags/v') | |
| steps: | |
| - name: Download all artifacts | |
| uses: actions/download-artifact@v7 | |
| with: | |
| path: artifacts | |
| - name: Create Release | |
| uses: softprops/action-gh-release@v2 | |
| with: | |
| name: "Bal Masqué ${{ github.ref_name }}" | |
| body: | | |
| ## 🎭 Bal Masqué ${{ github.ref_name }} | |
| ### Téléchargements | |
| | Plateforme | Fichier | | |
| |---|---| | |
| | 🪟 Windows | `BalMasque_Windows.zip` | | |
| | 🐧 Linux (Ubuntu/Mint) | `BalMasque_Linux.tar.gz` | | |
| | 🍎 macOS (Intel) | `BalMasque_Mac_Intel.tar.gz` | | |
| | 🍎 macOS (Apple Silicon) | `BalMasque_Mac_AppleSilicon.tar.gz` | | |
| | 🤖 Android (APK) | `BalMasque_Android.zip` | | |
| ### Installation | |
| **Windows** : Extraire le zip et lancer `BalMasque.exe` | |
| **Linux** : | |
| ```bash | |
| tar xzf BalMasque_Linux.tar.gz | |
| chmod +x BalMasque | |
| ./BalMasque | |
| ``` | |
| **macOS** : | |
| ```bash | |
| tar xzf BalMasque_Mac_Intel.tar.gz | |
| open BalMasque.app | |
| ``` | |
| **Android** : | |
| 1. Extraire `BalMasque_Android.zip` | |
| 2. Installer `BalMasque.apk` (activer "Sources inconnues" dans les paramètres) | |
| 3. L'application apparaît dans le menu "Partager avec" pour les images | |
| ### Depuis les sources | |
| ```bash | |
| pip install -r requirements.txt | |
| python bal_masque.py | |
| ``` | |
| files: | | |
| artifacts/**/*.zip | |
| artifacts/**/*.tar.gz | |
| draft: false | |
| prerelease: false |