name: Desktop installers # Produit les installeurs de BUREAU (.msi Windows + AppImage Linux) et les publie # en tant qu'assets d'une GitHub Release, sur tag `v*`. # # Complementaire au pipeline Gitea Actions (.gitea/workflows/release.yml) qui, # lui, build et pousse les IMAGES Docker. Ici on est sur GitHub car jpackage ne # sait PAS cross-compiler : le .msi DOIT etre construit sur un runner Windows et # l'AppImage sur un runner Linux — GitHub fournit les deux gratuitement. # # Prerequis : le depot Gitea doit etre mirrore vers GitHub (push mirror, tags # inclus) pour que le tag declenche ce workflow. # # Tag stable vX.Y.Z -> GitHub Release PUBLIQUE avec le .msi attache. # Tag beta vX.Y.Z-beta* -> AUCUNE publication publique. Le .msi est depose en # ARTEFACT PRIVE du run (telechargeable seulement par # toi via l'onglet Actions) ; tu le joins ensuite a un # post Patreon reserve a un palier. Patreon = la # barriere d'acces (equivalent du registry prive + # relais pour les images Docker beta). on: push: tags: ['v*'] # Declenchement MANUEL depuis l'onglet Actions ("Run workflow"). Utile quand un # tag a ete pousse AVANT que le workflow existe sur GitHub (ne se redeclenche # pas tout seul), ou pour rejouer un build. Saisir la version SANS le "v". workflow_dispatch: inputs: version: description: "Version a builder (doit correspondre a un tag existant, ex: 0.15.0 ou 0.15.0-beta)" required: true permissions: contents: write # requis pour creer la Release et y attacher le .msi jobs: # GATE : les 3 suites unitaires (Java / Python / Angular) doivent passer avant # de construire le .msi. Tourne sur ubuntu-latest (moins cher/plus rapide que # windows) ; le build natif lui-meme reste sur windows-latest via `needs`. # Auto-suffisant : ne depend PAS du resultat de Gitea (CI separee), il rejoue # les memes tests ici. Un test rouge => pas d'installeur publie. tests: runs-on: ubuntu-latest # Base PostgreSQL réelle pour les tests Core. Sur les runners GitHub (job sur # la VM, pas en conteneur), le service est joignable via localhost + le port mappé. services: postgres: image: postgres:16-alpine env: POSTGRES_DB: loremind_test POSTGRES_USER: loremind_test POSTGRES_PASSWORD: loremind_test ports: - 5432:5432 options: >- --health-cmd "pg_isready -U loremind_test -d loremind_test" --health-interval 10s --health-timeout 5s --health-retries 10 steps: - uses: actions/checkout@v4 with: ref: ${{ github.event_name == 'workflow_dispatch' && format('v{0}', inputs.version) || github.ref }} - name: Set up JDK 17 uses: actions/setup-java@v4 with: distribution: temurin java-version: '17' cache: maven - name: Core — mvn test (+ JaCoCo check) working-directory: core env: SPRING_DATASOURCE_URL: jdbc:postgresql://localhost:5432/loremind_test SPRING_DATASOURCE_USERNAME: loremind_test SPRING_DATASOURCE_PASSWORD: loremind_test run: | chmod +x ./mvnw ./mvnw -B test - name: Set up Python 3.12 uses: actions/setup-python@v5 with: python-version: '3.12' cache: pip cache-dependency-path: brain/requirements-dev.txt - name: Brain — pytest (+ couverture) working-directory: brain run: | pip install -r requirements-dev.txt pytest --cov=app --cov-report=term-missing --cov-fail-under=50 - name: Set up Node 20 uses: actions/setup-node@v4 with: node-version: '20' cache: npm cache-dependency-path: web/package-lock.json - name: Web — vitest (+ couverture) working-directory: web run: | npm ci --no-audit --no-fund npm run test:unit:coverage windows: needs: tests runs-on: windows-latest steps: # En declenchement manuel, on checkout le TAG correspondant a la version # saisie (sinon checkout prendrait la branche par defaut). En push de tag, # on prend la ref poussee. - uses: actions/checkout@v4 with: ref: ${{ github.event_name == 'workflow_dispatch' && format('v{0}', inputs.version) || github.ref }} # Apporte jpackage (lanceur d'empaquetage natif) dans le PATH. - name: Set up JDK 21 uses: actions/setup-java@v4 with: distribution: temurin java-version: '21' - name: Set up Node uses: actions/setup-node@v4 with: node-version: '20' # Python 3.12 = meme version que l'image Docker du Brain (coherence runtime). - name: Set up Python uses: actions/setup-python@v5 with: python-version: '3.12' # jpackage genere le MSI via WiX Toolset v3 (candle.exe/light.exe). WiX 4+ # ne convient pas (outils renommes). Le paquet choco `wixtoolset` est la # ligne 3.x et s'ajoute au PATH. - name: Install WiX Toolset 3 shell: pwsh run: choco install wixtoolset -y --no-progress # Tesseract OCR : non preinstalle sur windows-latest. Requis pour que # build-windows.ps1 embarque l'OCR des PDF scannes (sinon il skip en # degradation gracieuse). Installe dans %ProgramFiles%\Tesseract-OCR. - name: Install Tesseract OCR shell: pwsh run: choco install tesseract -y --no-progress # Version de l'installeur = version du tag (push) OU de l'input (manuel). # Sorties : version (numerique X.Y.Z pour le MSI), tag (vX.Y.Z[-beta]), # isbeta (true/false) — independant du nom de ref (qui est une branche en manuel). - name: Derive version id: ver shell: pwsh run: | if ('${{ github.event_name }}' -eq 'workflow_dispatch') { $raw = '${{ inputs.version }}' } else { $raw = '${{ github.ref_name }}' } $raw = $raw -replace '^v','' # 0.15.0 ou 0.15.0-beta $num = ($raw -split '-')[0] # 0.15.0 $isbeta = if ($raw -like '*-beta*') { 'true' } else { 'false' } "version=$num" >> $env:GITHUB_OUTPUT "tag=v$raw" >> $env:GITHUB_OUTPUT "isbeta=$isbeta" >> $env:GITHUB_OUTPUT - name: Build Windows installer shell: pwsh run: .\installers\desktop\build-windows.ps1 -Version ${{ steps.ver.outputs.version }} # STABLE uniquement : Release GitHub publique avec le .msi. # tag_name explicite : en declenchement manuel, github.ref est une branche, # donc on cible le tag derive (la release est attachee au bon tag). - name: Publish installer to GitHub Release (stable) if: ${{ steps.ver.outputs.isbeta == 'false' }} uses: softprops/action-gh-release@v2 with: tag_name: ${{ steps.ver.outputs.tag }} files: core/target/dist-out/*.msi fail_on_unmatched_files: true generate_release_notes: true # BETA uniquement : artefact PRIVE (pas de release publique). A recuperer # via l'onglet Actions puis a joindre a un post Patreon gate par palier. - name: Upload installer as private artifact (beta) if: ${{ steps.ver.outputs.isbeta == 'true' }} uses: actions/upload-artifact@v4 with: name: loremind-beta-${{ steps.ver.outputs.version }}-msi path: core/target/dist-out/*.msi retention-days: 90 # LINUX : AppImage (1 fichier, toutes distros) attache a la MEME release. # Tourne sur ubuntu-latest (jpackage ne cross-compile pas -> build natif Linux). # Brain empaquete via python-build-standalone (pas de Python embeddable Linux # officiel ; pas de PyInstaller -> pas de faux positif AV). Memes regles de # publication que windows : stable -> release publique ; beta -> artefact prive. linux: needs: tests runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 with: ref: ${{ github.event_name == 'workflow_dispatch' && format('v{0}', inputs.version) || github.ref }} # Apporte jpackage (empaquetage natif) dans le PATH. - name: Set up JDK 21 uses: actions/setup-java@v4 with: distribution: temurin java-version: '21' - name: Set up Node uses: actions/setup-node@v4 with: node-version: '20' # Pas de setup-python : le Brain utilise SON python-build-standalone # (telecharge par le script, avec son propre pip). Le host n'en a pas besoin. # Version (numerique X.Y.Z) + tag + isbeta, comme le job windows. - name: Derive version id: ver run: | if [ '${{ github.event_name }}' = 'workflow_dispatch' ]; then raw='${{ inputs.version }}' else raw='${{ github.ref_name }}' fi raw="${raw#v}" # 0.15.0 ou 0.15.0-beta num="${raw%%-*}" # 0.15.0 case "$raw" in *-beta*) isbeta=true ;; *) isbeta=false ;; esac echo "version=$num" >> "$GITHUB_OUTPUT" echo "tag=v$raw" >> "$GITHUB_OUTPUT" echo "isbeta=$isbeta" >> "$GITHUB_OUTPUT" - name: Build Linux AppImage run: bash ./installers/desktop/build-linux.sh --version ${{ steps.ver.outputs.version }} # STABLE uniquement : attache l'AppImage a la release publique (meme tag que # le .msi -> les deux installeurs sur la meme release). - name: Publish AppImage to GitHub Release (stable) if: ${{ steps.ver.outputs.isbeta == 'false' }} uses: softprops/action-gh-release@v2 with: tag_name: ${{ steps.ver.outputs.tag }} files: core/target/dist-out/*.AppImage fail_on_unmatched_files: true # BETA uniquement : artefact PRIVE (pas de release publique). - name: Upload AppImage as private artifact (beta) if: ${{ steps.ver.outputs.isbeta == 'true' }} uses: actions/upload-artifact@v4 with: name: loremind-beta-${{ steps.ver.outputs.version }}-appimage path: core/target/dist-out/*.AppImage retention-days: 90