Update SonarQube job to match established pattern
Some checks failed
CI / lint-and-test (push) Failing after 2m25s
CI / secret-scanning (push) Successful in 1m33s
CI / security-scan (push) Successful in 2m13s
CI / dependency-scan (push) Successful in 1m39s
CI / sast-scan (push) Successful in 2m42s
CI / container-scan (push) Successful in 2m14s
CI / sonar-analysis (push) Failing after 2m44s
CI / docker-build-test (push) Failing after 1m40s
CI / workflow-summary (push) Successful in 1m30s
Some checks failed
CI / lint-and-test (push) Failing after 2m25s
CI / secret-scanning (push) Successful in 1m33s
CI / security-scan (push) Successful in 2m13s
CI / dependency-scan (push) Successful in 1m39s
CI / sast-scan (push) Successful in 2m42s
CI / container-scan (push) Successful in 2m14s
CI / sonar-analysis (push) Failing after 2m44s
CI / docker-build-test (push) Failing after 1m40s
CI / workflow-summary (push) Successful in 1m30s
CHANGES: ======== ✅ Added conditional execution - Runs on pull_request or main/dev/qa branches - Matches pattern from other project ✅ Graceful secret handling - Exits 0 if secrets not set (doesn't break CI) - Clear warning message ✅ Non-blocking on failure - Exits 0 on SonarScanner failure (not exit 1) - Prevents CI failures from SonarQube issues - Matches established pattern ✅ Kept coverage report generation - Generates coverage.xml for SonarQube - Uses pytest-cov CONFIGURATION: ============== - Project key: pote - Sources: src/ - Tests: tests/ - Python version: 3.11 - Coverage: coverage.xml This matches the pattern used in other projects while maintaining POTE-specific configuration.
This commit is contained in:
parent
f94ca17b39
commit
6eba94346a
159
.github/workflows/ci.yml
vendored
159
.github/workflows/ci.yml
vendored
@ -231,6 +231,161 @@ jobs:
|
||||
trivy fs --scanners vuln --severity HIGH,CRITICAL --format table . || true
|
||||
continue-on-error: true
|
||||
|
||||
sonar-analysis:
|
||||
if: github.event_name == 'pull_request' || github.ref == 'refs/heads/main' || github.ref == 'refs/heads/dev' || github.ref == 'refs/heads/qa'
|
||||
runs-on: ubuntu-latest
|
||||
container:
|
||||
image: ubuntu:22.04
|
||||
env:
|
||||
SONAR_HOST_URL: ${{ secrets.SONAR_HOST_URL }}
|
||||
SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
|
||||
steps:
|
||||
- name: Install Node.js for checkout action
|
||||
run: |
|
||||
apt-get update && apt-get install -y curl
|
||||
curl -fsSL https://deb.nodesource.com/setup_20.x | bash -
|
||||
apt-get install -y nodejs
|
||||
|
||||
- name: Check out code
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Install Java and SonarScanner
|
||||
run: |
|
||||
set -e
|
||||
apt-get update && apt-get install -y wget curl unzip openjdk-21-jre
|
||||
|
||||
# Use a known working version to avoid download issues
|
||||
SONAR_SCANNER_VERSION="5.0.1.3006"
|
||||
SCANNER_URL="https://binaries.sonarsource.com/Distribution/sonar-scanner-cli/sonar-scanner-cli-${SONAR_SCANNER_VERSION}-linux.zip"
|
||||
|
||||
echo "Installing SonarScanner version: ${SONAR_SCANNER_VERSION}"
|
||||
echo "Downloading from: ${SCANNER_URL}"
|
||||
|
||||
# Download with verbose error output
|
||||
if ! wget --progress=bar:force "${SCANNER_URL}" -O /tmp/sonar-scanner.zip 2>&1; then
|
||||
echo "❌ Failed to download SonarScanner"
|
||||
echo "Checking if file was partially downloaded:"
|
||||
ls -lh /tmp/sonar-scanner.zip 2>/dev/null || echo "No file found"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Verify download
|
||||
if [ ! -f /tmp/sonar-scanner.zip ] || [ ! -s /tmp/sonar-scanner.zip ]; then
|
||||
echo "❌ Downloaded file is missing or empty"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "Download complete. File size: $(du -h /tmp/sonar-scanner.zip | cut -f1)"
|
||||
|
||||
echo "Extracting SonarScanner..."
|
||||
if ! unzip -q /tmp/sonar-scanner.zip -d /tmp; then
|
||||
echo "❌ Failed to extract SonarScanner"
|
||||
echo "Archive info:"
|
||||
file /tmp/sonar-scanner.zip || true
|
||||
unzip -l /tmp/sonar-scanner.zip 2>&1 | head -20 || true
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Find the extracted directory (handle both naming conventions)
|
||||
EXTRACTED_DIR=""
|
||||
if [ -d "/tmp/sonar-scanner-${SONAR_SCANNER_VERSION}-linux" ]; then
|
||||
EXTRACTED_DIR="/tmp/sonar-scanner-${SONAR_SCANNER_VERSION}-linux"
|
||||
elif [ -d "/tmp/sonar-scanner-cli-${SONAR_SCANNER_VERSION}-linux" ]; then
|
||||
EXTRACTED_DIR="/tmp/sonar-scanner-cli-${SONAR_SCANNER_VERSION}-linux"
|
||||
else
|
||||
# Try to find any sonar-scanner directory
|
||||
EXTRACTED_DIR=$(find /tmp -maxdepth 1 -type d -name "*sonar-scanner*" | head -1)
|
||||
fi
|
||||
|
||||
if [ -z "$EXTRACTED_DIR" ] || [ ! -d "$EXTRACTED_DIR" ]; then
|
||||
echo "❌ SonarScanner directory not found after extraction"
|
||||
echo "Contents of /tmp:"
|
||||
ls -la /tmp/ | grep -E "(sonar|zip)" || ls -la /tmp/ | head -20
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "Found extracted directory: ${EXTRACTED_DIR}"
|
||||
mv "${EXTRACTED_DIR}" /opt/sonar-scanner
|
||||
|
||||
# Create symlink
|
||||
if [ -f /opt/sonar-scanner/bin/sonar-scanner ]; then
|
||||
ln -sf /opt/sonar-scanner/bin/sonar-scanner /usr/local/bin/sonar-scanner
|
||||
chmod +x /opt/sonar-scanner/bin/sonar-scanner
|
||||
chmod +x /usr/local/bin/sonar-scanner
|
||||
else
|
||||
echo "❌ sonar-scanner binary not found in /opt/sonar-scanner/bin/"
|
||||
echo "Contents of /opt/sonar-scanner/bin/:"
|
||||
ls -la /opt/sonar-scanner/bin/ || true
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "Verifying installation..."
|
||||
if ! sonar-scanner --version; then
|
||||
echo "❌ SonarScanner verification failed"
|
||||
echo "PATH: $PATH"
|
||||
which sonar-scanner || echo "sonar-scanner not in PATH"
|
||||
exit 1
|
||||
fi
|
||||
echo "✓ SonarScanner installed successfully"
|
||||
|
||||
- name: Verify SonarQube connection
|
||||
run: |
|
||||
echo "Checking SonarQube connectivity..."
|
||||
if [ -z "$SONAR_HOST_URL" ] || [ -z "$SONAR_TOKEN" ]; then
|
||||
echo "⚠️ Skipping SonarQube analysis: SONAR_HOST_URL or SONAR_TOKEN secrets are not set."
|
||||
exit 0
|
||||
fi
|
||||
echo "✓ Secrets are configured"
|
||||
echo "SonarQube URL: ${SONAR_HOST_URL}"
|
||||
echo "Testing connectivity to SonarQube server..."
|
||||
if curl -f -s -o /dev/null -w "%{http_code}" "${SONAR_HOST_URL}/api/system/status" | grep -q "200"; then
|
||||
echo "✓ SonarQube server is reachable"
|
||||
else
|
||||
echo "⚠️ Warning: Could not verify SonarQube server connectivity (continuing anyway)"
|
||||
fi
|
||||
|
||||
- name: Generate coverage report
|
||||
run: |
|
||||
echo "Generating coverage report for SonarQube..."
|
||||
pip install --upgrade pip
|
||||
pip install -e ".[dev]"
|
||||
pytest tests/ --cov=src/pote --cov-report=xml --cov-report=term || true
|
||||
|
||||
- name: Run SonarScanner
|
||||
run: |
|
||||
echo "Starting SonarQube analysis..."
|
||||
if [ -z "$SONAR_HOST_URL" ] || [ -z "$SONAR_TOKEN" ]; then
|
||||
echo "Skipping SonarQube analysis: secrets not set."
|
||||
exit 0
|
||||
fi
|
||||
|
||||
if ! sonar-scanner \
|
||||
-Dsonar.projectKey=pote \
|
||||
-Dsonar.sources=src \
|
||||
-Dsonar.tests=tests \
|
||||
-Dsonar.python.coverage.reportPaths=coverage.xml \
|
||||
-Dsonar.host.url=${SONAR_HOST_URL} \
|
||||
-Dsonar.token=${SONAR_TOKEN} \
|
||||
-Dsonar.scm.disabled=true \
|
||||
-Dsonar.python.version=3.11 \
|
||||
-X; then
|
||||
echo ""
|
||||
echo "❌ SonarScanner analysis failed!"
|
||||
echo ""
|
||||
echo "Common issues:"
|
||||
echo " 1. Project 'pote' doesn't exist in SonarQube"
|
||||
echo " → Create it manually in SonarQube UI"
|
||||
echo " 2. Token doesn't have permission to analyze/create project"
|
||||
echo " → Ensure token has 'Execute Analysis' permission"
|
||||
echo " 3. Token doesn't have 'Create Projects' permission (if project doesn't exist)"
|
||||
echo " → Grant this permission in SonarQube user settings"
|
||||
echo ""
|
||||
echo "Check SonarQube logs for more details."
|
||||
# Do not fail CI on Sonar auth/project setup issues.
|
||||
exit 0
|
||||
fi
|
||||
continue-on-error: true
|
||||
|
||||
docker-build-test:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
@ -255,7 +410,7 @@ jobs:
|
||||
|
||||
workflow-summary:
|
||||
runs-on: ubuntu-latest
|
||||
needs: [lint-and-test, secret-scanning, security-scan, dependency-scan, sast-scan, container-scan, docker-build-test]
|
||||
needs: [lint-and-test, secret-scanning, security-scan, dependency-scan, sast-scan, container-scan, sonar-analysis, docker-build-test]
|
||||
if: always()
|
||||
steps:
|
||||
- name: Generate workflow summary
|
||||
@ -272,6 +427,7 @@ jobs:
|
||||
echo "| 📦 Dependency Scan | ${{ needs.dependency-scan.result }} |" >> $GITHUB_STEP_SUMMARY || true
|
||||
echo "| 🔍 SAST Scan | ${{ needs.sast-scan.result }} |" >> $GITHUB_STEP_SUMMARY || true
|
||||
echo "| 🐳 Container Scan | ${{ needs.container-scan.result }} |" >> $GITHUB_STEP_SUMMARY || true
|
||||
echo "| 🔍 SonarQube Analysis | ${{ needs.sonar-analysis.result }} |" >> $GITHUB_STEP_SUMMARY || true
|
||||
echo "| 🐋 Docker Build | ${{ needs.docker-build-test.result }} |" >> $GITHUB_STEP_SUMMARY || true
|
||||
echo "" >> $GITHUB_STEP_SUMMARY || true
|
||||
echo "### 📊 Summary" >> $GITHUB_STEP_SUMMARY || true
|
||||
@ -284,4 +440,5 @@ jobs:
|
||||
echo "- ✅ Static security analysis (Bandit)" >> $GITHUB_STEP_SUMMARY || true
|
||||
echo "- ✅ SAST scanning (Semgrep)" >> $GITHUB_STEP_SUMMARY || true
|
||||
echo "- ✅ Container scanning (Trivy)" >> $GITHUB_STEP_SUMMARY || true
|
||||
echo "- ✅ Code quality analysis (SonarQube)" >> $GITHUB_STEP_SUMMARY || true
|
||||
continue-on-error: true
|
||||
|
||||
128
SONARQUBE_QUICKSTART.md
Normal file
128
SONARQUBE_QUICKSTART.md
Normal file
@ -0,0 +1,128 @@
|
||||
# SonarQube Quick Start
|
||||
|
||||
**5-minute setup guide for SonarQube code quality analysis.**
|
||||
|
||||
---
|
||||
|
||||
## ✅ What's Already Done
|
||||
|
||||
- ✅ `sonar-project.properties` - Project configuration
|
||||
- ✅ CI pipeline job - `sonar-analysis` added
|
||||
- ✅ Coverage report generation - Integrated with pytest
|
||||
|
||||
---
|
||||
|
||||
## 🚀 Quick Setup (3 Steps)
|
||||
|
||||
### Step 1: Create Project in SonarQube
|
||||
|
||||
1. Login to SonarQube: `http://your-server:9000`
|
||||
2. **Projects** → **Create Project**
|
||||
3. **Project Key:** `pote`
|
||||
4. **Display Name:** `POTE`
|
||||
5. Click **Set Up**
|
||||
|
||||
### Step 2: Generate Token
|
||||
|
||||
1. **My Account** → **Security** → **Generate Token**
|
||||
2. **Name:** `POTE CI/CD`
|
||||
3. **Type:** User Token
|
||||
4. Click **Generate**
|
||||
5. **⚠️ COPY THE TOKEN** (you won't see it again!)
|
||||
|
||||
### Step 3: Add Secrets to Gitea
|
||||
|
||||
1. Go to: `https://git.levkin.ca/ilia/POTE/settings/secrets/actions`
|
||||
2. Add secret: `SONAR_HOST_URL` = `http://your-server:9000`
|
||||
3. Add secret: `SONAR_TOKEN` = (paste token from Step 2)
|
||||
|
||||
---
|
||||
|
||||
## 🧪 Test It
|
||||
|
||||
```bash
|
||||
# Push to dev branch
|
||||
git push origin dev
|
||||
|
||||
# Check CI results
|
||||
# https://git.levkin.ca/ilia/POTE/actions
|
||||
|
||||
# View SonarQube results
|
||||
# http://your-server:9000/dashboard?id=pote
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 📋 Configuration
|
||||
|
||||
### Project Key
|
||||
- **Key:** `pote` (in `sonar-project.properties`)
|
||||
- **Name:** `POTE`
|
||||
- **Version:** `0.1.0`
|
||||
|
||||
### Source Code
|
||||
- **Sources:** `src/`
|
||||
- **Tests:** `tests/`
|
||||
- **Coverage:** `coverage.xml` (auto-generated)
|
||||
|
||||
### Exclusions
|
||||
- `__pycache__/`, `*.pyc`
|
||||
- `venv/`, `tests/`
|
||||
- `alembic/versions/`
|
||||
|
||||
---
|
||||
|
||||
## 🔧 Customize
|
||||
|
||||
Edit `sonar-project.properties`:
|
||||
```properties
|
||||
sonar.projectKey=pote
|
||||
sonar.projectName=POTE
|
||||
sonar.sources=src
|
||||
sonar.tests=tests
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 📊 View Results
|
||||
|
||||
**SonarQube Dashboard:**
|
||||
```
|
||||
http://your-server:9000/dashboard?id=pote
|
||||
```
|
||||
|
||||
**Metrics:**
|
||||
- Code Coverage
|
||||
- Bugs & Vulnerabilities
|
||||
- Code Smells
|
||||
- Technical Debt
|
||||
- Quality Gate Status
|
||||
|
||||
---
|
||||
|
||||
## 🐛 Troubleshooting
|
||||
|
||||
### "Project does not exist"
|
||||
→ Create project manually in SonarQube UI
|
||||
|
||||
### "Authentication failed"
|
||||
→ Check `SONAR_TOKEN` secret is correct
|
||||
|
||||
### "Connection refused"
|
||||
→ Verify `SONAR_HOST_URL` and server accessibility
|
||||
|
||||
### "Coverage not found"
|
||||
→ Ensure pytest runs before SonarScanner (already configured)
|
||||
|
||||
---
|
||||
|
||||
## 📖 Full Documentation
|
||||
|
||||
See: `docs/17_sonarqube_setup.md` for complete guide.
|
||||
|
||||
---
|
||||
|
||||
**Setup Time:** ~5 minutes
|
||||
**CI Integration:** ✅ Already done
|
||||
**Manual Steps:** 3 (create project, generate token, add secrets)
|
||||
|
||||
414
docs/17_sonarqube_setup.md
Normal file
414
docs/17_sonarqube_setup.md
Normal file
@ -0,0 +1,414 @@
|
||||
# SonarQube Setup Guide for POTE
|
||||
|
||||
**Complete guide for setting up SonarQube code quality analysis.**
|
||||
|
||||
---
|
||||
|
||||
## 🎯 Overview
|
||||
|
||||
SonarQube provides:
|
||||
- **Code Quality Metrics** - Maintainability, reliability, security
|
||||
- **Technical Debt** - Time to fix issues
|
||||
- **Code Coverage** - Test coverage visualization
|
||||
- **Code Smells** - Code quality issues
|
||||
- **Security Vulnerabilities** - Security hotspots
|
||||
- **Bug Detection** - Potential bugs
|
||||
|
||||
---
|
||||
|
||||
## 📋 Prerequisites
|
||||
|
||||
### 1. SonarQube Server
|
||||
- ✅ You mentioned you have the runner (SonarQube server)
|
||||
- Server URL: `http://your-sonarqube-server:9000` (or your URL)
|
||||
- Server must be accessible from CI/CD runners
|
||||
|
||||
### 2. SonarQube Project
|
||||
- Project key: `pote` (configured in `sonar-project.properties`)
|
||||
- Project name: `POTE`
|
||||
- Can be created manually or auto-created on first scan
|
||||
|
||||
### 3. SonarQube Token
|
||||
- User token with permissions:
|
||||
- ✅ **Execute Analysis** (required)
|
||||
- ✅ **Create Projects** (if project doesn't exist)
|
||||
|
||||
---
|
||||
|
||||
## 🔧 Step 1: Create SonarQube Project
|
||||
|
||||
### Option A: Create Manually (Recommended)
|
||||
|
||||
1. **Login to SonarQube:**
|
||||
```
|
||||
http://your-sonarqube-server:9000
|
||||
```
|
||||
|
||||
2. **Create Project:**
|
||||
- Go to: **Projects** → **Create Project**
|
||||
- **Project Key:** `pote`
|
||||
- **Display Name:** `POTE`
|
||||
- **Main Branch:** `main`
|
||||
- Click **Set Up**
|
||||
|
||||
3. **Generate Token:**
|
||||
- Go to: **My Account** → **Security** → **Generate Token**
|
||||
- **Name:** `POTE CI/CD`
|
||||
- **Type:** **User Token**
|
||||
- **Expires:** (set expiration or leave blank)
|
||||
- Click **Generate**
|
||||
- **⚠️ COPY THE TOKEN** - You won't see it again!
|
||||
|
||||
### Option B: Auto-Create (First Scan)
|
||||
|
||||
- Project will be created automatically on first scan
|
||||
- Token must have **"Create Projects"** permission
|
||||
|
||||
---
|
||||
|
||||
## 🔐 Step 2: Configure Gitea Secrets
|
||||
|
||||
### Add Secrets in Gitea
|
||||
|
||||
1. **Go to Repository Settings:**
|
||||
```
|
||||
https://git.levkin.ca/ilia/POTE/settings/secrets/actions
|
||||
```
|
||||
|
||||
2. **Add Secret: `SONAR_HOST_URL`**
|
||||
- **Name:** `SONAR_HOST_URL`
|
||||
- **Value:** `http://your-sonarqube-server:9000`
|
||||
- Example: `http://10.0.30.169:9000`
|
||||
- Click **Add Secret**
|
||||
|
||||
3. **Add Secret: `SONAR_TOKEN`**
|
||||
- **Name:** `SONAR_TOKEN`
|
||||
- **Value:** (paste the token from Step 1)
|
||||
- Click **Add Secret**
|
||||
|
||||
### Verify Secrets
|
||||
|
||||
```bash
|
||||
# In CI pipeline, secrets are available as:
|
||||
${{ secrets.SONAR_HOST_URL }}
|
||||
${{ secrets.SONAR_TOKEN }}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 📄 Step 3: Project Configuration
|
||||
|
||||
### File: `sonar-project.properties`
|
||||
|
||||
Already created in project root with these settings:
|
||||
|
||||
```properties
|
||||
# Project identification
|
||||
sonar.projectKey=pote
|
||||
sonar.projectName=POTE
|
||||
sonar.projectVersion=0.1.0
|
||||
|
||||
# Source code location
|
||||
sonar.sources=src
|
||||
sonar.sourceEncoding=UTF-8
|
||||
|
||||
# Test code location
|
||||
sonar.tests=tests
|
||||
sonar.test.inclusions=**/test_*.py
|
||||
|
||||
# Exclusions
|
||||
sonar.exclusions=**/__pycache__/**,**/*.pyc,**/venv/**,**/tests/**,**/alembic/versions/**
|
||||
|
||||
# Python-specific settings
|
||||
sonar.python.version=3.11
|
||||
|
||||
# Coverage reports
|
||||
sonar.python.coverage.reportPaths=coverage.xml
|
||||
```
|
||||
|
||||
### Customize if Needed
|
||||
|
||||
Edit `sonar-project.properties` to:
|
||||
- Change project key/name
|
||||
- Add more exclusions
|
||||
- Configure additional settings
|
||||
|
||||
---
|
||||
|
||||
## 🚀 Step 4: CI Pipeline Integration
|
||||
|
||||
### Already Configured!
|
||||
|
||||
The CI pipeline (`.github/workflows/ci.yml`) includes:
|
||||
|
||||
1. **SonarScanner Installation**
|
||||
- Downloads and installs SonarScanner CLI
|
||||
- Version: `5.0.1.3006` (stable)
|
||||
|
||||
2. **Coverage Report Generation**
|
||||
- Runs pytest with coverage
|
||||
- Generates `coverage.xml` for SonarQube
|
||||
|
||||
3. **SonarScanner Execution**
|
||||
- Runs analysis
|
||||
- Uploads results to SonarQube server
|
||||
- Non-blocking (won't fail CI if SonarQube is unavailable)
|
||||
|
||||
### Job: `sonar-analysis`
|
||||
|
||||
```yaml
|
||||
sonar-analysis:
|
||||
runs-on: ubuntu-latest
|
||||
env:
|
||||
SONAR_HOST_URL: ${{ secrets.SONAR_HOST_URL }}
|
||||
SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
|
||||
steps:
|
||||
- Install SonarScanner
|
||||
- Generate coverage report
|
||||
- Run SonarScanner analysis
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🧪 Step 5: Test Locally (Optional)
|
||||
|
||||
### Install SonarScanner Locally
|
||||
|
||||
```bash
|
||||
# Download SonarScanner
|
||||
wget https://binaries.sonarsource.com/Distribution/sonar-scanner-cli/sonar-scanner-cli-5.0.1.3006-linux.zip
|
||||
unzip sonar-scanner-cli-5.0.1.3006-linux.zip
|
||||
export PATH=$PATH:$(pwd)/sonar-scanner-5.0.1.3006-linux/bin
|
||||
```
|
||||
|
||||
### Run Analysis Locally
|
||||
|
||||
```bash
|
||||
cd /home/user/Documents/code/pote
|
||||
|
||||
# Generate coverage report
|
||||
source venv/bin/activate
|
||||
pytest tests/ --cov=src/pote --cov-report=xml
|
||||
|
||||
# Run SonarScanner
|
||||
sonar-scanner \
|
||||
-Dsonar.host.url=http://your-sonarqube-server:9000 \
|
||||
-Dsonar.token=your_token_here
|
||||
```
|
||||
|
||||
### Or Use Environment Variables
|
||||
|
||||
```bash
|
||||
export SONAR_HOST_URL=http://your-sonarqube-server:9000
|
||||
export SONAR_TOKEN=your_token_here
|
||||
sonar-scanner
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 📊 Step 6: View Results
|
||||
|
||||
### In SonarQube UI
|
||||
|
||||
1. **Go to Project:**
|
||||
```
|
||||
http://your-sonarqube-server:9000/dashboard?id=pote
|
||||
```
|
||||
|
||||
2. **View Metrics:**
|
||||
- **Overview** - Overall quality gate status
|
||||
- **Issues** - Bugs, vulnerabilities, code smells
|
||||
- **Measures** - Coverage, complexity, duplications
|
||||
- **Code** - Source code with inline issues
|
||||
- **Activity** - Analysis history
|
||||
|
||||
### Quality Gate
|
||||
|
||||
SonarQube will show:
|
||||
- ✅ **Pass** - Meets quality standards
|
||||
- ❌ **Fail** - Doesn't meet quality standards
|
||||
|
||||
### Common Metrics
|
||||
|
||||
- **Coverage** - Test coverage percentage
|
||||
- **Duplications** - Code duplication percentage
|
||||
- **Maintainability Rating** - A-E rating
|
||||
- **Reliability Rating** - A-E rating
|
||||
- **Security Rating** - A-E rating
|
||||
- **Technical Debt** - Time to fix all issues
|
||||
|
||||
---
|
||||
|
||||
## 🔧 Configuration Options
|
||||
|
||||
### Quality Gate
|
||||
|
||||
Configure in SonarQube:
|
||||
- **Projects** → **POTE** → **Quality Gates**
|
||||
- Set thresholds for:
|
||||
- Coverage
|
||||
- Duplications
|
||||
- Bugs
|
||||
- Vulnerabilities
|
||||
- Code smells
|
||||
|
||||
### Exclusions
|
||||
|
||||
Add to `sonar-project.properties`:
|
||||
|
||||
```properties
|
||||
# Exclude specific files
|
||||
sonar.exclusions=**/legacy/**,**/old_code/**
|
||||
|
||||
# Exclude specific issues
|
||||
sonar.issue.ignore.multicriteria=e1
|
||||
sonar.issue.ignore.multicriteria.e1.ruleKey=python:S1234
|
||||
sonar.issue.ignore.multicriteria.e1.resourceKey=**/*.py
|
||||
```
|
||||
|
||||
### Coverage Exclusions
|
||||
|
||||
```properties
|
||||
# Exclude from coverage
|
||||
sonar.coverage.exclusions=**/tests/**,**/migrations/**,**/__init__.py
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🐛 Troubleshooting
|
||||
|
||||
### Issue: "Project 'pote' does not exist"
|
||||
|
||||
**Solution:**
|
||||
1. Create project manually in SonarQube UI
|
||||
2. OR ensure token has "Create Projects" permission
|
||||
|
||||
### Issue: "Authentication failed"
|
||||
|
||||
**Solution:**
|
||||
1. Verify `SONAR_TOKEN` secret is correct
|
||||
2. Check token hasn't expired
|
||||
3. Regenerate token if needed
|
||||
|
||||
### Issue: "Connection refused"
|
||||
|
||||
**Solution:**
|
||||
1. Verify `SONAR_HOST_URL` is correct
|
||||
2. Check SonarQube server is running
|
||||
3. Verify network connectivity from CI runner
|
||||
4. Check firewall rules
|
||||
|
||||
### Issue: "Coverage report not found"
|
||||
|
||||
**Solution:**
|
||||
1. Ensure pytest runs before SonarScanner
|
||||
2. Check `coverage.xml` is generated
|
||||
3. Verify path in `sonar-project.properties`:
|
||||
```properties
|
||||
sonar.python.coverage.reportPaths=coverage.xml
|
||||
```
|
||||
|
||||
### Issue: "No files to analyze"
|
||||
|
||||
**Solution:**
|
||||
1. Check `sonar.sources=src` is correct
|
||||
2. Verify source files aren't excluded
|
||||
3. Check file encoding (should be UTF-8)
|
||||
|
||||
---
|
||||
|
||||
## 📈 Best Practices
|
||||
|
||||
### 1. Regular Analysis
|
||||
- Run on every commit (already configured in CI)
|
||||
- Review results regularly
|
||||
- Fix issues incrementally
|
||||
|
||||
### 2. Quality Gate
|
||||
- Set realistic thresholds
|
||||
- Start with warnings, not failures
|
||||
- Gradually increase standards
|
||||
|
||||
### 3. Coverage
|
||||
- Aim for 80%+ coverage
|
||||
- Focus on critical paths first
|
||||
- Don't sacrifice quality for coverage
|
||||
|
||||
### 4. Technical Debt
|
||||
- Track and reduce over time
|
||||
- Prioritize high-impact issues
|
||||
- Set time limits for fixing
|
||||
|
||||
### 5. Team Integration
|
||||
- Share SonarQube dashboard with team
|
||||
- Review issues in code reviews
|
||||
- Use quality gate in PR checks
|
||||
|
||||
---
|
||||
|
||||
## 🔗 Integration with CI/CD
|
||||
|
||||
### Current Setup
|
||||
|
||||
✅ **Already Integrated:**
|
||||
- Runs automatically on every push
|
||||
- Non-blocking (won't fail CI)
|
||||
- Generates coverage report
|
||||
- Uploads results to SonarQube
|
||||
|
||||
### Make Quality Gate Blocking (Optional)
|
||||
|
||||
To fail CI if quality gate fails:
|
||||
|
||||
```yaml
|
||||
- name: Run SonarScanner
|
||||
run: |
|
||||
sonar-scanner \
|
||||
-Dsonar.qualitygate.wait=true \
|
||||
...
|
||||
```
|
||||
|
||||
Then remove `continue-on-error: true` from the step.
|
||||
|
||||
---
|
||||
|
||||
## 📝 Summary
|
||||
|
||||
### Quick Setup Checklist
|
||||
|
||||
- [ ] SonarQube server running and accessible
|
||||
- [ ] Project `pote` created in SonarQube (or auto-create enabled)
|
||||
- [ ] Token generated with "Execute Analysis" permission
|
||||
- [ ] `SONAR_HOST_URL` secret added to Gitea
|
||||
- [ ] `SONAR_TOKEN` secret added to Gitea
|
||||
- [ ] `sonar-project.properties` file exists (✅ already created)
|
||||
- [ ] CI pipeline includes `sonar-analysis` job (✅ already added)
|
||||
- [ ] Test by pushing to dev branch
|
||||
|
||||
### Files Created
|
||||
|
||||
- ✅ `sonar-project.properties` - Project configuration
|
||||
- ✅ `.github/workflows/ci.yml` - Updated with SonarScanner job
|
||||
|
||||
### Next Steps
|
||||
|
||||
1. **Add secrets to Gitea** (Step 2)
|
||||
2. **Push to dev branch** - CI will run SonarScanner
|
||||
3. **View results** in SonarQube dashboard
|
||||
4. **Configure quality gate** as needed
|
||||
5. **Review and fix issues** incrementally
|
||||
|
||||
---
|
||||
|
||||
## 📞 Support
|
||||
|
||||
- **SonarQube Docs:** https://docs.sonarqube.org/
|
||||
- **SonarScanner Docs:** https://docs.sonarqube.org/latest/analysis/scan/sonarscanner/
|
||||
- **Python Plugin:** https://docs.sonarqube.org/latest/analysis/languages/python/
|
||||
|
||||
---
|
||||
|
||||
**Last Updated:** December 2025
|
||||
**SonarScanner Version:** 5.0.1.3006
|
||||
**Python Version:** 3.11
|
||||
|
||||
40
sonar-project.properties
Normal file
40
sonar-project.properties
Normal file
@ -0,0 +1,40 @@
|
||||
# SonarQube Project Configuration for POTE
|
||||
# ===========================================
|
||||
|
||||
# Project identification
|
||||
sonar.projectKey=pote
|
||||
sonar.projectName=POTE
|
||||
sonar.projectVersion=0.1.0
|
||||
|
||||
# Source code location
|
||||
sonar.sources=src
|
||||
sonar.sourceEncoding=UTF-8
|
||||
|
||||
# Test code location
|
||||
sonar.tests=tests
|
||||
sonar.test.inclusions=**/test_*.py
|
||||
|
||||
# Exclusions
|
||||
sonar.exclusions=**/__pycache__/**,**/*.pyc,**/venv/**,**/tests/**,**/alembic/versions/**,**/*.egg-info/**,**/pote.egg-info/**
|
||||
|
||||
# Python-specific settings
|
||||
sonar.python.version=3.11
|
||||
|
||||
# Coverage reports (generated by pytest-cov)
|
||||
sonar.python.coverage.reportPaths=coverage.xml
|
||||
|
||||
# Code analysis
|
||||
sonar.python.xunit.reportPath=test-results.xml
|
||||
|
||||
# Language
|
||||
sonar.language=py
|
||||
|
||||
# Encoding
|
||||
sonar.sourceEncoding=UTF-8
|
||||
|
||||
# SCM (optional - if you want to track blame)
|
||||
# sonar.scm.provider=git
|
||||
|
||||
# Quality Gate
|
||||
# sonar.qualitygate.wait=true
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user