From 2b7202ffd6044911334c3a099621fb894677cd20 Mon Sep 17 00:00:00 2001 From: Ethan Date: Thu, 9 Apr 2026 15:04:12 +0200 Subject: [PATCH 1/4] chore(tests): Adding junits --- README.md | 1 + 1 file changed, 1 insertion(+) create mode 100644 README.md diff --git a/README.md b/README.md new file mode 100644 index 0000000..234c52f --- /dev/null +++ b/README.md @@ -0,0 +1 @@ +# DEVOPS From 46c32bf2d070e6a0beb4364ab78b215f3c4d0057 Mon Sep 17 00:00:00 2001 From: Ethan Date: Fri, 17 Apr 2026 15:08:02 +0200 Subject: [PATCH 2/4] docs: Add spec for JaCoCo and SonarCloud integration --- .../2026-04-17-jacoco-sonarcloud-design.md | 183 ++++++++++++++++++ 1 file changed, 183 insertions(+) create mode 100644 docs/superpowers/specs/2026-04-17-jacoco-sonarcloud-design.md diff --git a/docs/superpowers/specs/2026-04-17-jacoco-sonarcloud-design.md b/docs/superpowers/specs/2026-04-17-jacoco-sonarcloud-design.md new file mode 100644 index 0000000..b25cfbf --- /dev/null +++ b/docs/superpowers/specs/2026-04-17-jacoco-sonarcloud-design.md @@ -0,0 +1,183 @@ +# Spec — Intégration JaCoCo + SonarCloud + +**Date** : 2026-04-17 +**Projet** : DEVOPS_TP1 (Spring Boot 2.7.18, Gradle) +**Référence** : README de https://github.com/benoit-charroux/rent + +## Objectif + +Ajouter au projet : +1. **Couverture de code** via JaCoCo (rapport HTML + XML, seuil indicatif 80%) +2. **Contrôle qualité** via SonarCloud (analyse statique, code smells, vulnérabilités, bugs) + +Les deux doivent être exécutés dans le pipeline CI GitHub Actions sur chaque PR et chaque push sur `main`. + +## Périmètre + +**Inclus** +- Ajout du plugin JaCoCo à `build.gradle` +- Ajout du plugin `org.sonarqube` à `build.gradle` +- Fichier `sonar-project.properties` (ou équivalent dans `build.gradle`) +- Extension du workflow `.github/workflows/ci.yml` +- Documentation du setup manuel côté SonarCloud (README ou note) + +**Exclus** +- Blocage du build sur seuil de couverture (seuil **indicatif** uniquement) +- Écriture de nouveaux tests (l'existant JUnit est la base) +- Migration Java 1.8 → 17 (déjà incohérent entre `build.gradle` et CI, mais hors sujet) +- Tests MockMvc + +## Architecture + +### 1. JaCoCo — `build.gradle` + +```gradle +plugins { + id 'java' + id 'jacoco' + id 'org.springframework.boot' version '2.7.18' + id 'io.spring.dependency-management' version '1.1.4' +} + +jacoco { + toolVersion = "0.8.11" +} + +test { + finalizedBy jacocoTestReport +} + +jacocoTestReport { + dependsOn test + reports { + xml.required = true + html.required = true + } +} +``` + +**Sorties** : +- HTML : `build/reports/jacoco/test/html/index.html` +- XML : `build/reports/jacoco/test/jacocoTestReport.xml` (consommé par SonarCloud) + +**Seuil** : 80% indicatif — aucune tâche `jacocoTestCoverageVerification` n'est activée pour bloquer le build. + +### 2. SonarCloud — `build.gradle` + `sonar-project.properties` + +**`build.gradle`** (ajout du plugin) : + +```gradle +plugins { + // ... plugins existants + id 'org.sonarqube' version '4.4.1.3373' +} +``` + +**`sonar-project.properties`** (à la racine) : + +```properties +sonar.projectKey=BlueShork_devops_tp1 +sonar.organization= +sonar.host.url=https://sonarcloud.io +sonar.java.binaries=build/classes +sonar.coverage.jacoco.xmlReportPaths=build/reports/jacoco/test/jacocoTestReport.xml +``` + +`` à remplir une fois l'organisation SonarCloud créée (probablement `blueshork`). + +### 3. CI — `.github/workflows/ci.yml` étendu + +```yaml +name: CI + +on: + push: + branches: [main] + pull_request: + branches: [main] + +jobs: + build: + runs-on: ubuntu-latest + steps: + - name: Checkout repository + uses: actions/checkout@v4 + with: + fetch-depth: 0 # requis par SonarCloud + + - name: Set up Java + uses: actions/setup-java@v4 + with: + java-version: '17' + distribution: 'temurin' + + - name: Cache SonarCloud packages + uses: actions/cache@v4 + with: + path: ~/.sonar/cache + key: ${{ runner.os }}-sonar + restore-keys: ${{ runner.os }}-sonar + + - name: Cache Gradle packages + uses: actions/cache@v4 + with: + path: ~/.gradle/caches + key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle') }} + restore-keys: ${{ runner.os }}-gradle + + - name: Build and test with coverage + run: ./gradlew build jacocoTestReport + + - name: SonarCloud Scan + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} + run: ./gradlew sonar +``` + +### 4. Setup manuel SonarCloud (à faire par l'utilisateur après intégration) + +1. Se connecter à https://sonarcloud.io avec le compte GitHub +2. Créer/rejoindre l'organisation (noter la clé ``) +3. Importer le projet `DEVOPS_TP1` (projectKey attendu : `BlueShork_devops_tp1`) +4. Choisir le mode d'analyse **"With GitHub Actions"** (désactive l'Automatic Analysis) +5. Générer un token SonarCloud +6. Ajouter le token dans `GitHub → Settings → Secrets → SONAR_TOKEN` +7. Mettre à jour `sonar.organization` dans `sonar-project.properties` + +## Flux de données + +``` +./gradlew build jacocoTestReport + │ + ├─► build/classes/… (compilation Java) + ├─► build/reports/tests/test/ (rapports JUnit HTML) + └─► build/reports/jacoco/test/ + ├─► html/index.html (lecture humaine) + └─► jacocoTestReport.xml ─────┐ + │ +./gradlew sonar ◄──────────────────────────────┘ + │ + └─► SonarCloud (projet BlueShork_devops_tp1) + ├─► Coverage (%) + ├─► Bugs / Vulnerabilities / Code Smells + └─► Quality Gate status (affiché dans les PRs) +``` + +## Gestion des erreurs + +| Scénario | Comportement attendu | +|---|---| +| `SONAR_TOKEN` absent/invalide | Étape `sonar` échoue, le reste du build a déjà passé → rapport JaCoCo quand même disponible en artifact local | +| Tests échouent | `gradlew build` échoue → JaCoCo et Sonar non exécutés (ordre naturel) | +| `fetch-depth: 0` oublié | SonarCloud warn sur la détection de blame/branches mais l'analyse tourne | +| Couverture < 80% | Rapport affiche le chiffre, **aucun blocage** (seuil indicatif) | + +## Critères d'acceptation + +- [ ] `./gradlew test jacocoTestReport` génère `build/reports/jacoco/test/jacocoTestReport.xml` +- [ ] Rapport HTML JaCoCo ouvrable localement +- [ ] `sonar-project.properties` présent et référence le projectKey correct +- [ ] Workflow CI passe sur PR et push main (modulo SONAR_TOKEN à configurer) +- [ ] Une fois `SONAR_TOKEN` ajouté : résultat SonarCloud visible sur https://sonarcloud.io/project/overview?id=BlueShork_devops_tp1 +- [ ] Badge/statut SonarCloud remonté dans les PRs GitHub From 0e490572d50bd8b082ecb45733f5171a5f685c87 Mon Sep 17 00:00:00 2001 From: Ethan Date: Fri, 17 Apr 2026 15:12:14 +0200 Subject: [PATCH 3/4] feat(ci): Add JaCoCo coverage and SonarCloud quality analysis - Add jacoco plugin with XML+HTML reports for coverage tracking - Add org.sonarqube plugin with sonar-project.properties - Extend CI workflow with fetch-depth:0, caches, and sonar scan step - Trigger CI on push to main in addition to PRs --- .github/workflows/ci.yml | 30 ++++++++++++++++++++++++++---- build.gradle | 15 +++++++++++++++ sonar-project.properties | 10 ++++++++++ 3 files changed, 51 insertions(+), 4 deletions(-) create mode 100644 sonar-project.properties diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 0b8701b..bc79c49 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -1,6 +1,9 @@ name: CI on: + push: + branches: + - main pull_request: branches: - main @@ -12,6 +15,8 @@ jobs: steps: - name: Checkout repository uses: actions/checkout@v4 + with: + fetch-depth: 0 - name: Set up Java uses: actions/setup-java@v4 @@ -19,8 +24,25 @@ jobs: java-version: '17' distribution: 'temurin' - - name: Build with Gradle - run: ./gradlew build + - name: Cache SonarCloud packages + uses: actions/cache@v4 + with: + path: ~/.sonar/cache + key: ${{ runner.os }}-sonar + restore-keys: ${{ runner.os }}-sonar + + - name: Cache Gradle packages + uses: actions/cache@v4 + with: + path: ~/.gradle/caches + key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle') }} + restore-keys: ${{ runner.os }}-gradle + + - name: Build and test with coverage + run: ./gradlew build jacocoTestReport - - name: Run tests - run: ./gradlew test + - name: SonarCloud Scan + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} + run: ./gradlew sonar diff --git a/build.gradle b/build.gradle index 24dfc55..0a34735 100644 --- a/build.gradle +++ b/build.gradle @@ -1,7 +1,9 @@ plugins { id 'java' + id 'jacoco' id 'org.springframework.boot' version '2.7.18' id 'io.spring.dependency-management' version '1.1.4' + id 'org.sonarqube' version '4.4.1.3373' } group = 'fr.devops' @@ -20,6 +22,19 @@ dependencies { testImplementation 'org.springframework.boot:spring-boot-starter-test' } +jacoco { + toolVersion = "0.8.11" +} + tasks.named('test') { useJUnitPlatform() + finalizedBy jacocoTestReport +} + +jacocoTestReport { + dependsOn test + reports { + xml.required = true + html.required = true + } } diff --git a/sonar-project.properties b/sonar-project.properties new file mode 100644 index 0000000..23495e2 --- /dev/null +++ b/sonar-project.properties @@ -0,0 +1,10 @@ +sonar.projectKey=BlueShork_devops_tp1 +sonar.organization=blueshork +sonar.host.url=https://sonarcloud.io + +sonar.sources=src/main/java +sonar.tests=src/test/java +sonar.java.binaries=build/classes/java/main +sonar.java.test.binaries=build/classes/java/test + +sonar.coverage.jacoco.xmlReportPaths=build/reports/jacoco/test/jacocoTestReport.xml From b5e52b4eed89f38b95608bc7b00cb32a57f2692e Mon Sep 17 00:00:00 2001 From: Ethan Date: Fri, 17 Apr 2026 15:27:38 +0200 Subject: [PATCH 4/4] fix(ci): Move SonarCloud config to build.gradle sonar block The gradle sonarqube plugin does not read sonar-project.properties (that file is only for the standalone sonar-scanner CLI). Without this config the plugin defaulted to http://localhost:9000 and failed. Config is now inlined via the sonar { properties { ... } } block. --- build.gradle | 9 +++++++++ sonar-project.properties | 10 ---------- 2 files changed, 9 insertions(+), 10 deletions(-) delete mode 100644 sonar-project.properties diff --git a/build.gradle b/build.gradle index 0a34735..913d993 100644 --- a/build.gradle +++ b/build.gradle @@ -38,3 +38,12 @@ jacocoTestReport { html.required = true } } + +sonar { + properties { + property "sonar.projectKey", "BlueShork_devops_tp1" + property "sonar.organization", "blueshork" + property "sonar.host.url", "https://sonarcloud.io" + property "sonar.coverage.jacoco.xmlReportPaths", "build/reports/jacoco/test/jacocoTestReport.xml" + } +} diff --git a/sonar-project.properties b/sonar-project.properties deleted file mode 100644 index 23495e2..0000000 --- a/sonar-project.properties +++ /dev/null @@ -1,10 +0,0 @@ -sonar.projectKey=BlueShork_devops_tp1 -sonar.organization=blueshork -sonar.host.url=https://sonarcloud.io - -sonar.sources=src/main/java -sonar.tests=src/test/java -sonar.java.binaries=build/classes/java/main -sonar.java.test.binaries=build/classes/java/test - -sonar.coverage.jacoco.xmlReportPaths=build/reports/jacoco/test/jacocoTestReport.xml