From fd6a228d9550f9b9ea4cd86147f7a5d00c6c7e54 Mon Sep 17 00:00:00 2001 From: mirage <119869686+ClementBobin@users.noreply.github.com> Date: Wed, 25 Mar 2026 10:08:49 +0100 Subject: [PATCH 01/23] =?UTF-8?q?chore:=20mise=20=C3=A0=20jour=20la=20vers?= =?UTF-8?q?ion=20de=20l'API=20=C3=A0=202.0=20dans=20ApiController?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Webzine.WebApplication/Controllers/ApiController.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Webzine.WebApplication/Controllers/ApiController.cs b/Webzine.WebApplication/Controllers/ApiController.cs index 92ee3c6..3a9518b 100644 --- a/Webzine.WebApplication/Controllers/ApiController.cs +++ b/Webzine.WebApplication/Controllers/ApiController.cs @@ -38,7 +38,7 @@ public class ApiController : ControllerBase return Ok(new { nom = "webzine", - version = "1.0", + version = "2.0", }); } } \ No newline at end of file From 1f254a68825951b84d1b577a3fc2fc055d366ae7 Mon Sep 17 00:00:00 2001 From: "b.nodon" Date: Wed, 25 Mar 2026 15:35:10 +0100 Subject: [PATCH 02/23] =?UTF-8?q?#104=20J'ai=20enlev=C3=A9=20les=20restant?= =?UTF-8?q?=20de=20style=20inline?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Webzine.Repository.Contracts/stylecop1.json | 14 ++++++++++++++ .../Administration/Views/Artiste/Index.cshtml | 2 +- .../Administration/Views/Commentaire/Index.cshtml | 2 +- .../Areas/Administration/Views/Style/Create.cshtml | 2 +- .../Areas/Administration/Views/Style/Edit.cshtml | 2 +- .../Areas/Administration/Views/Style/Index.cshtml | 2 +- wwwroot/css/site.css | 0 7 files changed, 19 insertions(+), 5 deletions(-) create mode 100644 Webzine.Repository.Contracts/stylecop1.json create mode 100644 wwwroot/css/site.css diff --git a/Webzine.Repository.Contracts/stylecop1.json b/Webzine.Repository.Contracts/stylecop1.json new file mode 100644 index 0000000..42fb1f8 --- /dev/null +++ b/Webzine.Repository.Contracts/stylecop1.json @@ -0,0 +1,14 @@ +{ + // ACTION REQUIRED: This file was automatically added to your project, but it + // will not take effect until additional steps are taken to enable it. See the + // following page for additional information: + // + // https://github.com/DotNetAnalyzers/StyleCopAnalyzers/blob/master/documentation/EnableConfiguration.md + + "$schema": "https://raw.githubusercontent.com/DotNetAnalyzers/StyleCopAnalyzers/master/StyleCop.Analyzers/StyleCop.Analyzers/Settings/stylecop.schema.json", + "settings": { + "documentationRules": { + "companyName": "PlaceholderCompany" + } + } +} diff --git a/Webzine.WebApplication/Areas/Administration/Views/Artiste/Index.cshtml b/Webzine.WebApplication/Areas/Administration/Views/Artiste/Index.cshtml index 78c392b..73aabac 100644 --- a/Webzine.WebApplication/Areas/Administration/Views/Artiste/Index.cshtml +++ b/Webzine.WebApplication/Areas/Administration/Views/Artiste/Index.cshtml @@ -16,7 +16,7 @@ Nom - Actions + Actions diff --git a/Webzine.WebApplication/Areas/Administration/Views/Commentaire/Index.cshtml b/Webzine.WebApplication/Areas/Administration/Views/Commentaire/Index.cshtml index 4f696e8..7b71df3 100644 --- a/Webzine.WebApplication/Areas/Administration/Views/Commentaire/Index.cshtml +++ b/Webzine.WebApplication/Areas/Administration/Views/Commentaire/Index.cshtml @@ -17,7 +17,7 @@ Auteur Commentaire Date de création - Actions + Actions diff --git a/Webzine.WebApplication/Areas/Administration/Views/Style/Create.cshtml b/Webzine.WebApplication/Areas/Administration/Views/Style/Create.cshtml index 0ac8105..c0cb8f7 100644 --- a/Webzine.WebApplication/Areas/Administration/Views/Style/Create.cshtml +++ b/Webzine.WebApplication/Areas/Administration/Views/Style/Create.cshtml @@ -22,7 +22,7 @@ @* Input *@
- +
@* Bouton *@ diff --git a/Webzine.WebApplication/Areas/Administration/Views/Style/Edit.cshtml b/Webzine.WebApplication/Areas/Administration/Views/Style/Edit.cshtml index e9b763b..446cabe 100644 --- a/Webzine.WebApplication/Areas/Administration/Views/Style/Edit.cshtml +++ b/Webzine.WebApplication/Areas/Administration/Views/Style/Edit.cshtml @@ -25,7 +25,7 @@ @* Input *@
- +
@* Bouton *@ diff --git a/Webzine.WebApplication/Areas/Administration/Views/Style/Index.cshtml b/Webzine.WebApplication/Areas/Administration/Views/Style/Index.cshtml index 7a710ee..bfe8ab9 100644 --- a/Webzine.WebApplication/Areas/Administration/Views/Style/Index.cshtml +++ b/Webzine.WebApplication/Areas/Administration/Views/Style/Index.cshtml @@ -20,7 +20,7 @@ Libellé - Actions + Actions diff --git a/wwwroot/css/site.css b/wwwroot/css/site.css new file mode 100644 index 0000000..e69de29 From 74cc45020d9c992844296fd3c27a54e4e2b49c90 Mon Sep 17 00:00:00 2001 From: "b.nodon" Date: Wed, 25 Mar 2026 15:45:42 +0100 Subject: [PATCH 03/23] #104 J'ai en sorte que le footer reste en bas de la page --- Webzine.WebApplication/Views/Shared/_Layout.cshtml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Webzine.WebApplication/Views/Shared/_Layout.cshtml b/Webzine.WebApplication/Views/Shared/_Layout.cshtml index 60de9d0..e1e6514 100644 --- a/Webzine.WebApplication/Views/Shared/_Layout.cshtml +++ b/Webzine.WebApplication/Views/Shared/_Layout.cshtml @@ -12,7 +12,7 @@ - +
From a1a8c125802969e50e00a70848049767c174f89a Mon Sep 17 00:00:00 2001 From: "b.nodon" Date: Wed, 25 Mar 2026 16:08:38 +0100 Subject: [PATCH 04/23] =?UTF-8?q?#104=20cr=C3=A9ation=20de=20l'image=20ava?= =?UTF-8?q?tar.png=20appel=C3=A9e=20dans=20les=20commentaires=20de=20la=20?= =?UTF-8?q?vue=20Webzine.WebApplication\Views\Titre\Details.cshtml?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../wwwroot/images/avatar.png | Bin 0 -> 21423 bytes .../wwwroot/images/avater.png | 0 2 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 Webzine.WebApplication/wwwroot/images/avatar.png delete mode 100644 Webzine.WebApplication/wwwroot/images/avater.png diff --git a/Webzine.WebApplication/wwwroot/images/avatar.png b/Webzine.WebApplication/wwwroot/images/avatar.png new file mode 100644 index 0000000000000000000000000000000000000000..42127efa55cde405a21934a00d517ee9ebf9c13d GIT binary patch literal 21423 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 VG%Oy5<$(YI002ovPDHLkV1h=GwmSd- literal 0 HcmV?d00001 diff --git a/Webzine.WebApplication/wwwroot/images/avater.png b/Webzine.WebApplication/wwwroot/images/avater.png deleted file mode 100644 index e69de29..0000000 From e4295a14aaec8aed077d717f4e897f61f3e7e499 Mon Sep 17 00:00:00 2001 From: "b.nodon" Date: Wed, 25 Mar 2026 16:21:54 +0100 Subject: [PATCH 05/23] =?UTF-8?q?#104=20les=20description=20des=20titres?= =?UTF-8?q?=20dans=20la=20page=20acceuil=20sont=20r=C3=A9duit=20a=20200=20?= =?UTF-8?q?caract=C3=A8re=20max=20+=20...?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Webzine.WebApplication/Views/Accueil/Index.cshtml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Webzine.WebApplication/Views/Accueil/Index.cshtml b/Webzine.WebApplication/Views/Accueil/Index.cshtml index 23290ad..bf225d4 100644 --- a/Webzine.WebApplication/Views/Accueil/Index.cshtml +++ b/Webzine.WebApplication/Views/Accueil/Index.cshtml @@ -37,7 +37,7 @@

- @titre.Chronique + @(titre.Chronique.Length > 200 ? titre.Chronique.Substring(0, 200) + "..." : titre.Chronique)

From f5e3a25459d6ae5df8d18bb8313bf0878ca11f95 Mon Sep 17 00:00:00 2001 From: "b.nodon" Date: Wed, 25 Mar 2026 16:28:44 +0100 Subject: [PATCH 06/23] =?UTF-8?q?#104=20gras=20de=20la=20page=20artiste=20?= =?UTF-8?q?enlev=C3=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Webzine.WebApplication/Views/Artiste/Index.cshtml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Webzine.WebApplication/Views/Artiste/Index.cshtml b/Webzine.WebApplication/Views/Artiste/Index.cshtml index f719270..737e563 100644 --- a/Webzine.WebApplication/Views/Artiste/Index.cshtml +++ b/Webzine.WebApplication/Views/Artiste/Index.cshtml @@ -59,7 +59,7 @@ + class="text-primary"> @titre.Libelle From ed02bf29cdf8225ecb6292bba01e38bec4b97fbb Mon Sep 17 00:00:00 2001 From: "b.nodon" Date: Wed, 25 Mar 2026 17:01:03 +0100 Subject: [PATCH 07/23] =?UTF-8?q?Logo=20de=20la=20page=20contact=20centr?= =?UTF-8?q?=C3=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Webzine.WebApplication/Views/Contact/Index.cshtml | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/Webzine.WebApplication/Views/Contact/Index.cshtml b/Webzine.WebApplication/Views/Contact/Index.cshtml index 1817b16..6d022ba 100644 --- a/Webzine.WebApplication/Views/Contact/Index.cshtml +++ b/Webzine.WebApplication/Views/Contact/Index.cshtml @@ -22,42 +22,42 @@
From 3380b237aee6a8762e2cacc6331a1a7fc965c4cb Mon Sep 17 00:00:00 2001 From: "b.nodon" Date: Thu, 26 Mar 2026 09:39:54 +0100 Subject: [PATCH 08/23] #104 Page contact --- .../Views/Contact/Index.cshtml | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/Webzine.WebApplication/Views/Contact/Index.cshtml b/Webzine.WebApplication/Views/Contact/Index.cshtml index 6d022ba..55ef4d4 100644 --- a/Webzine.WebApplication/Views/Contact/Index.cshtml +++ b/Webzine.WebApplication/Views/Contact/Index.cshtml @@ -4,14 +4,15 @@

Contact

-
+
C.U.C.D.B - DIIAGE
69 Avenue Aristide Briand
21000 Dijon
-
+ +
Phone : 03 80 40 50 60
- secretariat@cucdb.fr + secretariat@cucdb.fr
@@ -21,42 +22,42 @@

Suivez-nous

- +
Twitter
From d7832d8924cef8382e5a024bc61daa3938a43ad3 Mon Sep 17 00:00:00 2001 From: "b.nodon" Date: Thu, 26 Mar 2026 09:51:20 +0100 Subject: [PATCH 09/23] #104 Page de modif artiste --- .../Areas/Administration/Views/Artiste/_Form.cshtml | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/Webzine.WebApplication/Areas/Administration/Views/Artiste/_Form.cshtml b/Webzine.WebApplication/Areas/Administration/Views/Artiste/_Form.cshtml index 3a3101e..f5c84bc 100644 --- a/Webzine.WebApplication/Areas/Administration/Views/Artiste/_Form.cshtml +++ b/Webzine.WebApplication/Areas/Administration/Views/Artiste/_Form.cshtml @@ -2,7 +2,7 @@
-
+
@@ -10,14 +10,15 @@
-
- +
+
- +
+
From ca0fe6b042e6344b2de274e147a9ca22f3d70436 Mon Sep 17 00:00:00 2001 From: "b.nodon" Date: Thu, 26 Mar 2026 10:07:12 +0100 Subject: [PATCH 10/23] #104 Formulaire des titre --- .../Areas/Administration/Views/Titre/_Form.cshtml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Webzine.WebApplication/Areas/Administration/Views/Titre/_Form.cshtml b/Webzine.WebApplication/Areas/Administration/Views/Titre/_Form.cshtml index ac6eef5..d1f4f8c 100644 --- a/Webzine.WebApplication/Areas/Administration/Views/Titre/_Form.cshtml +++ b/Webzine.WebApplication/Areas/Administration/Views/Titre/_Form.cshtml @@ -62,7 +62,7 @@
- +
@@ -102,13 +102,13 @@
-
+
@Model.NbLectures
-
+
@Model.NbLikes From 5a9d1b7425820d6734abd7df8c68a5b15e16ef06 Mon Sep 17 00:00:00 2001 From: "b.nodon" Date: Thu, 26 Mar 2026 11:18:08 +0100 Subject: [PATCH 11/23] #104 Page des styles --- .../Areas/Administration/Views/Style/Index.cshtml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Webzine.WebApplication/Areas/Administration/Views/Style/Index.cshtml b/Webzine.WebApplication/Areas/Administration/Views/Style/Index.cshtml index bfe8ab9..ff7e162 100644 --- a/Webzine.WebApplication/Areas/Administration/Views/Style/Index.cshtml +++ b/Webzine.WebApplication/Areas/Administration/Views/Style/Index.cshtml @@ -28,11 +28,11 @@ { @foreach (Webzine.Entity.Style style in Model.Styles) { - - + + @style.Libelle - + From 2be5c154a7e0d66b62c1e7ed22073941b95a4298 Mon Sep 17 00:00:00 2001 From: "b.nodon" Date: Thu, 26 Mar 2026 11:29:21 +0100 Subject: [PATCH 12/23] #104 Les titres dans la colonne de gauche renvoient sur leur page titre (lien) --- .../Areas/Administration/Views/Commentaire/Index.cshtml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Webzine.WebApplication/Areas/Administration/Views/Commentaire/Index.cshtml b/Webzine.WebApplication/Areas/Administration/Views/Commentaire/Index.cshtml index 7b71df3..e86350e 100644 --- a/Webzine.WebApplication/Areas/Administration/Views/Commentaire/Index.cshtml +++ b/Webzine.WebApplication/Areas/Administration/Views/Commentaire/Index.cshtml @@ -25,7 +25,9 @@ { - @commentaire.Titre.Libelle + + @commentaire.Titre.Libelle + @commentaire.Auteur From 69116fb46b93fe6c576cbf90947acb19968cb659 Mon Sep 17 00:00:00 2001 From: "b.nodon" Date: Thu, 26 Mar 2026 11:59:18 +0100 Subject: [PATCH 13/23] #104 Rework du style du dashboard --- .../Views/Dashboard/Index.cshtml | 121 ++++++++++-------- 1 file changed, 66 insertions(+), 55 deletions(-) diff --git a/Webzine.WebApplication/Areas/Administration/Views/Dashboard/Index.cshtml b/Webzine.WebApplication/Areas/Administration/Views/Dashboard/Index.cshtml index 861c59b..5498169 100644 --- a/Webzine.WebApplication/Areas/Administration/Views/Dashboard/Index.cshtml +++ b/Webzine.WebApplication/Areas/Administration/Views/Dashboard/Index.cshtml @@ -12,19 +12,19 @@
+ @@ -33,17 +33,17 @@ + @@ -52,19 +52,20 @@ + @@ -72,19 +73,20 @@
+ @@ -94,19 +96,20 @@ asp-controller="Titre" asp-action="Details" asp-route-id="@Model.IdMusiqueLaPlusJouee"> +
-
- +
+ -

+

@Model.MusiqueLaPlusJouee -

+

titre le plus lu

- +
@@ -114,19 +117,20 @@
+ @@ -134,50 +138,57 @@
+
-
- +
-

- @Model.NombreLectures -

+
+ -

- lectures -

+

+ @Model.NombreLectures +

+ +

+ lectures +

+
-
- +
-

+
+ + +

@Model.NombreLikes -

+

likes

+
From 4bccf85a400a3cab4b1f8a8d7a5d76cfacf1664e Mon Sep 17 00:00:00 2001 From: mirage <119869686+ClementBobin@users.noreply.github.com> Date: Thu, 26 Mar 2026 13:06:58 +0100 Subject: [PATCH 14/23] =?UTF-8?q?feat:=20ajouter=20un=20flux=20de=20travai?= =?UTF-8?q?l=20et=20un=20script=20de=20test=20pour=20la=20v=C3=A9rificatio?= =?UTF-8?q?n=20des=20performances=20des=20points=20d=E2=80=99acc=C3=A8s=20?= =?UTF-8?q?PR?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitea/workflows/pr-endpoint-check.yml | 132 +++++++++++++++ scripts/test-endpoints.sh | 221 +++++++++++++++++++++++++ 2 files changed, 353 insertions(+) create mode 100644 .gitea/workflows/pr-endpoint-check.yml create mode 100644 scripts/test-endpoints.sh diff --git a/.gitea/workflows/pr-endpoint-check.yml b/.gitea/workflows/pr-endpoint-check.yml new file mode 100644 index 0000000..c0936d2 --- /dev/null +++ b/.gitea/workflows/pr-endpoint-check.yml @@ -0,0 +1,132 @@ +name: PR Endpoint Performance Check + +on: + pull_request: + branches: + - main + - master + - develop + +jobs: + endpoint-performance-check: + name: Test All Endpoints (< 1s) + runs-on: ubuntu-latest + + steps: + # ───────────────────────────────────────────── + # 1. Checkout code + # ───────────────────────────────────────────── + - name: Checkout PR branch + uses: actions/checkout@v4 + + # ───────────────────────────────────────────── + # 2. Setup .NET 10 + # ───────────────────────────────────────────── + - name: Setup .NET 10 + uses: actions/setup-dotnet@v4 + with: + dotnet-version: "10.0.x" + + # ───────────────────────────────────────────── + # 3. Restore & Build + # ───────────────────────────────────────────── + - name: Restore dependencies + run: dotnet restore Webzine.sln + + - name: Build solution + run: dotnet build Webzine.sln --no-restore --configuration Release + + # ───────────────────────────────────────────── + # 4. Run unit tests (entity tests) + # ───────────────────────────────────────────── + - name: Run unit tests + run: | + dotnet test Webzine.Entity.Tests/Webzine.Entity.Tests.csproj \ + --no-build \ + --configuration Release \ + --logger "console;verbosity=normal" + + # ───────────────────────────────────────────── + # 5. Start the web application in background + # ───────────────────────────────────────────── + - name: Start Webzine application + run: | + dotnet run \ + --project Webzine.WebApplication/Webzine.WebApplication.csproj \ + --configuration Release \ + --no-build \ + -- --urls "http://localhost:5038" & + + echo "Waiting for application to start..." + timeout 60 bash -c ' + until curl -sf http://localhost:5038 > /dev/null 2>&1; do + sleep 1 + done + ' + echo "Application is ready!" + + # ───────────────────────────────────────────── + # 6. Run endpoint performance tests + # ───────────────────────────────────────────── + - name: Test endpoint response times + id: perf_test + run: | + chmod +x scripts/test-endpoints.sh + bash scripts/test-endpoints.sh http://localhost:5038 1000 || true + FAIL_COUNT=$(grep -c "^\[FAIL\]\|^\[SLOW\]" /tmp/webzine_endpoint_report.txt || echo 0) + echo "failed=$FAIL_COUNT" >> "$GITHUB_OUTPUT" + + # ───────────────────────────────────────────── + # 7. Post report as PR comment + # ───────────────────────────────────────────── + - name: Post performance report as PR comment + if: always() + env: + GITEA_TOKEN: ${{ secrets.GITEA_TOKEN }} + GITEA_SERVER_URL: ${{ gitea.server_url }} + REPO: ${{ gitea.repository }} + PR_NUMBER: ${{ gitea.event.pull_request.number }} + run: | + REPORT_CONTENT=$(cat /tmp/webzine_endpoint_report.txt 2>/dev/null || echo "No report generated.") + FAILED_COUNT="${{ steps.perf_test.outputs.failed }}" + + if [ "${FAILED_COUNT:-0}" -gt 0 ]; then + HEADER="## ❌ Performance Check FAILED" + INTRO="${FAILED_COUNT} endpoint(s) exceeded 1 second or returned a server error." + else + HEADER="## ✅ Performance Check PASSED" + INTRO="All endpoints responded in under 1 second." + fi + + BODY=$(cat < Threshold: **1000ms** | Checked by the **PR Endpoint Performance** workflow. + EOF + ) + + curl -s -X POST \ + -H "Authorization: token $GITEA_TOKEN" \ + -H "Content-Type: application/json" \ + -d "$(jq -n --arg body "$BODY" '{body: $body}')" \ + "$GITEA_SERVER_URL/api/v1/repos/$REPO/issues/$PR_NUMBER/comments" + + # ───────────────────────────────────────────── + # 8. Fail the job if any endpoint failed + # ───────────────────────────────────────────── + - name: Enforce performance gate + run: | + FAILED="${{ steps.perf_test.outputs.failed }}" + if [ "${FAILED:-0}" -gt 0 ]; then + echo "❌ PR REJECTED: ${FAILED} endpoint(s) failed the 1-second threshold." + echo " Fix the slow/failing endpoints listed above before merging." + exit 1 + else + echo "✅ All endpoints passed the performance gate." + fi \ No newline at end of file diff --git a/scripts/test-endpoints.sh b/scripts/test-endpoints.sh new file mode 100644 index 0000000..a768ecd --- /dev/null +++ b/scripts/test-endpoints.sh @@ -0,0 +1,221 @@ +#!/usr/bin/env bash +# ============================================================================= +# test-endpoints.sh +# Tests all Webzine endpoints and reports which ones exceed the threshold. +# +# Usage: +# ./scripts/test-endpoints.sh [BASE_URL] [MAX_MS] +# +# Examples: +# ./scripts/test-endpoints.sh # defaults: localhost:5038, 1000ms +# ./scripts/test-endpoints.sh http://localhost:5038 500 +# ============================================================================= + +set -euo pipefail + +BASE_URL="${1:-http://localhost:5038}" +MAX_MS="${2:-1000}" +REPORT_FILE="/tmp/webzine_endpoint_report.txt" +FAILED=0 +TOTAL=0 + +# ── Colours ────────────────────────────────────────────────────────────────── +RED='\033[0;31m' +YELLOW='\033[1;33m' +GREEN='\033[0;32m' +CYAN='\033[0;36m' +BOLD='\033[1m' +RESET='\033[0m' + +# ── Helpers ────────────────────────────────────────────────────────────────── +log() { echo -e "$*"; } +pass() { log "${GREEN}[PASS]${RESET} $*"; } +fail() { log "${RED}[FAIL]${RESET} $*"; FAILED=$((FAILED + 1)); } +slow() { log "${YELLOW}[SLOW]${RESET} $*"; FAILED=$((FAILED + 1)); } +info() { log "${CYAN}$*${RESET}"; } + +# ── check_endpoint ──────────────────────────────────────────────────────────── +# Arguments: +# $1 HTTP method (GET | POST) +# $2 URL (absolute) +# $3 Label (human-readable) +# $4 Body data (optional, for POST) +# $5 Content-Type (optional, default: application/x-www-form-urlencoded) +# ───────────────────────────────────────────────────────────────────────────── +check_endpoint() { + local METHOD="${1:-GET}" + local URL="$2" + local LABEL="$3" + local BODY="${4:-}" + local CONTENT_TYPE="${5:-application/x-www-form-urlencoded}" + + TOTAL=$((TOTAL + 1)) + + if [ "$METHOD" = "POST" ] && [ -n "$BODY" ]; then + RESPONSE=$(curl -s -o /dev/null \ + -w "%{http_code}|%{time_total}" \ + -X POST \ + -H "Content-Type: $CONTENT_TYPE" \ + -d "$BODY" \ + --max-time 10 \ + "$URL" 2>&1) || RESPONSE="000|9.999" + else + RESPONSE=$(curl -s -o /dev/null \ + -w "%{http_code}|%{time_total}" \ + -X GET \ + --max-time 10 \ + --location \ + "$URL" 2>&1) || RESPONSE="000|9.999" + fi + + HTTP_CODE=$(echo "$RESPONSE" | cut -d'|' -f1) + TIME_TOTAL=$(echo "$RESPONSE" | cut -d'|' -f2) + + # Convert to integer milliseconds — awk is locale-safe, no bc/printf decimal issues + TIME_MS=$(awk "BEGIN {printf \"%.0f\", $TIME_TOTAL * 1000}") + + # Evaluate result + if [ "${HTTP_CODE:-0}" -ge 500 ] 2>/dev/null; then + slow "$LABEL → HTTP $HTTP_CODE (${TIME_MS}ms)" + echo "[FAIL] $LABEL → HTTP $HTTP_CODE (${TIME_MS}ms)" >> "$REPORT_FILE" + elif [ "${TIME_MS:-99999}" -gt "$MAX_MS" ] 2>/dev/null; then + slow "$LABEL → ${TIME_MS}ms exceeds ${MAX_MS}ms threshold" + echo "[SLOW] $LABEL → ${TIME_MS}ms (limit: ${MAX_MS}ms)" >> "$REPORT_FILE" + else + pass "$LABEL → ${TIME_MS}ms" + echo "[OK] $LABEL → ${TIME_MS}ms" >> "$REPORT_FILE" + fi +} + +# ============================================================================= +# MAIN +# ============================================================================= + +# Initialise report +> "$REPORT_FILE" +cat >> "$REPORT_FILE" </dev/null || echo "$STYLE") + check_endpoint GET "$BASE_URL/titre/style/$ENCODED" "GET /titre/style/$STYLE" +done + +log "" +info "── Artiste ───────────────────────────────────────────────" +ARTISTES=("fatal-bazooka" "daft-punk" "justice" "kraftwerk") +for ARTISTE in "${ARTISTES[@]}"; do + check_endpoint GET "$BASE_URL/artiste/$ARTISTE" "GET /artiste/$ARTISTE" +done + +log "" +info "── Recherche (POST) ──────────────────────────────────────" +MOTS=("rock" "jazz" "pop" "metal") +for MOT in "${MOTS[@]}"; do + check_endpoint POST "$BASE_URL/recherche" \ + "POST /recherche (mot=$MOT)" \ + "mot=$MOT" +done + +log "" + +# ── ADMINISTRATION SECTION ──────────────────────────────────────────────────── +info "── Administration – Dashboard ────────────────────────────" +check_endpoint GET "$BASE_URL/Administration/Dashboard" "GET /Administration/Dashboard" + +log "" +info "── Administration – Artiste ──────────────────────────────" +check_endpoint GET "$BASE_URL/Administration/Artiste" "GET /Administration/Artiste (Index)" +check_endpoint GET "$BASE_URL/Administration/Artiste/Create" "GET /Administration/Artiste/Create" +check_endpoint GET "$BASE_URL/Administration/Artiste/Edit/1" "GET /Administration/Artiste/Edit/1" +check_endpoint GET "$BASE_URL/Administration/Artiste/Delete/1" "GET /Administration/Artiste/Delete/1" + +log "" +info "── Administration – Commentaire ──────────────────────────" +check_endpoint GET "$BASE_URL/Administration/Commentaire" "GET /Administration/Commentaire (Index)" +check_endpoint GET "$BASE_URL/Administration/Commentaire/Delete/1" \ + "GET /Administration/Commentaire/Delete/1" + +log "" +info "── Administration – Style ────────────────────────────────" +check_endpoint GET "$BASE_URL/Administration/Style" "GET /Administration/Style (Index)" +check_endpoint GET "$BASE_URL/Administration/Style/Create" "GET /Administration/Style/Create" +check_endpoint GET "$BASE_URL/Administration/Style/Edit/1" "GET /Administration/Style/Edit/1" +check_endpoint GET "$BASE_URL/Administration/Style/Delete/1" "GET /Administration/Style/Delete/1" + +log "" +info "── Administration – Titre ────────────────────────────────" +check_endpoint GET "$BASE_URL/Administration/Titre" "GET /Administration/Titre (Index)" +check_endpoint GET "$BASE_URL/Administration/Titre/Create" "GET /Administration/Titre/Create" +check_endpoint GET "$BASE_URL/Administration/Titre/Edit/1" "GET /Administration/Titre/Edit/1" +check_endpoint GET "$BASE_URL/Administration/Titre/Delete/1" "GET /Administration/Titre/Delete/1" + +# ── SUMMARY ─────────────────────────────────────────────────────────────────── +PASSED=$((TOTAL - FAILED)) + +log "" +info "╔══════════════════════════════════════════════════════════╗" +info "║ Results ║" +info "╚══════════════════════════════════════════════════════════╝" +log " Total : ${TOTAL}" +log " ${GREEN}Passed${RESET} : ${PASSED}" + +if [ "$FAILED" -gt 0 ]; then + log " ${RED}Failed${RESET} : ${FAILED}" + log "" + log "${RED}${BOLD}❌ FAILED ENDPOINTS:${RESET}" + grep -E "^\[(FAIL|SLOW)\]" "$REPORT_FILE" | while IFS= read -r line; do + log " ${RED}→${RESET} $line" + done + log "" + log "${RED}PR should be rejected. Fix the endpoints above.${RESET}" +else + log " ${GREEN}Failed${RESET} : 0" + log "" + log "${GREEN}${BOLD}✅ All endpoints are within the ${MAX_MS}ms threshold.${RESET}" +fi + +log "" +log "Full report saved to: ${REPORT_FILE}" +log "" + +# Write summary to report +cat >> "$REPORT_FILE" < Date: Thu, 26 Mar 2026 14:37:13 +0100 Subject: [PATCH 15/23] feat: add deployment workflow for production and development environments --- .gitea/workflows/deploy.yml | 151 ++++++++++++++++++++++++++++++++++++ 1 file changed, 151 insertions(+) create mode 100644 .gitea/workflows/deploy.yml diff --git a/.gitea/workflows/deploy.yml b/.gitea/workflows/deploy.yml new file mode 100644 index 0000000..f6ae360 --- /dev/null +++ b/.gitea/workflows/deploy.yml @@ -0,0 +1,151 @@ +name: Deploy Webzine + +on: + push: + branches: + - main + - dev + +jobs: + # ───────────────────────────────────────────── + # BUILD — commun aux deux branches + # ───────────────────────────────────────────── + build: + name: Build & Push Docker Image + runs-on: ubuntu-latest + + steps: + - name: Checkout code + uses: actions/checkout@v4 + + # Le tag d'image dépend de la branche : + # main → webzine:latest + # dev → webzine:dev + - name: Set image tag + id: vars + run: | + if [ "${{ gitea.ref_name }}" = "main" ]; then + echo "IMAGE_TAG=latest" >> $GITHUB_OUTPUT + echo "ENV_LABEL=production" >> $GITHUB_OUTPUT + else + echo "IMAGE_TAG=dev" >> $GITHUB_OUTPUT + echo "ENV_LABEL=development" >> $GITHUB_OUTPUT + fi + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + + # Connexion au registry Gitea intégré + - name: Log in to Gitea Container Registry + uses: docker/login-action@v3 + with: + registry: ${{ vars.REGISTRY_URL }} + username: ${{ secrets.REGISTRY_USERNAME }} + password: ${{ secrets.REGISTRY_PASSWORD }} + + - name: Build and push Docker image + uses: docker/build-push-action@v5 + with: + context: . + file: ./Webzine.WebApplication/Dockerfile + push: true + tags: ${{ vars.REGISTRY_URL }}/webzine/webzine:${{ steps.vars.outputs.IMAGE_TAG }} + cache-from: type=registry,ref=${{ vars.REGISTRY_URL }}/webzine/webzine:buildcache-${{ steps.vars.outputs.IMAGE_TAG }} + cache-to: type=registry,ref=${{ vars.REGISTRY_URL }}/webzine/webzine:buildcache-${{ steps.vars.outputs.IMAGE_TAG }},mode=max + + outputs: + image_tag: ${{ steps.vars.outputs.IMAGE_TAG }} + env_label: ${{ steps.vars.outputs.ENV_LABEL }} + + # ───────────────────────────────────────────── + # DEPLOY — Machine de PRODUCTION (branche main) + # ───────────────────────────────────────────── + deploy-production: + name: Deploy to Production + needs: build + if: gitea.ref_name == 'main' + runs-on: ubuntu-latest # l'agent doit être joignable depuis le runner + + steps: + - name: Deploy via SSH to PRODUCTION server + uses: appleboy/ssh-action@v1.0.3 + with: + host: ${{ secrets.PROD_SSH_HOST }} + username: ${{ secrets.PROD_SSH_USER }} + key: ${{ secrets.PROD_SSH_KEY }} + port: ${{ secrets.PROD_SSH_PORT || 22 }} + script: | + set -e + + echo "=== [PROD] Pulling image ===" + docker login ${{ vars.REGISTRY_URL }} \ + -u ${{ secrets.REGISTRY_USERNAME }} \ + -p ${{ secrets.REGISTRY_PASSWORD }} + + docker pull ${{ vars.REGISTRY_URL }}/webzine/webzine:latest + + echo "=== [PROD] Stopping old container ===" + docker stop webzine-prod 2>/dev/null || true + docker rm webzine-prod 2>/dev/null || true + + echo "=== [PROD] Starting new container ===" + docker run -d \ + --name webzine-prod \ + --restart unless-stopped \ + -p 80:8080 \ + -p 443:8081 \ + -v /opt/webzine/prod/data:/app/Data \ + -v /opt/webzine/prod/logs:/Logs \ + -e ASPNETCORE_ENVIRONMENT=Production \ + ${{ vars.REGISTRY_URL }}/webzine/webzine:latest + + echo "=== [PROD] Cleaning up old images ===" + docker image prune -f + + echo "=== [PROD] Deployment complete ===" + + # ───────────────────────────────────────────── + # DEPLOY — Machine de DÉVELOPPEMENT (branche dev) + # ───────────────────────────────────────────── + deploy-development: + name: Deploy to Development + needs: build + if: gitea.ref_name == 'dev' + runs-on: ubuntu-latest + + steps: + - name: Deploy via SSH to DEVELOPMENT server + uses: appleboy/ssh-action@v1.0.3 + with: + host: ${{ secrets.DEV_SSH_HOST }} + username: ${{ secrets.DEV_SSH_USER }} + key: ${{ secrets.DEV_SSH_KEY }} + port: ${{ secrets.DEV_SSH_PORT || 22 }} + script: | + set -e + + echo "=== [DEV] Pulling image ===" + docker login ${{ vars.REGISTRY_URL }} \ + -u ${{ secrets.REGISTRY_USERNAME }} \ + -p ${{ secrets.REGISTRY_PASSWORD }} + + docker pull ${{ vars.REGISTRY_URL }}/webzine/webzine:dev + + echo "=== [DEV] Stopping old container ===" + docker stop webzine-dev 2>/dev/null || true + docker rm webzine-dev 2>/dev/null || true + + echo "=== [DEV] Starting new container ===" + docker run -d \ + --name webzine-dev \ + --restart unless-stopped \ + -p 8080:8080 \ + -v /opt/webzine/dev/data:/app/Data \ + -v /opt/webzine/dev/logs:/Logs \ + -e ASPNETCORE_ENVIRONMENT=Development \ + ${{ vars.REGISTRY_URL }}/webzine/webzine:dev + + echo "=== [DEV] Cleaning up old images ===" + docker image prune -f + + echo "=== [DEV] Deployment complete ===" \ No newline at end of file From 4301cd0f720aa47056d3bcc7b3d29623fd4e6a85 Mon Sep 17 00:00:00 2001 From: mirage <119869686+ClementBobin@users.noreply.github.com> Date: Thu, 26 Mar 2026 14:37:21 +0100 Subject: [PATCH 16/23] fix: ensure production deployment runs on the correct agent --- .gitea/workflows/deploy.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitea/workflows/deploy.yml b/.gitea/workflows/deploy.yml index f6ae360..4ba731c 100644 --- a/.gitea/workflows/deploy.yml +++ b/.gitea/workflows/deploy.yml @@ -64,7 +64,7 @@ jobs: name: Deploy to Production needs: build if: gitea.ref_name == 'main' - runs-on: ubuntu-latest # l'agent doit être joignable depuis le runner + runs-on: ubuntu-latest steps: - name: Deploy via SSH to PRODUCTION server From ae2e415524e7f360cc6592dac9dded6e6d6ae2c6 Mon Sep 17 00:00:00 2001 From: "josephine.vetu" Date: Thu, 26 Mar 2026 15:18:39 +0100 Subject: [PATCH 17/23] #104 Suppression d'un fichier automatique et renommage d'un champ --- Webzine.Repository.Contracts/stylecop1.json | 14 -------------- .../Administration/Views/Commentaire/Index.cshtml | 2 +- 2 files changed, 1 insertion(+), 15 deletions(-) delete mode 100644 Webzine.Repository.Contracts/stylecop1.json diff --git a/Webzine.Repository.Contracts/stylecop1.json b/Webzine.Repository.Contracts/stylecop1.json deleted file mode 100644 index 42fb1f8..0000000 --- a/Webzine.Repository.Contracts/stylecop1.json +++ /dev/null @@ -1,14 +0,0 @@ -{ - // ACTION REQUIRED: This file was automatically added to your project, but it - // will not take effect until additional steps are taken to enable it. See the - // following page for additional information: - // - // https://github.com/DotNetAnalyzers/StyleCopAnalyzers/blob/master/documentation/EnableConfiguration.md - - "$schema": "https://raw.githubusercontent.com/DotNetAnalyzers/StyleCopAnalyzers/master/StyleCop.Analyzers/StyleCop.Analyzers/Settings/stylecop.schema.json", - "settings": { - "documentationRules": { - "companyName": "PlaceholderCompany" - } - } -} diff --git a/Webzine.WebApplication/Areas/Administration/Views/Commentaire/Index.cshtml b/Webzine.WebApplication/Areas/Administration/Views/Commentaire/Index.cshtml index e86350e..c8608b7 100644 --- a/Webzine.WebApplication/Areas/Administration/Views/Commentaire/Index.cshtml +++ b/Webzine.WebApplication/Areas/Administration/Views/Commentaire/Index.cshtml @@ -14,7 +14,7 @@ Titre - Auteur + Nom Commentaire Date de création Actions From 45b91d4c987d3573dc50ea7e59c241fbeeaade0b Mon Sep 17 00:00:00 2001 From: mirage <119869686+ClementBobin@users.noreply.github.com> Date: Thu, 26 Mar 2026 15:20:27 +0100 Subject: [PATCH 18/23] refactor: update French comments and variable names in test-endpoints script for consistency --- scripts/test-endpoints.sh | 228 +++++++++++++++++++------------------- 1 file changed, 117 insertions(+), 111 deletions(-) diff --git a/scripts/test-endpoints.sh b/scripts/test-endpoints.sh index a768ecd..146cfcb 100644 --- a/scripts/test-endpoints.sh +++ b/scripts/test-endpoints.sh @@ -1,13 +1,13 @@ #!/usr/bin/env bash # ============================================================================= # test-endpoints.sh -# Tests all Webzine endpoints and reports which ones exceed the threshold. +# Teste tous les endpoints du Webzine et signale ceux qui dépassent le seuil. # -# Usage: -# ./scripts/test-endpoints.sh [BASE_URL] [MAX_MS] +# Usage : +# ./scripts/test-endpoints.sh [URL_BASE] [MAX_MS] # -# Examples: -# ./scripts/test-endpoints.sh # defaults: localhost:5038, 1000ms +# Exemples : +# ./scripts/test-endpoints.sh # défauts : localhost:5038, 1000ms # ./scripts/test-endpoints.sh http://localhost:5038 500 # ============================================================================= @@ -15,207 +15,213 @@ set -euo pipefail BASE_URL="${1:-http://localhost:5038}" MAX_MS="${2:-1000}" -REPORT_FILE="/tmp/webzine_endpoint_report.txt" -FAILED=0 +RAPPORT_FICHIER="/tmp/webzine_rapport_endpoints.txt" +ECHECS=0 TOTAL=0 -# ── Colours ────────────────────────────────────────────────────────────────── -RED='\033[0;31m' -YELLOW='\033[1;33m' -GREEN='\033[0;32m' +# ── Couleurs ────────────────────────────────────────────────────────────────── +ROUGE='\033[0;31m' +JAUNE='\033[1;33m' +VERT='\033[0;32m' CYAN='\033[0;36m' -BOLD='\033[1m' +GRAS='\033[1m' RESET='\033[0m' -# ── Helpers ────────────────────────────────────────────────────────────────── -log() { echo -e "$*"; } -pass() { log "${GREEN}[PASS]${RESET} $*"; } -fail() { log "${RED}[FAIL]${RESET} $*"; FAILED=$((FAILED + 1)); } -slow() { log "${YELLOW}[SLOW]${RESET} $*"; FAILED=$((FAILED + 1)); } -info() { log "${CYAN}$*${RESET}"; } +# ── Fonctions utilitaires ────────────────────────────────────────────────────── +log() { echo -e "$*"; } +succes() { log "${VERT}[OK]${RESET} $*"; } +echec() { log "${ROUGE}[ÉCHEC]${RESET} $*"; ECHECS=$((ECHECS + 1)); } +lent() { log "${JAUNE}[LENT]${RESET} $*"; ECHECS=$((ECHECS + 1)); } +info() { log "${CYAN}$*${RESET}"; } -# ── check_endpoint ──────────────────────────────────────────────────────────── -# Arguments: -# $1 HTTP method (GET | POST) -# $2 URL (absolute) -# $3 Label (human-readable) -# $4 Body data (optional, for POST) -# $5 Content-Type (optional, default: application/x-www-form-urlencoded) +# ── verifier_endpoint ───────────────────────────────────────────────────────── +# Arguments : +# $1 Méthode HTTP (GET | POST) +# $2 URL (absolue) +# $3 Libellé (texte lisible) +# $4 Corps (optionnel, pour POST) +# $5 Content-Type (optionnel, défaut : application/x-www-form-urlencoded) # ───────────────────────────────────────────────────────────────────────────── -check_endpoint() { - local METHOD="${1:-GET}" +verifier_endpoint() { + local METHODE="${1:-GET}" local URL="$2" - local LABEL="$3" - local BODY="${4:-}" - local CONTENT_TYPE="${5:-application/x-www-form-urlencoded}" + local LIBELLE="$3" + local CORPS="${4:-}" + local TYPE_CONTENU="${5:-application/x-www-form-urlencoded}" TOTAL=$((TOTAL + 1)) - if [ "$METHOD" = "POST" ] && [ -n "$BODY" ]; then - RESPONSE=$(curl -s -o /dev/null \ + # Exécution de la requête selon la méthode HTTP + if [ "$METHODE" = "POST" ] && [ -n "$CORPS" ]; then + REPONSE=$(curl -s -o /dev/null \ -w "%{http_code}|%{time_total}" \ -X POST \ - -H "Content-Type: $CONTENT_TYPE" \ - -d "$BODY" \ + -H "Content-Type: $TYPE_CONTENU" \ + -d "$CORPS" \ --max-time 10 \ - "$URL" 2>&1) || RESPONSE="000|9.999" + "$URL" 2>&1) || REPONSE="000|9.999" else - RESPONSE=$(curl -s -o /dev/null \ + REPONSE=$(curl -s -o /dev/null \ -w "%{http_code}|%{time_total}" \ -X GET \ --max-time 10 \ --location \ - "$URL" 2>&1) || RESPONSE="000|9.999" + "$URL" 2>&1) || REPONSE="000|9.999" fi - HTTP_CODE=$(echo "$RESPONSE" | cut -d'|' -f1) - TIME_TOTAL=$(echo "$RESPONSE" | cut -d'|' -f2) + # Extraction du code HTTP et du temps de réponse + CODE_HTTP=$(echo "$REPONSE" | cut -d'|' -f1) + TEMPS_TOTAL=$(echo "$REPONSE" | cut -d'|' -f2) - # Convert to integer milliseconds — awk is locale-safe, no bc/printf decimal issues - TIME_MS=$(awk "BEGIN {printf \"%.0f\", $TIME_TOTAL * 1000}") + # Conversion en millisecondes entières — awk évite les problèmes de locale décimale + TEMPS_MS=$(awk "BEGIN {printf \"%.0f\", $TEMPS_TOTAL * 1000}") - # Evaluate result - if [ "${HTTP_CODE:-0}" -ge 500 ] 2>/dev/null; then - slow "$LABEL → HTTP $HTTP_CODE (${TIME_MS}ms)" - echo "[FAIL] $LABEL → HTTP $HTTP_CODE (${TIME_MS}ms)" >> "$REPORT_FILE" - elif [ "${TIME_MS:-99999}" -gt "$MAX_MS" ] 2>/dev/null; then - slow "$LABEL → ${TIME_MS}ms exceeds ${MAX_MS}ms threshold" - echo "[SLOW] $LABEL → ${TIME_MS}ms (limit: ${MAX_MS}ms)" >> "$REPORT_FILE" + # Évaluation du résultat : erreur serveur, dépassement de seuil ou succès + if [ "${CODE_HTTP:-0}" -ge 500 ] 2>/dev/null; then + echec "$LIBELLE → HTTP $CODE_HTTP (${TEMPS_MS}ms)" + echo "[ÉCHEC] $LIBELLE → HTTP $CODE_HTTP (${TEMPS_MS}ms)" >> "$RAPPORT_FICHIER" + elif [ "${TEMPS_MS:-99999}" -gt "$MAX_MS" ] 2>/dev/null; then + lent "$LIBELLE → ${TEMPS_MS}ms dépasse le seuil de ${MAX_MS}ms" + echo "[LENT] $LIBELLE → ${TEMPS_MS}ms (limite : ${MAX_MS}ms)" >> "$RAPPORT_FICHIER" else - pass "$LABEL → ${TIME_MS}ms" - echo "[OK] $LABEL → ${TIME_MS}ms" >> "$REPORT_FILE" + succes "$LIBELLE → ${TEMPS_MS}ms" + echo "[OK] $LIBELLE → ${TEMPS_MS}ms" >> "$RAPPORT_FICHIER" fi } # ============================================================================= -# MAIN +# PROGRAMME PRINCIPAL # ============================================================================= -# Initialise report -> "$REPORT_FILE" -cat >> "$REPORT_FILE" < "$RAPPORT_FICHIER" +cat >> "$RAPPORT_FICHIER" </dev/null || echo "$STYLE") - check_endpoint GET "$BASE_URL/titre/style/$ENCODED" "GET /titre/style/$STYLE" + ENCODE=$(python3 -c "import urllib.parse; print(urllib.parse.quote('$STYLE'))" 2>/dev/null || echo "$STYLE") + verifier_endpoint GET "$BASE_URL/titre/style/$ENCODE" "GET /titre/style/$STYLE" done log "" info "── Artiste ───────────────────────────────────────────────" +# Test des pages artiste avec des noms en kebab-case ARTISTES=("fatal-bazooka" "daft-punk" "justice" "kraftwerk") for ARTISTE in "${ARTISTES[@]}"; do - check_endpoint GET "$BASE_URL/artiste/$ARTISTE" "GET /artiste/$ARTISTE" + verifier_endpoint GET "$BASE_URL/artiste/$ARTISTE" "GET /artiste/$ARTISTE" done log "" info "── Recherche (POST) ──────────────────────────────────────" +# Test de la recherche plein texte par mots-clés MOTS=("rock" "jazz" "pop" "metal") for MOT in "${MOTS[@]}"; do - check_endpoint POST "$BASE_URL/recherche" \ + verifier_endpoint POST "$BASE_URL/recherche" \ "POST /recherche (mot=$MOT)" \ "mot=$MOT" done log "" -# ── ADMINISTRATION SECTION ──────────────────────────────────────────────────── -info "── Administration – Dashboard ────────────────────────────" -check_endpoint GET "$BASE_URL/Administration/Dashboard" "GET /Administration/Dashboard" +# ── SECTION ADMINISTRATION ──────────────────────────────────────────────────── +info "── Administration – Tableau de bord ──────────────────────" +verifier_endpoint GET "$BASE_URL/Administration/Dashboard" "GET /Administration/Dashboard" log "" info "── Administration – Artiste ──────────────────────────────" -check_endpoint GET "$BASE_URL/Administration/Artiste" "GET /Administration/Artiste (Index)" -check_endpoint GET "$BASE_URL/Administration/Artiste/Create" "GET /Administration/Artiste/Create" -check_endpoint GET "$BASE_URL/Administration/Artiste/Edit/1" "GET /Administration/Artiste/Edit/1" -check_endpoint GET "$BASE_URL/Administration/Artiste/Delete/1" "GET /Administration/Artiste/Delete/1" +verifier_endpoint GET "$BASE_URL/Administration/Artiste" "GET /Administration/Artiste (liste)" +verifier_endpoint GET "$BASE_URL/Administration/Artiste/Create" "GET /Administration/Artiste/Create" +verifier_endpoint GET "$BASE_URL/Administration/Artiste/Edit/1" "GET /Administration/Artiste/Edit/1" +verifier_endpoint GET "$BASE_URL/Administration/Artiste/Delete/1" "GET /Administration/Artiste/Delete/1" log "" info "── Administration – Commentaire ──────────────────────────" -check_endpoint GET "$BASE_URL/Administration/Commentaire" "GET /Administration/Commentaire (Index)" -check_endpoint GET "$BASE_URL/Administration/Commentaire/Delete/1" \ - "GET /Administration/Commentaire/Delete/1" +verifier_endpoint GET "$BASE_URL/Administration/Commentaire" "GET /Administration/Commentaire (liste)" +verifier_endpoint GET "$BASE_URL/Administration/Commentaire/Delete/1" "GET /Administration/Commentaire/Delete/1" log "" info "── Administration – Style ────────────────────────────────" -check_endpoint GET "$BASE_URL/Administration/Style" "GET /Administration/Style (Index)" -check_endpoint GET "$BASE_URL/Administration/Style/Create" "GET /Administration/Style/Create" -check_endpoint GET "$BASE_URL/Administration/Style/Edit/1" "GET /Administration/Style/Edit/1" -check_endpoint GET "$BASE_URL/Administration/Style/Delete/1" "GET /Administration/Style/Delete/1" +verifier_endpoint GET "$BASE_URL/Administration/Style" "GET /Administration/Style (liste)" +verifier_endpoint GET "$BASE_URL/Administration/Style/Create" "GET /Administration/Style/Create" +verifier_endpoint GET "$BASE_URL/Administration/Style/Edit/1" "GET /Administration/Style/Edit/1" +verifier_endpoint GET "$BASE_URL/Administration/Style/Delete/1" "GET /Administration/Style/Delete/1" log "" info "── Administration – Titre ────────────────────────────────" -check_endpoint GET "$BASE_URL/Administration/Titre" "GET /Administration/Titre (Index)" -check_endpoint GET "$BASE_URL/Administration/Titre/Create" "GET /Administration/Titre/Create" -check_endpoint GET "$BASE_URL/Administration/Titre/Edit/1" "GET /Administration/Titre/Edit/1" -check_endpoint GET "$BASE_URL/Administration/Titre/Delete/1" "GET /Administration/Titre/Delete/1" +verifier_endpoint GET "$BASE_URL/Administration/Titre" "GET /Administration/Titre (liste)" +verifier_endpoint GET "$BASE_URL/Administration/Titre/Create" "GET /Administration/Titre/Create" +verifier_endpoint GET "$BASE_URL/Administration/Titre/Edit/1" "GET /Administration/Titre/Edit/1" +verifier_endpoint GET "$BASE_URL/Administration/Titre/Delete/1" "GET /Administration/Titre/Delete/1" -# ── SUMMARY ─────────────────────────────────────────────────────────────────── -PASSED=$((TOTAL - FAILED)) +# ── RÉCAPITULATIF ───────────────────────────────────────────────────────────── +REUSSIS=$((TOTAL - ECHECS)) log "" info "╔══════════════════════════════════════════════════════════╗" -info "║ Results ║" +info "║ Résultats ║" info "╚══════════════════════════════════════════════════════════╝" -log " Total : ${TOTAL}" -log " ${GREEN}Passed${RESET} : ${PASSED}" +log " Total : ${TOTAL}" +log " ${VERT}Réussis${RESET} : ${REUSSIS}" -if [ "$FAILED" -gt 0 ]; then - log " ${RED}Failed${RESET} : ${FAILED}" +if [ "$ECHECS" -gt 0 ]; then + log " ${ROUGE}Échecs${RESET} : ${ECHECS}" log "" - log "${RED}${BOLD}❌ FAILED ENDPOINTS:${RESET}" - grep -E "^\[(FAIL|SLOW)\]" "$REPORT_FILE" | while IFS= read -r line; do - log " ${RED}→${RESET} $line" + log "${ROUGE}${GRAS}❌ ENDPOINTS EN ÉCHEC :${RESET}" + # Affichage de tous les endpoints ayant échoué ou dépassé le seuil + grep -E "^\[(ÉCHEC|LENT)\]" "$RAPPORT_FICHIER" | while IFS= read -r ligne; do + log " ${ROUGE}→${RESET} $ligne" done log "" - log "${RED}PR should be rejected. Fix the endpoints above.${RESET}" + log "${ROUGE}La PR doit être rejetée. Corrigez les endpoints ci-dessus.${RESET}" else - log " ${GREEN}Failed${RESET} : 0" + log " ${VERT}Échecs${RESET} : 0" log "" - log "${GREEN}${BOLD}✅ All endpoints are within the ${MAX_MS}ms threshold.${RESET}" + log "${VERT}${GRAS}✅ Tous les endpoints respectent le seuil de ${MAX_MS}ms.${RESET}" fi log "" -log "Full report saved to: ${REPORT_FILE}" +log "Rapport complet enregistré dans : ${RAPPORT_FICHIER}" log "" -# Write summary to report -cat >> "$REPORT_FILE" <> "$RAPPORT_FICHIER" < Date: Thu, 26 Mar 2026 15:20:51 +0100 Subject: [PATCH 19/23] =?UTF-8?q?refactor=C2=A0:=20mettre=20=C3=A0=20jour?= =?UTF-8?q?=20les=20commentaires=20fran=C3=A7ais=20pour=20plus=20de=20clar?= =?UTF-8?q?t=C3=A9=20et=20de=20coh=C3=A9rence=20dans=20le=20d=C3=A9ploieme?= =?UTF-8?q?nt=20et=20les=20workflows=20de=20v=C3=A9rification=20des=20poin?= =?UTF-8?q?ts=20de=20terminaison=20PR?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitea/workflows/deploy.yml | 73 ++++---------------------- .gitea/workflows/pr-endpoint-check.yml | 38 +++++++------- 2 files changed, 29 insertions(+), 82 deletions(-) diff --git a/.gitea/workflows/deploy.yml b/.gitea/workflows/deploy.yml index 4ba731c..1b5ea9a 100644 --- a/.gitea/workflows/deploy.yml +++ b/.gitea/workflows/deploy.yml @@ -4,11 +4,10 @@ on: push: branches: - main - - dev jobs: # ───────────────────────────────────────────── - # BUILD — commun aux deux branches + # COMPILATION — commun aux deux branches # ───────────────────────────────────────────── build: name: Build & Push Docker Image @@ -20,17 +19,11 @@ jobs: # Le tag d'image dépend de la branche : # main → webzine:latest - # dev → webzine:dev - name: Set image tag id: vars run: | - if [ "${{ gitea.ref_name }}" = "main" ]; then - echo "IMAGE_TAG=latest" >> $GITHUB_OUTPUT - echo "ENV_LABEL=production" >> $GITHUB_OUTPUT - else - echo "IMAGE_TAG=dev" >> $GITHUB_OUTPUT - echo "ENV_LABEL=development" >> $GITHUB_OUTPUT - fi + echo "IMAGE_TAG=latest" >> $GITHUB_OUTPUT + echo "ENV_LABEL=production" >> $GITHUB_OUTPUT - name: Set up Docker Buildx uses: docker/setup-buildx-action@v3 @@ -43,6 +36,7 @@ jobs: username: ${{ secrets.REGISTRY_USERNAME }} password: ${{ secrets.REGISTRY_PASSWORD }} + # Construction et publication de l'image Docker - name: Build and push Docker image uses: docker/build-push-action@v5 with: @@ -58,12 +52,11 @@ jobs: env_label: ${{ steps.vars.outputs.ENV_LABEL }} # ───────────────────────────────────────────── - # DEPLOY — Machine de PRODUCTION (branche main) + # DÉPLOIEMENT — Serveur de PRODUCTION (branche main) # ───────────────────────────────────────────── deploy-production: name: Deploy to Production needs: build - if: gitea.ref_name == 'main' runs-on: ubuntu-latest steps: @@ -77,18 +70,18 @@ jobs: script: | set -e - echo "=== [PROD] Pulling image ===" + echo "=== [PROD] Récupération de l'image ===" docker login ${{ vars.REGISTRY_URL }} \ -u ${{ secrets.REGISTRY_USERNAME }} \ -p ${{ secrets.REGISTRY_PASSWORD }} docker pull ${{ vars.REGISTRY_URL }}/webzine/webzine:latest - echo "=== [PROD] Stopping old container ===" + echo "=== [PROD] Arrêt de l'ancien conteneur ===" docker stop webzine-prod 2>/dev/null || true docker rm webzine-prod 2>/dev/null || true - echo "=== [PROD] Starting new container ===" + echo "=== [PROD] Démarrage du nouveau conteneur ===" docker run -d \ --name webzine-prod \ --restart unless-stopped \ @@ -99,53 +92,7 @@ jobs: -e ASPNETCORE_ENVIRONMENT=Production \ ${{ vars.REGISTRY_URL }}/webzine/webzine:latest - echo "=== [PROD] Cleaning up old images ===" + echo "=== [PROD] Nettoyage des anciennes images ===" docker image prune -f - echo "=== [PROD] Deployment complete ===" - - # ───────────────────────────────────────────── - # DEPLOY — Machine de DÉVELOPPEMENT (branche dev) - # ───────────────────────────────────────────── - deploy-development: - name: Deploy to Development - needs: build - if: gitea.ref_name == 'dev' - runs-on: ubuntu-latest - - steps: - - name: Deploy via SSH to DEVELOPMENT server - uses: appleboy/ssh-action@v1.0.3 - with: - host: ${{ secrets.DEV_SSH_HOST }} - username: ${{ secrets.DEV_SSH_USER }} - key: ${{ secrets.DEV_SSH_KEY }} - port: ${{ secrets.DEV_SSH_PORT || 22 }} - script: | - set -e - - echo "=== [DEV] Pulling image ===" - docker login ${{ vars.REGISTRY_URL }} \ - -u ${{ secrets.REGISTRY_USERNAME }} \ - -p ${{ secrets.REGISTRY_PASSWORD }} - - docker pull ${{ vars.REGISTRY_URL }}/webzine/webzine:dev - - echo "=== [DEV] Stopping old container ===" - docker stop webzine-dev 2>/dev/null || true - docker rm webzine-dev 2>/dev/null || true - - echo "=== [DEV] Starting new container ===" - docker run -d \ - --name webzine-dev \ - --restart unless-stopped \ - -p 8080:8080 \ - -v /opt/webzine/dev/data:/app/Data \ - -v /opt/webzine/dev/logs:/Logs \ - -e ASPNETCORE_ENVIRONMENT=Development \ - ${{ vars.REGISTRY_URL }}/webzine/webzine:dev - - echo "=== [DEV] Cleaning up old images ===" - docker image prune -f - - echo "=== [DEV] Deployment complete ===" \ No newline at end of file + echo "=== [PROD] Déploiement terminé ===" \ No newline at end of file diff --git a/.gitea/workflows/pr-endpoint-check.yml b/.gitea/workflows/pr-endpoint-check.yml index c0936d2..c67fab3 100644 --- a/.gitea/workflows/pr-endpoint-check.yml +++ b/.gitea/workflows/pr-endpoint-check.yml @@ -14,13 +14,13 @@ jobs: steps: # ───────────────────────────────────────────── - # 1. Checkout code + # Récupération du code source # ───────────────────────────────────────────── - name: Checkout PR branch uses: actions/checkout@v4 # ───────────────────────────────────────────── - # 2. Setup .NET 10 + # Installation de .NET 10 # ───────────────────────────────────────────── - name: Setup .NET 10 uses: actions/setup-dotnet@v4 @@ -28,7 +28,7 @@ jobs: dotnet-version: "10.0.x" # ───────────────────────────────────────────── - # 3. Restore & Build + # Restauration des dépendances et compilation # ───────────────────────────────────────────── - name: Restore dependencies run: dotnet restore Webzine.sln @@ -37,7 +37,7 @@ jobs: run: dotnet build Webzine.sln --no-restore --configuration Release # ───────────────────────────────────────────── - # 4. Run unit tests (entity tests) + # Exécution des tests unitaires (entités) # ───────────────────────────────────────────── - name: Run unit tests run: | @@ -47,7 +47,7 @@ jobs: --logger "console;verbosity=normal" # ───────────────────────────────────────────── - # 5. Start the web application in background + # Démarrage de l'application web en arrière-plan # ───────────────────────────────────────────── - name: Start Webzine application run: | @@ -57,16 +57,16 @@ jobs: --no-build \ -- --urls "http://localhost:5038" & - echo "Waiting for application to start..." + echo "Attente du démarrage de l'application..." timeout 60 bash -c ' until curl -sf http://localhost:5038 > /dev/null 2>&1; do sleep 1 done ' - echo "Application is ready!" + echo "Application prête !" # ───────────────────────────────────────────── - # 6. Run endpoint performance tests + # Exécution des tests de performance des endpoints # ───────────────────────────────────────────── - name: Test endpoint response times id: perf_test @@ -77,7 +77,7 @@ jobs: echo "failed=$FAIL_COUNT" >> "$GITHUB_OUTPUT" # ───────────────────────────────────────────── - # 7. Post report as PR comment + # Publication du rapport en commentaire de PR # ───────────────────────────────────────────── - name: Post performance report as PR comment if: always() @@ -87,15 +87,15 @@ jobs: REPO: ${{ gitea.repository }} PR_NUMBER: ${{ gitea.event.pull_request.number }} run: | - REPORT_CONTENT=$(cat /tmp/webzine_endpoint_report.txt 2>/dev/null || echo "No report generated.") + REPORT_CONTENT=$(cat /tmp/webzine_endpoint_report.txt 2>/dev/null || echo "Aucun rapport généré.") FAILED_COUNT="${{ steps.perf_test.outputs.failed }}" if [ "${FAILED_COUNT:-0}" -gt 0 ]; then - HEADER="## ❌ Performance Check FAILED" - INTRO="${FAILED_COUNT} endpoint(s) exceeded 1 second or returned a server error." + HEADER="## ❌ Vérification des performances ÉCHOUÉE" + INTRO="${FAILED_COUNT} endpoint(s) ont dépassé 1 seconde ou retourné une erreur serveur." else - HEADER="## ✅ Performance Check PASSED" - INTRO="All endpoints responded in under 1 second." + HEADER="## ✅ Vérification des performances RÉUSSIE" + INTRO="Tous les endpoints ont répondu en moins d'une seconde." fi BODY=$(cat < Threshold: **1000ms** | Checked by the **PR Endpoint Performance** workflow. + > Seuil : **1000ms** | Vérifié par le workflow **PR Endpoint Performance**. EOF ) @@ -118,15 +118,15 @@ jobs: "$GITEA_SERVER_URL/api/v1/repos/$REPO/issues/$PR_NUMBER/comments" # ───────────────────────────────────────────── - # 8. Fail the job if any endpoint failed + # Blocage de la PR si un endpoint a échoué # ───────────────────────────────────────────── - name: Enforce performance gate run: | FAILED="${{ steps.perf_test.outputs.failed }}" if [ "${FAILED:-0}" -gt 0 ]; then - echo "❌ PR REJECTED: ${FAILED} endpoint(s) failed the 1-second threshold." - echo " Fix the slow/failing endpoints listed above before merging." + echo "❌ PR REJETÉE : ${FAILED} endpoint(s) n'ont pas respecté le seuil d'une seconde." + echo " Corrigez les endpoints lents ou en erreur avant de fusionner." exit 1 else - echo "✅ All endpoints passed the performance gate." + echo "✅ Tous les endpoints ont passé le contrôle de performance." fi \ No newline at end of file From ccf1436ffca4de4225c4944fb5b7840814551332 Mon Sep 17 00:00:00 2001 From: mirage <119869686+ClementBobin@users.noreply.github.com> Date: Thu, 26 Mar 2026 15:26:17 +0100 Subject: [PATCH 20/23] =?UTF-8?q?feat=C2=A0:=20ajouter=20des=20=C3=A9tapes?= =?UTF-8?q?=20de=20d=C3=A9ploiement=20pour=20l=E2=80=99environnement=20de?= =?UTF-8?q?=20d=C3=A9veloppement=20et=20mettre=20=C3=A0=20jour=20la=20logi?= =?UTF-8?q?que=20de=20marquage=20des=20images?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitea/workflows/deploy.yml | 108 +++++++++++++++++++++++++----------- 1 file changed, 75 insertions(+), 33 deletions(-) diff --git a/.gitea/workflows/deploy.yml b/.gitea/workflows/deploy.yml index 1b5ea9a..aaa3eb0 100644 --- a/.gitea/workflows/deploy.yml +++ b/.gitea/workflows/deploy.yml @@ -4,6 +4,7 @@ on: push: branches: - main + - dev jobs: # ───────────────────────────────────────────── @@ -19,11 +20,17 @@ jobs: # Le tag d'image dépend de la branche : # main → webzine:latest + # dev → webzine:dev - name: Set image tag id: vars run: | - echo "IMAGE_TAG=latest" >> $GITHUB_OUTPUT - echo "ENV_LABEL=production" >> $GITHUB_OUTPUT + if [ "${{ gitea.ref_name }}" = "main" ]; then + echo "IMAGE_TAG=latest" >> $GITHUB_OUTPUT + echo "ENV_LABEL=production" >> $GITHUB_OUTPUT + else + echo "IMAGE_TAG=dev" >> $GITHUB_OUTPUT + echo "ENV_LABEL=development" >> $GITHUB_OUTPUT + fi - name: Set up Docker Buildx uses: docker/setup-buildx-action@v3 @@ -57,42 +64,77 @@ jobs: deploy-production: name: Deploy to Production needs: build - runs-on: ubuntu-latest + if: gitea.ref_name == 'main' + runs-on: self-hosted steps: - - name: Deploy via SSH to PRODUCTION server - uses: appleboy/ssh-action@v1.0.3 - with: - host: ${{ secrets.PROD_SSH_HOST }} - username: ${{ secrets.PROD_SSH_USER }} - key: ${{ secrets.PROD_SSH_KEY }} - port: ${{ secrets.PROD_SSH_PORT || 22 }} - script: | - set -e + - name: Deploy on PRODUCTION server + run: | + set -e - echo "=== [PROD] Récupération de l'image ===" - docker login ${{ vars.REGISTRY_URL }} \ - -u ${{ secrets.REGISTRY_USERNAME }} \ - -p ${{ secrets.REGISTRY_PASSWORD }} + echo "=== [PROD] Récupération de l'image ===" + docker login ${{ vars.REGISTRY_URL }} \ + -u ${{ secrets.REGISTRY_USERNAME }} \ + -p ${{ secrets.REGISTRY_PASSWORD }} - docker pull ${{ vars.REGISTRY_URL }}/webzine/webzine:latest + docker pull ${{ vars.REGISTRY_URL }}/webzine/webzine:latest - echo "=== [PROD] Arrêt de l'ancien conteneur ===" - docker stop webzine-prod 2>/dev/null || true - docker rm webzine-prod 2>/dev/null || true + echo "=== [PROD] Arrêt de l'ancien conteneur ===" + docker stop webzine-prod 2>/dev/null || true + docker rm webzine-prod 2>/dev/null || true - echo "=== [PROD] Démarrage du nouveau conteneur ===" - docker run -d \ - --name webzine-prod \ - --restart unless-stopped \ - -p 80:8080 \ - -p 443:8081 \ - -v /opt/webzine/prod/data:/app/Data \ - -v /opt/webzine/prod/logs:/Logs \ - -e ASPNETCORE_ENVIRONMENT=Production \ - ${{ vars.REGISTRY_URL }}/webzine/webzine:latest + echo "=== [PROD] Démarrage du nouveau conteneur ===" + docker run -d \ + --name webzine-prod \ + --restart unless-stopped \ + -p 80:8080 \ + -p 443:8081 \ + -v /opt/webzine/prod/data:/app/Data \ + -v /opt/webzine/prod/logs:/Logs \ + -e ASPNETCORE_ENVIRONMENT=Production \ + ${{ vars.REGISTRY_URL }}/webzine/webzine:latest - echo "=== [PROD] Nettoyage des anciennes images ===" - docker image prune -f + echo "=== [PROD] Nettoyage des anciennes images ===" + docker image prune -f - echo "=== [PROD] Déploiement terminé ===" \ No newline at end of file + echo "=== [PROD] Déploiement terminé ===" + + # ───────────────────────────────────────────── + # DÉPLOIEMENT — Serveur de DÉVELOPPEMENT (branche dev) + # ───────────────────────────────────────────── + deploy-development: + name: Deploy to Development + needs: build + if: gitea.ref_name == 'dev' + runs-on: self-hosted + + steps: + - name: Deploy on DEVELOPMENT server + run: | + set -e + + echo "=== [DEV] Récupération de l'image ===" + docker login ${{ vars.REGISTRY_URL }} \ + -u ${{ secrets.REGISTRY_USERNAME }} \ + -p ${{ secrets.REGISTRY_PASSWORD }} + + docker pull ${{ vars.REGISTRY_URL }}/webzine/webzine:dev + + echo "=== [DEV] Arrêt de l'ancien conteneur ===" + docker stop webzine-dev 2>/dev/null || true + docker rm webzine-dev 2>/dev/null || true + + echo "=== [DEV] Démarrage du nouveau conteneur ===" + docker run -d \ + --name webzine-dev \ + --restart unless-stopped \ + -p 8080:8080 \ + -v /opt/webzine/dev/data:/app/Data \ + -v /opt/webzine/dev/logs:/Logs \ + -e ASPNETCORE_ENVIRONMENT=Development \ + ${{ vars.REGISTRY_URL }}/webzine/webzine:dev + + echo "=== [DEV] Nettoyage des anciennes images ===" + docker image prune -f + + echo "=== [DEV] Déploiement terminé ===" \ No newline at end of file From 1f2f4bc5128b39137b41c0ef4fcadba01287cfbe Mon Sep 17 00:00:00 2001 From: mirage <119869686+ClementBobin@users.noreply.github.com> Date: Thu, 26 Mar 2026 15:28:19 +0100 Subject: [PATCH 21/23] feat: update deployment workflow to use SSH for production server --- .gitea/workflows/deploy.yml | 107 +++++++++++------------------------- 1 file changed, 33 insertions(+), 74 deletions(-) diff --git a/.gitea/workflows/deploy.yml b/.gitea/workflows/deploy.yml index aaa3eb0..12661df 100644 --- a/.gitea/workflows/deploy.yml +++ b/.gitea/workflows/deploy.yml @@ -20,17 +20,11 @@ jobs: # Le tag d'image dépend de la branche : # main → webzine:latest - # dev → webzine:dev - name: Set image tag id: vars run: | - if [ "${{ gitea.ref_name }}" = "main" ]; then - echo "IMAGE_TAG=latest" >> $GITHUB_OUTPUT - echo "ENV_LABEL=production" >> $GITHUB_OUTPUT - else - echo "IMAGE_TAG=dev" >> $GITHUB_OUTPUT - echo "ENV_LABEL=development" >> $GITHUB_OUTPUT - fi + echo "IMAGE_TAG=latest" >> $GITHUB_OUTPUT + echo "ENV_LABEL=production" >> $GITHUB_OUTPUT - name: Set up Docker Buildx uses: docker/setup-buildx-action@v3 @@ -64,77 +58,42 @@ jobs: deploy-production: name: Deploy to Production needs: build - if: gitea.ref_name == 'main' - runs-on: self-hosted + runs-on: ubuntu-latest steps: - - name: Deploy on PRODUCTION server - run: | - set -e + - name: Deploy via SSH to PRODUCTION server + uses: appleboy/ssh-action@v1.0.3 + with: + host: ${{ secrets.PROD_SSH_HOST }} + username: ${{ secrets.PROD_SSH_USER }} + key: ${{ secrets.PROD_SSH_KEY }} + port: ${{ secrets.PROD_SSH_PORT || 22 }} + script: | + set -e - echo "=== [PROD] Récupération de l'image ===" - docker login ${{ vars.REGISTRY_URL }} \ - -u ${{ secrets.REGISTRY_USERNAME }} \ - -p ${{ secrets.REGISTRY_PASSWORD }} + echo "=== [PROD] Récupération de l'image ===" + docker login ${{ vars.REGISTRY_URL }} \ + -u ${{ secrets.REGISTRY_USERNAME }} \ + -p ${{ secrets.REGISTRY_PASSWORD }} - docker pull ${{ vars.REGISTRY_URL }}/webzine/webzine:latest + docker pull ${{ vars.REGISTRY_URL }}/webzine/webzine:latest - echo "=== [PROD] Arrêt de l'ancien conteneur ===" - docker stop webzine-prod 2>/dev/null || true - docker rm webzine-prod 2>/dev/null || true + echo "=== [PROD] Arrêt de l'ancien conteneur ===" + docker stop webzine-prod 2>/dev/null || true + docker rm webzine-prod 2>/dev/null || true - echo "=== [PROD] Démarrage du nouveau conteneur ===" - docker run -d \ - --name webzine-prod \ - --restart unless-stopped \ - -p 80:8080 \ - -p 443:8081 \ - -v /opt/webzine/prod/data:/app/Data \ - -v /opt/webzine/prod/logs:/Logs \ - -e ASPNETCORE_ENVIRONMENT=Production \ - ${{ vars.REGISTRY_URL }}/webzine/webzine:latest + echo "=== [PROD] Démarrage du nouveau conteneur ===" + docker run -d \ + --name webzine-prod \ + --restart unless-stopped \ + -p 80:8080 \ + -p 443:8081 \ + -v /opt/webzine/prod/data:/app/Data \ + -v /opt/webzine/prod/logs:/Logs \ + -e ASPNETCORE_ENVIRONMENT=Production \ + ${{ vars.REGISTRY_URL }}/webzine/webzine:latest - echo "=== [PROD] Nettoyage des anciennes images ===" - docker image prune -f + echo "=== [PROD] Nettoyage des anciennes images ===" + docker image prune -f - echo "=== [PROD] Déploiement terminé ===" - - # ───────────────────────────────────────────── - # DÉPLOIEMENT — Serveur de DÉVELOPPEMENT (branche dev) - # ───────────────────────────────────────────── - deploy-development: - name: Deploy to Development - needs: build - if: gitea.ref_name == 'dev' - runs-on: self-hosted - - steps: - - name: Deploy on DEVELOPMENT server - run: | - set -e - - echo "=== [DEV] Récupération de l'image ===" - docker login ${{ vars.REGISTRY_URL }} \ - -u ${{ secrets.REGISTRY_USERNAME }} \ - -p ${{ secrets.REGISTRY_PASSWORD }} - - docker pull ${{ vars.REGISTRY_URL }}/webzine/webzine:dev - - echo "=== [DEV] Arrêt de l'ancien conteneur ===" - docker stop webzine-dev 2>/dev/null || true - docker rm webzine-dev 2>/dev/null || true - - echo "=== [DEV] Démarrage du nouveau conteneur ===" - docker run -d \ - --name webzine-dev \ - --restart unless-stopped \ - -p 8080:8080 \ - -v /opt/webzine/dev/data:/app/Data \ - -v /opt/webzine/dev/logs:/Logs \ - -e ASPNETCORE_ENVIRONMENT=Development \ - ${{ vars.REGISTRY_URL }}/webzine/webzine:dev - - echo "=== [DEV] Nettoyage des anciennes images ===" - docker image prune -f - - echo "=== [DEV] Déploiement terminé ===" \ No newline at end of file + echo "=== [PROD] Déploiement terminé ===" \ No newline at end of file From 362a17d5f29487d4b32b7636a6d68d0aa72768c4 Mon Sep 17 00:00:00 2001 From: mirage <119869686+ClementBobin@users.noreply.github.com> Date: Thu, 26 Mar 2026 15:31:37 +0100 Subject: [PATCH 22/23] =?UTF-8?q?fix=C2=A0:=20mettre=20=C3=A0=20jour=20la?= =?UTF-8?q?=20configuration=20du=20d=C3=A9ploiement=20SSH=20pour=20le=20se?= =?UTF-8?q?rveur=20de=20production?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitea/workflows/deploy.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.gitea/workflows/deploy.yml b/.gitea/workflows/deploy.yml index 12661df..c58c5c7 100644 --- a/.gitea/workflows/deploy.yml +++ b/.gitea/workflows/deploy.yml @@ -64,8 +64,8 @@ jobs: - name: Deploy via SSH to PRODUCTION server uses: appleboy/ssh-action@v1.0.3 with: - host: ${{ secrets.PROD_SSH_HOST }} - username: ${{ secrets.PROD_SSH_USER }} + host: ${{ secrets.PROD_HOST }} + username: ${{ secrets.PROD_USER }} key: ${{ secrets.PROD_SSH_KEY }} port: ${{ secrets.PROD_SSH_PORT || 22 }} script: | From 957a1e3f424819c5eb3e354813c8caf5ae684946 Mon Sep 17 00:00:00 2001 From: "c.bobin" Date: Thu, 26 Mar 2026 15:43:55 +0100 Subject: [PATCH 23/23] Test: CI/CD Signed-off-by: c.bobin --- .dockerignore | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.dockerignore b/.dockerignore index cd967fc..59c3614 100644 --- a/.dockerignore +++ b/.dockerignore @@ -18,7 +18,7 @@ **/Dockerfile* **/node_modules **/npm-debug.log -**/obj +**/obj **/secrets.dev.yaml **/values.dev.yaml LICENSE