diff --git a/.gitea/workflows/api-docs.yml b/.gitea/workflows/api-docs.yml index 29ad8f9..94860f1 100644 --- a/.gitea/workflows/api-docs.yml +++ b/.gitea/workflows/api-docs.yml @@ -114,7 +114,8 @@ jobs: sonar-scanner \ -Dsonar.host.url=${{ secrets.SONAR_HOST_URL }} \ -Dsonar.login=${{ secrets.SONAR_TOKEN }} \ - -Dsonar.projectKey=labFusion + -Dsonar.projectKey=labfusion-api-docs \ + -Dsonar.projectName=LabFusion API Docs - name: Test results summary if: always() diff --git a/.gitea/workflows/api-gateway.yml b/.gitea/workflows/api-gateway.yml index 20da5b8..7182d5a 100644 --- a/.gitea/workflows/api-gateway.yml +++ b/.gitea/workflows/api-gateway.yml @@ -129,36 +129,11 @@ jobs: if: env.TEST_REPORTS_EXIST == 'true' run: | echo "Sending test results to SonarQube..." - # Configure SonarQube properties - cat > sonar-project.properties << EOF - sonar.projectKey=labFusion - sonar.projectName=LabFusion - sonar.projectVersion=1.0.0 - sonar.modules=api-gateway - sonar.sources=src/main/java - sonar.tests=src/test/java - sonar.java.binaries=target/classes - sonar.java.test.binaries=target/test-classes - sonar.junit.reportPaths=target/surefire-reports - sonar.coverage.jacoco.xmlReportPaths=target/site/jacoco/jacoco.xml - sonar.host.url=${{ secrets.SONAR_HOST_URL }} - sonar.login=${{ secrets.SONAR_TOKEN }} - EOF - - # Run SonarQube analysis - ./mvnw sonar:sonar \ + ./mvnw clean verify sonar:sonar \ + -Dsonar.projectKey=labfusion-api-gateway \ + -Dsonar.projectName=LabFusion API Gateway \ -Dsonar.host.url=${{ secrets.SONAR_HOST_URL }} \ - -Dsonar.login=${{ secrets.SONAR_TOKEN }} \ - -Dsonar.projectKey=labFusion \ - -Dsonar.projectName="LabFusion" \ - -Dsonar.projectVersion=1.0.0 \ - -Dsonar.modules=api-gateway \ - -Dsonar.sources=src/main/java \ - -Dsonar.tests=src/test/java \ - -Dsonar.java.binaries=target/classes \ - -Dsonar.java.test.binaries=target/test-classes \ - -Dsonar.junit.reportPaths=target/surefire-reports \ - -Dsonar.coverage.jacoco.xmlReportPaths=target/site/jacoco/jacoco.xml + -Dsonar.token=${{ secrets.SONAR_TOKEN }} - name: Fail if no test reports found if: env.TEST_REPORTS_EXIST == 'false' diff --git a/.gitea/workflows/ci.yml b/.gitea/workflows/ci.yml index 0d74a74..01466af 100644 --- a/.gitea/workflows/ci.yml +++ b/.gitea/workflows/ci.yml @@ -46,28 +46,14 @@ jobs: maven- fail-on-cache-miss: false - - name: Run tests - run: ./mvnw test - - - name: Generate code coverage - run: ./mvnw jacoco:report - - - name: Send results to SonarQube + - name: Run tests and send to SonarQube run: | - echo "Sending API Gateway results to SonarQube..." - ./mvnw sonar:sonar \ + echo "Running tests and sending results to SonarQube..." + ./mvnw clean verify sonar:sonar \ + -Dsonar.projectKey=labfusion-api-gateway \ + -Dsonar.projectName=LabFusion API Gateway \ -Dsonar.host.url=${{ secrets.SONAR_HOST_URL }} \ - -Dsonar.login=${{ secrets.SONAR_TOKEN }} \ - -Dsonar.projectKey=labFusion \ - -Dsonar.projectName="LabFusion" \ - -Dsonar.projectVersion=1.0.0 \ - -Dsonar.modules=api-gateway \ - -Dsonar.sources=src/main/java \ - -Dsonar.tests=src/test/java \ - -Dsonar.java.binaries=target/classes \ - -Dsonar.java.test.binaries=target/test-classes \ - -Dsonar.junit.reportPaths=target/surefire-reports \ - -Dsonar.coverage.jacoco.xmlReportPaths=target/site/jacoco/jacoco.xml + -Dsonar.token=${{ secrets.SONAR_TOKEN }} - name: Run code quality checks run: ./mvnw spotbugs:check checkstyle:check @@ -130,20 +116,14 @@ jobs: run: | echo "Sending Service Adapters results to SonarQube..." # Install SonarQube Scanner for Python - pip install sonar-scanner + pip install pysonar # Run SonarQube analysis - sonar-scanner \ - -Dsonar.host.url=${{ secrets.SONAR_HOST_URL }} \ - -Dsonar.login=${{ secrets.SONAR_TOKEN }} \ - -Dsonar.projectKey=labFusion \ - -Dsonar.projectName="LabFusion" \ - -Dsonar.projectVersion=1.0.0 \ - -Dsonar.modules=service-adapters \ - -Dsonar.sources=. \ - -Dsonar.tests=tests \ - -Dsonar.python.coverage.reportPaths=coverage.xml \ - -Dsonar.python.xunit.reportPath=tests/reports/junit.xml + pysonar \ + --sonar-host-url=${{ secrets.SONAR_HOST_URL }} \ + --sonar-token=${{ secrets.SONAR_TOKEN }} \ + --sonar-project-key=labfusion-service-adapters \ + --sonar-project-name=LabFusion Service Adapters - name: Build Docker image (test only) run: docker build -t service-adapters:test . @@ -198,20 +178,14 @@ jobs: run: | echo "Sending API Docs results to SonarQube..." # Install SonarQube Scanner for Node.js - npm install -g sonar-scanner + npm install -g @sonar/scan # Run SonarQube analysis sonar-scanner \ -Dsonar.host.url=${{ secrets.SONAR_HOST_URL }} \ -Dsonar.login=${{ secrets.SONAR_TOKEN }} \ - -Dsonar.projectKey=labFusion \ - -Dsonar.projectName="LabFusion" \ - -Dsonar.projectVersion=1.0.0 \ - -Dsonar.modules=api-docs \ - -Dsonar.sources=. \ - -Dsonar.tests=__tests__ \ - -Dsonar.javascript.lcov.reportPaths=coverage/lcov.info \ - -Dsonar.testExecutionReportPaths=test-results.xml + -Dsonar.projectKey=labfusion-api-docs \ + -Dsonar.projectName=LabFusion API Docs - name: Build application run: npm run build @@ -269,20 +243,14 @@ jobs: run: | echo "Sending Frontend results to SonarQube..." # Install SonarQube Scanner for Node.js - npm install -g sonar-scanner + npm install -g @sonar/scan # Run SonarQube analysis sonar-scanner \ -Dsonar.host.url=${{ secrets.SONAR_HOST_URL }} \ -Dsonar.login=${{ secrets.SONAR_TOKEN }} \ - -Dsonar.projectKey=labFusion \ - -Dsonar.projectName="LabFusion" \ - -Dsonar.projectVersion=1.0.0 \ - -Dsonar.modules=frontend \ - -Dsonar.sources=src \ - -Dsonar.tests=src \ - -Dsonar.javascript.lcov.reportPaths=coverage/lcov.info \ - -Dsonar.testExecutionReportPaths=test-results.xml + -Dsonar.projectKey=labfusion-frontend \ + -Dsonar.projectName=LabFusion Frontend - name: Build application run: npm run build diff --git a/.gitea/workflows/frontend.yml b/.gitea/workflows/frontend.yml index 887568c..b0b679d 100644 --- a/.gitea/workflows/frontend.yml +++ b/.gitea/workflows/frontend.yml @@ -80,20 +80,14 @@ jobs: run: | echo "Sending Frontend results to SonarQube..." # Install SonarQube Scanner for Node.js - npm install -g sonar-scanner + npm install -g @sonar/scan # Run SonarQube analysis sonar-scanner \ -Dsonar.host.url=${{ secrets.SONAR_HOST_URL }} \ -Dsonar.login=${{ secrets.SONAR_TOKEN }} \ - -Dsonar.projectKey=labFusion \ - -Dsonar.projectName="LabFusion" \ - -Dsonar.projectVersion=1.0.0 \ - -Dsonar.modules=frontend \ - -Dsonar.sources=src \ - -Dsonar.tests=src \ - -Dsonar.javascript.lcov.reportPaths=coverage/lcov.info \ - -Dsonar.testExecutionReportPaths=test-results.xml + -Dsonar.projectKey=labfusion-frontend \ + -Dsonar.projectName=LabFusion Frontend - name: Test results summary if: always() diff --git a/.gitea/workflows/service-adapters.yml b/.gitea/workflows/service-adapters.yml index 92179e9..8918240 100644 --- a/.gitea/workflows/service-adapters.yml +++ b/.gitea/workflows/service-adapters.yml @@ -98,14 +98,8 @@ jobs: sonar-scanner \ -Dsonar.host.url=${{ secrets.SONAR_HOST_URL }} \ -Dsonar.login=${{ secrets.SONAR_TOKEN }} \ - -Dsonar.projectKey=labFusion \ - -Dsonar.projectName="LabFusion" \ - -Dsonar.projectVersion=1.0.0 \ - -Dsonar.modules=service-adapters \ - -Dsonar.sources=. \ - -Dsonar.tests=tests \ - -Dsonar.python.coverage.reportPaths=coverage.xml \ - -Dsonar.python.xunit.reportPath=tests/reports/junit.xml + -Dsonar.projectKey=labfusion-service-adapters \ + -Dsonar.projectName=LabFusion Service Adapters - name: Test results summary diff --git a/docs/SONARQUBE_INTEGRATION.md b/docs/SONARQUBE_INTEGRATION.md index d6cb237..661db13 100644 --- a/docs/SONARQUBE_INTEGRATION.md +++ b/docs/SONARQUBE_INTEGRATION.md @@ -1,10 +1,10 @@ # SonarQube Integration for LabFusion -This document explains how to configure SonarQube integration for all LabFusion services in a unified project. +This document explains how to configure SonarQube integration for all LabFusion services using individual projects per service. ## Overview -All LabFusion services (API Gateway, Service Adapters, API Docs, Frontend) now send test results, code coverage, and quality metrics directly to a single unified SonarQube project called "LabFusion" instead of using external test reporters. +Each LabFusion service has its own dedicated SonarQube project, providing better isolation, clearer metrics per service, and easier maintenance. This approach allows for service-specific quality gates and more granular reporting. ## Required Configuration @@ -17,10 +17,12 @@ You need to configure the following secrets in your Gitea repository: ### 2. SonarQube Project Setup -1. **Create a unified project** in SonarQube: - - Project Key: `labfusion` - - Project Name: `LabFusion` - - Main Branch: `main` +1. **Create individual projects** in SonarQube for each service: + - **API Gateway**: `labfusion-api-gateway` - "LabFusion API Gateway" + - **Service Adapters**: `labfusion-service-adapters` - "LabFusion Service Adapters" + - **API Docs**: `labfusion-api-docs` - "LabFusion API Docs" + - **Frontend**: `labfusion-frontend` - "LabFusion Frontend" + - Main Branch: `main` for all projects 2. **Generate an authentication token**: - Go to User > My Account > Security @@ -37,46 +39,57 @@ Configure quality gates in SonarQube to enforce: ## What Gets Sent to SonarQube -### Unified LabFusion Project Structure -- **Project Key**: `labfusion` -- **Project Name**: `LabFusion` -- **Modules**: - - `api-gateway` (Java Spring Boot) - - `service-adapters` (Python FastAPI) - - `api-docs` (Node.js Express) - - `frontend` (React) +### Individual Service Projects -### Test Results -- **API Gateway**: JUnit XML reports from `target/surefire-reports/` -- **Service Adapters**: pytest XML reports from `tests/reports/junit.xml` -- **API Docs**: Jest XML reports from `test-results.xml` -- **Frontend**: Jest XML reports from `test-results.xml` +#### API Gateway +- **Project Key**: `labfusion-api-gateway` +- **Project Name**: LabFusion API Gateway +- **Language**: Java Spring Boot +- **Test Reports**: JUnit XML from `target/surefire-reports/` +- **Coverage**: JaCoCo XML from `target/site/jacoco/jacoco.xml` -### Code Coverage -- **API Gateway**: JaCoCo XML report from `target/site/jacoco/jacoco.xml` -- **Service Adapters**: Coverage XML from `coverage.xml` -- **API Docs**: LCOV report from `coverage/lcov.info` -- **Frontend**: LCOV report from `coverage/lcov.info` +#### Service Adapters +- **Project Key**: `labfusion-service-adapters` +- **Project Name**: LabFusion Service Adapters +- **Language**: Python FastAPI +- **Test Reports**: pytest XML from `tests/reports/junit.xml` +- **Coverage**: Coverage XML from `coverage.xml` + +#### API Docs +- **Project Key**: `labfusion-api-docs` +- **Project Name**: LabFusion API Docs +- **Language**: Node.js Express +- **Test Reports**: Jest XML from `test-results.xml` +- **Coverage**: LCOV from `coverage/lcov.info` + +#### Frontend +- **Project Key**: `labfusion-frontend` +- **Project Name**: LabFusion Frontend +- **Language**: React +- **Test Reports**: Jest XML from `test-results.xml` +- **Coverage**: LCOV from `coverage/lcov.info` ### Code Quality Metrics -- **Source code analysis** results for all languages -- **Code smells** and issues across all services -- **Security vulnerabilities** detection -- **Maintainability ratings** per module +- **Source code analysis** results per service +- **Code smells** and issues per service +- **Security vulnerabilities** detection per service +- **Maintainability ratings** per service +- **Service-specific quality gates** and thresholds ## Pipeline Integration -### All Services Send to Unified Project -Each service workflow includes a SonarQube integration step: +### Individual Service Projects +Each service workflow sends results to its own dedicated SonarQube project: #### API Gateway (Java) ```yaml - name: Send test results to SonarQube run: | - ./mvnw sonar:sonar \ - -Dsonar.projectKey=labfusion \ - -Dsonar.modules=api-gateway \ - # ... other properties + ./mvnw clean verify sonar:sonar \ + -Dsonar.projectKey=labfusion-api-gateway \ + -Dsonar.projectName=LabFusion API Gateway \ + -Dsonar.host.url=${{ secrets.SONAR_HOST_URL }} \ + -Dsonar.token=${{ secrets.SONAR_TOKEN }} ``` #### Service Adapters (Python) @@ -84,19 +97,32 @@ Each service workflow includes a SonarQube integration step: - name: Send results to SonarQube run: | sonar-scanner \ - -Dsonar.projectKey=labfusion \ - -Dsonar.modules=service-adapters \ - # ... other properties + -Dsonar.projectKey=labfusion-service-adapters \ + -Dsonar.projectName=LabFusion Service Adapters \ + -Dsonar.host.url=${{ secrets.SONAR_HOST_URL }} \ + -Dsonar.login=${{ secrets.SONAR_TOKEN }} ``` -#### API Docs & Frontend (Node.js) +#### API Docs (Node.js) ```yaml - name: Send results to SonarQube run: | sonar-scanner \ - -Dsonar.projectKey=labfusion \ - -Dsonar.modules=api-docs \ - # ... other properties + -Dsonar.projectKey=labfusion-api-docs \ + -Dsonar.projectName=LabFusion API Docs \ + -Dsonar.host.url=${{ secrets.SONAR_HOST_URL }} \ + -Dsonar.login=${{ secrets.SONAR_TOKEN }} +``` + +#### Frontend (React) +```yaml +- name: Send results to SonarQube + run: | + sonar-scanner \ + -Dsonar.projectKey=labfusion-frontend \ + -Dsonar.projectName=LabFusion Frontend \ + -Dsonar.host.url=${{ secrets.SONAR_HOST_URL }} \ + -Dsonar.login=${{ secrets.SONAR_TOKEN }} ``` ## Maven Plugins Added @@ -164,27 +190,35 @@ sonar.testExecutionReportPaths=test-results.xml ## Benefits -### 1. Centralized Quality Management -- All quality metrics in one place -- Historical trend analysis -- Cross-project comparisons +### 1. Service Isolation +- Each service has its own quality metrics +- Service-specific quality gates and thresholds +- Independent quality tracking per service +- Clear ownership and responsibility -### 2. Automated Quality Gates -- Pipeline fails if quality standards not met -- Enforces consistent code quality -- Prevents regression in code quality +### 2. Granular Reporting +- Service-specific test coverage reports +- Individual code smell identification +- Per-service security vulnerability detection +- Service-level technical debt tracking -### 3. Detailed Reporting -- Comprehensive test coverage reports -- Code smell identification -- Security vulnerability detection -- Technical debt tracking +### 3. Flexible Quality Gates +- Different quality standards per service type +- Language-specific quality rules +- Service-specific maintenance windows +- Independent quality gate configurations -### 4. Integration Benefits +### 4. Better Organization +- Clear separation of concerns +- Easier to identify problematic services +- Service-specific team assignments +- Independent service evolution + +### 5. Integration Benefits - No external service dependencies - Local data control -- Customizable quality rules -- Team collaboration features +- Customizable quality rules per service +- Team collaboration features per service ## Troubleshooting