From b9efb14b8dbd164ffab4e31d477d5b2a436c0e92 Mon Sep 17 00:00:00 2001 From: Bruno Charest Date: Thu, 12 Feb 2026 10:08:58 -0500 Subject: [PATCH] feat: Implement automated versioning system with PowerShell build script and centralized version management - Add version.properties file as single source of truth for VERSION_NAME and VERSION_CODE - Create build.ps1 script with automated version bumping (Major/Minor/Patch/None) and build orchestration - Update app/build.gradle.kts to read version from version.properties instead of hardcoded values - Display dynamic version info in Settings screen using BuildConfig.VERSION_NAME and VERSION_CODE - Add --- app/build.gradle.kts | 13 +- .../presentation/settings/SettingsScreen.kt | 3 +- build.ps1 | 208 ++++++++++++++++++ docs/RELEASE_BUILD.md | 137 +++++++++++- version.properties | 3 + 5 files changed, 356 insertions(+), 8 deletions(-) create mode 100644 build.ps1 create mode 100644 version.properties diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 7390017..b017c82 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -8,6 +8,15 @@ plugins { alias(libs.plugins.kotlin.serialization) } +val versionPropsFile = rootProject.file("version.properties") +val versionProps = Properties().apply { + if (versionPropsFile.exists()) { + versionPropsFile.inputStream().use { load(it) } + } +} +val appVersionCode = (versionProps["VERSION_CODE"] as? String)?.toIntOrNull() ?: 1 +val appVersionName = (versionProps["VERSION_NAME"] as? String) ?: "1.0.0" + android { namespace = "com.shaarit" compileSdk = 34 @@ -16,8 +25,8 @@ android { applicationId = "com.shaarit" minSdk = 24 targetSdk = 34 - versionCode = 1 - versionName = "1.0" + versionCode = appVersionCode + versionName = appVersionName testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" vectorDrawables { diff --git a/app/src/main/java/com/shaarit/presentation/settings/SettingsScreen.kt b/app/src/main/java/com/shaarit/presentation/settings/SettingsScreen.kt index 484dec2..c90226a 100644 --- a/app/src/main/java/com/shaarit/presentation/settings/SettingsScreen.kt +++ b/app/src/main/java/com/shaarit/presentation/settings/SettingsScreen.kt @@ -1,6 +1,7 @@ package com.shaarit.presentation.settings import android.content.Intent +import com.shaarit.BuildConfig import android.net.Uri import android.widget.Toast import androidx.activity.compose.rememberLauncherForActivityResult @@ -318,7 +319,7 @@ fun SettingsScreen( SettingsItem( icon = Icons.Default.Info, title = "Version", - subtitle = "ShaarIt v1.0", + subtitle = "ShaarIt v${BuildConfig.VERSION_NAME} (build ${BuildConfig.VERSION_CODE})", onClick = {} ) } diff --git a/build.ps1 b/build.ps1 new file mode 100644 index 0000000..758c267 --- /dev/null +++ b/build.ps1 @@ -0,0 +1,208 @@ +<# +.SYNOPSIS + Script de build et de versioning pour ShaarIt. +.DESCRIPTION + Incrémente la version (Major, Minor, Patch) dans version.properties + et lance le build Gradle approprié (Debug/Release) avec le format de sortie choisi (APK/AAB). +.PARAMETER Type + Le type de build : 'Debug' ou 'Release'. Défaut: Debug. +.PARAMETER Bump + Quelle partie de la version augmenter : 'Major', 'Minor', 'Patch' (défaut), ou 'None'. +.PARAMETER OutputFormat + Format de sortie : 'APK' (défaut) ou 'AAB' (pour Google Play Store). +.PARAMETER Clean + Si spécifié, effectue un clean avant le build. +.EXAMPLE + .\build.ps1 + # Incrémente le Patch (ex: 1.0.0 -> 1.0.1), augmente le VersionCode, build Debug APK. +.EXAMPLE + .\build.ps1 -Type Release -Bump Minor + # Passe à 1.1.0, augmente le VersionCode, build Release APK. +.EXAMPLE + .\build.ps1 -Type Release -Bump Minor -OutputFormat AAB + # Passe à 1.1.0, augmente le VersionCode, build Release AAB (pour Play Store). +.EXAMPLE + .\build.ps1 -Type Debug -Bump None + # Recompile en Debug sans changer la version. +.EXAMPLE + .\build.ps1 -Type Release -Bump Major -Clean + # Passe à 2.0.0, augmente le VersionCode, build Release APK avec clean. +#> +param ( + [ValidateSet("Debug", "Release")] + [string]$Type = "Debug", + + [ValidateSet("Major", "Minor", "Patch", "None")] + [string]$Bump = "Patch", + + [ValidateSet("APK", "AAB")] + [string]$OutputFormat = "APK", + + [switch]$Clean +) + +$ErrorActionPreference = "Stop" +$PropFile = Join-Path $PSScriptRoot "version.properties" + +# --- 1. Vérifier que le fichier version.properties existe --- +if (-not (Test-Path $PropFile)) { + Write-Error "Le fichier version.properties est introuvable à : $PropFile" + exit 1 +} + +# --- 2. Lire les propriétés actuelles --- +$VersionName = $null +$VersionCode = $null + +foreach ($line in (Get-Content $PropFile)) { + $line = $line.Trim() + if ($line.StartsWith("#") -or [string]::IsNullOrWhiteSpace($line)) { continue } + if ($line -match "^VERSION_NAME=(.+)$") { $VersionName = $Matches[1] } + if ($line -match "^VERSION_CODE=(\d+)$") { $VersionCode = [int]$Matches[1] } +} + +if (-not $VersionName -or -not $VersionCode) { + Write-Error "Impossible de lire VERSION_NAME ou VERSION_CODE depuis $PropFile" + exit 1 +} + +Write-Host "" +Write-Host "========================================" -ForegroundColor DarkCyan +Write-Host " ShaarIt Build Script" -ForegroundColor DarkCyan +Write-Host "========================================" -ForegroundColor DarkCyan +Write-Host " Version actuelle : $VersionName (code: $VersionCode)" -ForegroundColor Cyan +Write-Host " Type de build : $Type" -ForegroundColor Cyan +Write-Host " Format sortie : $OutputFormat" -ForegroundColor Cyan +Write-Host " Bump : $Bump" -ForegroundColor Cyan +Write-Host " Clean avant build: $(if ($Clean) { 'Oui' } else { 'Non' })" -ForegroundColor Cyan +Write-Host "========================================" -ForegroundColor DarkCyan +Write-Host "" + +# --- 3. Logique d'incrémentation --- +if ($Bump -ne "None") { + $Parts = $VersionName.Split('.') + if ($Parts.Count -ne 3) { + Write-Error "VERSION_NAME '$VersionName' n'est pas au format semver (X.Y.Z)" + exit 1 + } + + $Major = [int]$Parts[0] + $Minor = [int]$Parts[1] + $Patch = [int]$Parts[2] + + switch ($Bump) { + "Major" { $Major++; $Minor = 0; $Patch = 0 } + "Minor" { $Minor++; $Patch = 0 } + "Patch" { $Patch++ } + } + + $VersionCode++ + $NewVersionName = "$Major.$Minor.$Patch" + + # --- 4. Sauvegarde dans le fichier --- + $Timestamp = Get-Date -Format "ddd MMM dd HH:mm:ss yyyy" + $Content = @" +#$Timestamp +VERSION_NAME=$NewVersionName +VERSION_CODE=$VersionCode +"@ + Set-Content -Path $PropFile -Value $Content -NoNewline -Encoding UTF8 + + Write-Host " Nouvelle version : $NewVersionName (code: $VersionCode)" -ForegroundColor Green + Write-Host "" +} else { + $NewVersionName = $VersionName + Write-Host " Aucun changement de version." -ForegroundColor Yellow + Write-Host "" +} + +# --- 5. Lancement du Build Gradle --- +$GradleCmd = Join-Path $PSScriptRoot "gradlew.bat" + +if (-not (Test-Path $GradleCmd)) { + Write-Error "gradlew.bat introuvable à : $GradleCmd" + exit 1 +} + +# Déterminer la commande Gradle en fonction des paramètres +$GradleTask = "" +if ($Type -eq "Debug") { + if ($OutputFormat -eq "APK") { + $GradleTask = "assembleDebug" + } else { + Write-Error "Le format AAB n'est pas disponible pour les builds Debug. Utilisez -Type Release avec -OutputFormat AAB." + exit 1 + } +} else { # Release + if ($OutputFormat -eq "APK") { + $GradleTask = "assembleRelease" + } else { + $GradleTask = "bundleRelease" + } +} + +# Ajouter clean si demandé +if ($Clean) { + $GradleTask = "clean $GradleTask" +} + +Write-Host " Lancement : gradlew $GradleTask" -ForegroundColor Magenta +Write-Host "" +& $GradleCmd $GradleTask.Split(" ") + +if ($LASTEXITCODE -eq 0) { + Write-Host "" + Write-Host "========================================" -ForegroundColor Green + Write-Host " Build $Type terminé avec succès !" -ForegroundColor Green + Write-Host " Version : $NewVersionName (code: $VersionCode)" -ForegroundColor Green + Write-Host "========================================" -ForegroundColor Green + + # --- 6. Renommage des fichiers générés --- + Write-Host "" + Write-Host " Renommage des fichiers..." -ForegroundColor Cyan + + $ProjectRoot = $PSScriptRoot + $BuildDir = Join-Path $ProjectRoot "app\build\outputs" + + if ($Type -eq "Debug") { + $SourceFile = Join-Path $BuildDir "apk\debug\app-debug.apk" + if (Test-Path $SourceFile) { + $NewFileName = "ShaarIt-debug-$NewVersionName.apk" + $DestFile = Join-Path $BuildDir "apk\debug\$NewFileName" + Rename-Item -Path $SourceFile -NewName $NewFileName -Force + Write-Host " ✓ Renommé: $NewFileName" -ForegroundColor Green + Write-Host " Emplacement: $DestFile" -ForegroundColor Gray + } + } else { # Release + if ($OutputFormat -eq "APK") { + $SourceFile = Join-Path $BuildDir "apk\release\app-release.apk" + if (Test-Path $SourceFile) { + $NewFileName = "ShaarIt-$NewVersionName.apk" + $DestFile = Join-Path $BuildDir "apk\release\$NewFileName" + Rename-Item -Path $SourceFile -NewName $NewFileName -Force + Write-Host " ✓ Renommé: $NewFileName" -ForegroundColor Green + Write-Host " Emplacement: $DestFile" -ForegroundColor Gray + } + } else { + $SourceFile = Join-Path $BuildDir "bundle\release\app-release.aab" + if (Test-Path $SourceFile) { + $NewFileName = "ShaarIt-$NewVersionName.aab" + $DestFile = Join-Path $BuildDir "bundle\release\$NewFileName" + Rename-Item -Path $SourceFile -NewName $NewFileName -Force + Write-Host " ✓ Renommé: $NewFileName" -ForegroundColor Green + Write-Host " Emplacement: $DestFile" -ForegroundColor Gray + } + } + } + + Write-Host "" + Write-Host "========================================" -ForegroundColor Green + Write-Host " Opérations terminées avec succès !" -ForegroundColor Green + Write-Host "========================================" -ForegroundColor Green +} else { + Write-Host "" + Write-Host "========================================" -ForegroundColor Red + Write-Host " ERREUR lors du build $Type" -ForegroundColor Red + Write-Host "========================================" -ForegroundColor Red + exit $LASTEXITCODE +} diff --git a/docs/RELEASE_BUILD.md b/docs/RELEASE_BUILD.md index f578002..20b444e 100644 --- a/docs/RELEASE_BUILD.md +++ b/docs/RELEASE_BUILD.md @@ -42,24 +42,104 @@ keyPassword=votre_mot_de_passe_cle ## Build Release -### Debug build (pour tester): +### Méthode 1: Script PowerShell `build.ps1` (recommandé) + +Le script `build.ps1` automatise le versioning et le build. Il gère automatiquement l'incrémentation de la version dans `version.properties` et lance le build approprié. + +**Syntaxe de base:** +```powershell +.\build.ps1 [-Type Debug|Release] [-Bump Major|Minor|Patch|None] [-OutputFormat APK|AAB] [-Clean] +``` + +**Paramètres:** +- `-Type`: Type de build (`Debug` par défaut, `Release` pour la production) +- `-Bump`: Type d'incrémentation de version (`Patch` par défaut) +- `-OutputFormat`: Format de sortie (`APK` par défaut, `AAB` pour Google Play Store) +- `-Clean`: Effectue un clean avant le build (optionnel) + +**Exemples d'utilisation:** + +1. **Build Debug avec incrément de Patch (le plus courant):** + ```powershell + .\build.ps1 + # Résultat: version 1.0.1 → 1.0.2, build Debug APK + ``` + +2. **Build Release APK avec incrément de Minor (nouvelle fonctionnalité):** + ```powershell + .\build.ps1 -Type Release -Bump Minor + # Résultat: version 1.0.2 → 1.1.0, build Release APK + ``` + +3. **Build Release AAB pour Google Play Store:** + ```powershell + .\build.ps1 -Type Release -Bump Minor -OutputFormat AAB + # Résultat: version 1.0.2 → 1.1.0, build Release AAB + ``` + +4. **Build Release avec incrément de Major (version majeure):** + ```powershell + .\build.ps1 -Type Release -Bump Major -Clean + # Résultat: version 1.1.0 → 2.0.0, build Release APK avec clean + ``` + +5. **Build Debug sans changer la version (pour tests rapides):** + ```powershell + .\build.ps1 -Type Debug -Bump None + # Résultat: version inchangée, recompilation Debug APK + ``` + +6. **Build Release AAB pour hotfix (patch uniquement):** + ```powershell + .\build.ps1 -Type Release -Bump Patch -OutputFormat AAB + # Résultat: version 1.0.2 → 1.0.3, build Release AAB + ``` + +7. **Build complet avec clean et version majeure:** + ```powershell + .\build.ps1 -Type Release -Bump Major -OutputFormat AAB -Clean + # Résultat: version 1.1.0 → 2.0.0, build Release AAB avec clean complet + ``` + +**Fichiers générés (avec renommage automatique):** +- **Debug APK**: `app/build/outputs/apk/debug/ShaarIt-debug-x.x.x.apk` +- **Release APK**: `app/build/outputs/apk/release/ShaarIt-x.x.x.apk` +- **Release AAB**: `app/build/outputs/bundle/release/ShaarIt-x.x.x.aab` (pour Google Play Store) + +**Format de nommage:** +- Debug: `ShaarIt-debug-{VERSION_NAME}.apk` +- Release APK: `ShaarIt-{VERSION_NAME}.apk` +- Release AAB: `ShaarIt-{VERSION_NAME}.aab` + +**Note:** Le format AAB n'est disponible que pour les builds Release. Les builds Debug génèrent toujours des APK. Les fichiers sont automatiquement renommés après chaque build réussi. + +### Méthode 2: Gradle manuel (si nécessaire) + +Si vous préférez utiliser Gradle directement: + +**Debug build (pour tester):** ```bash ./gradlew assembleDebug ``` L'APK sera dans: `app/build/outputs/apk/debug/app-debug.apk` -### Release build (pour production): +**Release build (pour production):** ```bash ./gradlew assembleRelease ``` L'APK sera dans: `app/build/outputs/apk/release/app-release.apk` -### Bundle AAB (pour Google Play Store): +**Bundle AAB (pour Google Play Store):** ```bash ./gradlew bundleRelease ``` Le bundle sera dans: `app/build/outputs/bundle/release/app-release.aab` +⚠️ **Note**: Avec la méthode manuelle: +- Vous devez gérer le versioning manuellement dans `version.properties` +- Les fichiers conservent leurs noms par défaut (`app-debug.apk`, `app-release.apk`, `app-release.aab`) +- Aucun renommage automatique n'est effectué + ## Vérification du build Vérifiez l'APK signé: @@ -69,8 +149,19 @@ jarsigner -verify -verbose -certs app/build/outputs/apk/release/app-release.apk ## Checklist avant publication -- [ ] Version code incrémenté dans `build.gradle.kts` -- [ ] Version name mise à jour +### Si vous utilisez `build.ps1` (recommandé): +- [x] Version automatiquement incrémentée par le script +- [ ] Type de bump approprié choisi (Major/Minor/Patch) +- [ ] Tests passés +- [ ] ProGuard configuré et testé +- [ ] APK/AAB généré et vérifié +- [ ] Captures d'écran prêtes pour le store +- [ ] Description de l'app rédigée +- [ ] Icône et assets graphiques finalisés + +### Si vous utilisez Gradle manuel: +- [ ] Version code incrémenté dans `version.properties` +- [ ] Version name mise à jour dans `version.properties` - [ ] Tests passés - [ ] ProGuard configuré et testé - [ ] APK signé et vérifié @@ -78,6 +169,42 @@ jarsigner -verify -verbose -certs app/build/outputs/apk/release/app-release.apk - [ ] Description de l'app rédigée - [ ] Icône et assets graphiques finalisés +### Workflow recommandé avec `build.ps1`: +1. Développement et tests avec `.\build.ps1 -Bump None` +2. Quand prêt pour release: + - Hotfix: `.\build.ps1 -Type Release -Bump Patch` + - Nouvelle fonctionnalité: `.\build.ps1 -Type Release -Bump Minor` + - Version majeure: `.\build.ps1 -Type Release -Bump Major` +3. Vérifier l'AAB généré dans `app/build/outputs/bundle/release/` +4. Soumettre sur Google Play Console + +## Système de Versioning Automatique + +Le projet utilise un système de versioning sémantique (SemVer) automatisé: + +### Fichiers impliqués: +- **`version.properties`**: Source unique de vérité pour la version + ```properties + VERSION_NAME=1.0.1 + VERSION_CODE=3 + ``` +- **`build.ps1`**: Script qui incrémente la version et lance le build +- **`app/build.gradle.kts`**: Lit `version.properties` pour configurer `BuildConfig` +- **Settings → À propos**: Affiche dynamiquement `BuildConfig.VERSION_NAME` et `BuildConfig.VERSION_CODE` + +### Règles de versioning: +- **Major (X.0.0)**: Changements cassants, refactoring majeur +- **Minor (X.Y.0)**: Nouvelles fonctionnalités, rétrocompatibles +- **Patch (X.Y.Z)**: Corrections de bugs, petites améliorations +- **VERSION_CODE**: Toujours incrémenté pour Google Play Store (doit être unique) + +### Exemples de progression: +```bash +1.0.0 (code: 1) → Patch → 1.0.1 (code: 2) +1.0.1 (code: 2) → Minor → 1.1.0 (code: 3) +1.1.0 (code: 3) → Major → 2.0.0 (code: 4) +``` + ## Notes de sécurité ⚠️ **IMPORTANT**: Ne jamais commiter ces fichiers: diff --git a/version.properties b/version.properties new file mode 100644 index 0000000..44d2965 --- /dev/null +++ b/version.properties @@ -0,0 +1,3 @@ +#Thu Feb 12 09:29:54 2026 +VERSION_NAME=1.2.0 +VERSION_CODE=8 \ No newline at end of file