diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index a001286..97264f4 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -33,6 +33,25 @@ jobs: - name: Install frontend dependencies run: npm ci + - name: Extract changelog + id: changelog + shell: bash + run: | + TAG="${GITHUB_REF_NAME#v}" + # Extract section between ## [TAG] (or ## TAG) and next ## header + NOTES=$(sed -n "/^## \[${TAG}\]/,/^## /{/^## \[${TAG}\]/d;/^## /d;p}" CHANGELOG.md) + if [ -z "$NOTES" ]; then + NOTES=$(sed -n "/^## ${TAG}/,/^## /{/^## ${TAG}/d;/^## /d;p}" CHANGELOG.md) + fi + # Trim leading/trailing blank lines + NOTES=$(echo "$NOTES" | sed -e '/./,$!d' -e :a -e '/^\n*$/{$d;N;ba}') + # Write to multiline output + { + echo "notes<> "$GITHUB_OUTPUT" + - name: Build and release uses: tauri-apps/tauri-action@v0 env: @@ -43,6 +62,10 @@ jobs: tagName: ${{ github.ref_name }} releaseName: "Simpl'Résultat ${{ github.ref_name }}" releaseBody: | + ${{ steps.changelog.outputs.notes }} + + --- + ## Installation **Windows** : Téléchargez le fichier `.exe` ci-dessous et lancez l'installation. @@ -87,6 +110,22 @@ jobs: - name: Install frontend dependencies run: npm ci + - name: Extract changelog + id: changelog + shell: bash + run: | + TAG="${GITHUB_REF_NAME#v}" + NOTES=$(sed -n "/^## \[${TAG}\]/,/^## /{/^## \[${TAG}\]/d;/^## /d;p}" CHANGELOG.md) + if [ -z "$NOTES" ]; then + NOTES=$(sed -n "/^## ${TAG}/,/^## /{/^## ${TAG}/d;/^## /d;p}" CHANGELOG.md) + fi + NOTES=$(echo "$NOTES" | sed -e '/./,$!d' -e :a -e '/^\n*$/{$d;N;ba}') + { + echo "notes<> "$GITHUB_OUTPUT" + - name: Build and release uses: tauri-apps/tauri-action@v0 env: @@ -97,6 +136,10 @@ jobs: tagName: ${{ github.ref_name }} releaseName: "Simpl'Résultat ${{ github.ref_name }}" releaseBody: | + ${{ steps.changelog.outputs.notes }} + + --- + ## Installation **Windows** : Téléchargez le fichier `.exe` ci-dessous et lancez l'installation. diff --git a/CHANGELOG.md b/CHANGELOG.md index 3f71fb4..6957a39 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,8 @@ # Changelog -## 0.3.7 +## [Unreleased] + +## [0.3.7] ### Fixes - Remove MSI bundle to prevent updater install path conflict diff --git a/CLAUDE.md b/CLAUDE.md index a93d390..de03877 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -134,6 +134,10 @@ La documentation technique est centralisée dans `docs/` : - Décision technique structurante (choix de librairie, pattern architectural, changement de stratégie) → créer un nouvel ADR dans `docs/adr/` - Changement affectant l'utilisation de l'app → mettre à jour `docs/guide-utilisateur.md` et les traductions i18n correspondantes (`src/i18n/locales/fr.json`, `src/i18n/locales/en.json`, clés sous `docs.*`) +**Règle CHANGELOG :** tout changement affectant le comportement utilisateur → ajouter une entrée sous `## [Unreleased]` dans `CHANGELOG.md` +- Catégories : Added, Changed, Fixed, Removed +- Format [Keep a Changelog](https://keepachangelog.com/). Le contenu est extrait automatiquement par le CI pour les release notes GitHub et affiché dans l'app. + --- ## Points d'attention RS&DE / CRIC diff --git a/src/hooks/useUpdater.ts b/src/hooks/useUpdater.ts index 8da8639..b694786 100644 --- a/src/hooks/useUpdater.ts +++ b/src/hooks/useUpdater.ts @@ -15,6 +15,7 @@ type UpdateStatus = interface UpdaterState { status: UpdateStatus; version: string | null; + body: string | null; progress: number; contentLength: number | null; error: string | null; @@ -23,7 +24,7 @@ interface UpdaterState { type UpdaterAction = | { type: "CHECK_START" } | { type: "UP_TO_DATE" } - | { type: "AVAILABLE"; version: string } + | { type: "AVAILABLE"; version: string; body: string | null } | { type: "DOWNLOAD_START" } | { type: "DOWNLOAD_PROGRESS"; downloaded: number; contentLength: number | null } | { type: "READY_TO_INSTALL" } @@ -33,6 +34,7 @@ type UpdaterAction = const initialState: UpdaterState = { status: "idle", version: null, + body: null, progress: 0, contentLength: null, error: null, @@ -45,7 +47,7 @@ function reducer(state: UpdaterState, action: UpdaterAction): UpdaterState { case "UP_TO_DATE": return { ...state, status: "upToDate", error: null }; case "AVAILABLE": - return { ...state, status: "available", version: action.version, error: null }; + return { ...state, status: "available", version: action.version, body: action.body, error: null }; case "DOWNLOAD_START": return { ...state, status: "downloading", progress: 0, contentLength: null, error: null }; case "DOWNLOAD_PROGRESS": @@ -69,7 +71,7 @@ export function useUpdater() { const update = await check(); if (update) { updateRef.current = update; - dispatch({ type: "AVAILABLE", version: update.version }); + dispatch({ type: "AVAILABLE", version: update.version, body: update.body ?? null }); } else { dispatch({ type: "UP_TO_DATE" }); } diff --git a/src/i18n/locales/en.json b/src/i18n/locales/en.json index e768145..f07a8ab 100644 --- a/src/i18n/locales/en.json +++ b/src/i18n/locales/en.json @@ -382,7 +382,8 @@ "installButton": "Install and restart", "installing": "Installing...", "error": "Update failed", - "retryButton": "Retry" + "retryButton": "Retry", + "releaseNotes": "What's New" }, "dataManagement": { "title": "Data Management", diff --git a/src/i18n/locales/fr.json b/src/i18n/locales/fr.json index 030bc3e..c96c8f7 100644 --- a/src/i18n/locales/fr.json +++ b/src/i18n/locales/fr.json @@ -382,7 +382,8 @@ "installButton": "Installer et redémarrer", "installing": "Installation en cours...", "error": "Erreur lors de la mise à jour", - "retryButton": "Réessayer" + "retryButton": "Réessayer", + "releaseNotes": "Nouveautés" }, "dataManagement": { "title": "Gestion des données", diff --git a/src/pages/SettingsPage.tsx b/src/pages/SettingsPage.tsx index dd553a5..4b1803d 100644 --- a/src/pages/SettingsPage.tsx +++ b/src/pages/SettingsPage.tsx @@ -125,6 +125,26 @@ export default function SettingsPage() {

{t("settings.updates.available", { version: state.version })}

+ {state.body && ( +
+

+ {t("settings.updates.releaseNotes")} +

+
+ {state.body.split("\n").map((line, i) => { + const trimmed = line.trim(); + if (!trimmed) return
; + if (trimmed.startsWith("### ")) + return

{trimmed.slice(4)}

; + if (trimmed.startsWith("## ")) + return

{trimmed.slice(3)}

; + if (trimmed.startsWith("- ")) + return

{"\u2022 "}{trimmed.slice(2).replace(/\*\*(.+?)\*\*/g, "$1")}

; + return

{trimmed}

; + })} +
+
+ )}