Skip to content

Commit 8ff3bf4

Browse files
Add more details
1 parent 7e01dc0 commit 8ff3bf4

File tree

2 files changed

+140
-4
lines changed

2 files changed

+140
-4
lines changed

jenkins_integration/github/send_sonar_results_to_github.py

Lines changed: 128 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
import os
99
import requests
1010
import sys
11+
import re
1112
from datetime import datetime
1213

1314
def post_pr_comment(github_token, repo_owner, repo_name, pr_number, comment_body):
@@ -61,7 +62,100 @@ def post_commit_status(github_token, repo_owner, repo_name, commit_sha, state, d
6162
print(f"Response: {response.text}")
6263
return False
6364

64-
def create_comment_body(result, status, commit_sha, branch_name, target_branch, sonar_output):
65+
def fetch_sonar_metrics(sonar_host, sonar_token, project_key, pr_number=None):
66+
"""Fetch SonarQube metrics from SonarQube server API"""
67+
metrics = {
68+
'duplicated_lines': 'N/A',
69+
'new_violations': 'N/A',
70+
'new_code_smells': 'N/A',
71+
'new_maintainability_rating': 'N/A',
72+
'quality_gate_details': 'N/A',
73+
'new_bugs': 'N/A',
74+
'reliability_rating': 'N/A',
75+
'new_vulnerabilities': 'N/A',
76+
'new_security_rating': 'N/A',
77+
'new_security_hotspots': 'N/A',
78+
'ncloc': 'N/A'
79+
}
80+
81+
try:
82+
# Prepare headers for SonarQube API
83+
headers = {
84+
'Authorization': f'Bearer {sonar_token}',
85+
'Accept': 'application/json'
86+
}
87+
88+
# Determine component key - use pullRequest key if it's a PR analysis
89+
component_key = project_key
90+
if pr_number:
91+
component_key = f"{project_key}/pull/{pr_number}"
92+
93+
# Define metrics to fetch from SonarQube API
94+
metric_keys = [
95+
'duplicated_lines',
96+
'new_violations',
97+
'new_code_smells',
98+
'new_maintainability_rating',
99+
'new_bugs',
100+
'reliability_rating',
101+
'new_vulnerabilities',
102+
'new_security_rating',
103+
'new_security_hotspots',
104+
'ncloc'
105+
]
106+
107+
# Fetch metrics from SonarQube API
108+
metrics_url = f"{sonar_host}/api/measures/component"
109+
params = {
110+
'component': component_key,
111+
'metricKeys': ','.join(metric_keys)
112+
}
113+
114+
print(f"🔍 Fetching metrics from SonarQube: {metrics_url}")
115+
print(f"📊 Component: {component_key}")
116+
117+
response = requests.get(metrics_url, headers=headers, params=params, timeout=30)
118+
119+
if response.status_code == 200:
120+
data = response.json()
121+
122+
if 'component' in data and 'measures' in data['component']:
123+
for measure in data['component']['measures']:
124+
metric_key = measure.get('metric')
125+
value = measure.get('value', 'N/A')
126+
127+
if metric_key in metrics:
128+
metrics[metric_key] = value
129+
print(f"📈 {metric_key}: {value}")
130+
else:
131+
print("⚠️ No measures found in SonarQube response")
132+
else:
133+
print(f"❌ Failed to fetch metrics from SonarQube: {response.status_code}")
134+
print(f"Response: {response.text}")
135+
136+
# Fetch quality gate status separately
137+
try:
138+
qg_url = f"{sonar_host}/api/qualitygates/project_status"
139+
qg_params = {'projectKey': component_key}
140+
141+
qg_response = requests.get(qg_url, headers=headers, params=qg_params, timeout=30)
142+
143+
if qg_response.status_code == 200:
144+
qg_data = qg_response.json()
145+
if 'projectStatus' in qg_data:
146+
metrics['quality_gate_details'] = qg_data['projectStatus'].get('status', 'N/A')
147+
print(f"🚦 Quality Gate: {metrics['quality_gate_details']}")
148+
else:
149+
print(f"⚠️ Could not fetch quality gate status: {qg_response.status_code}")
150+
except Exception as qg_ex:
151+
print(f"⚠️ Error fetching quality gate: {str(qg_ex)}")
152+
153+
except Exception as e:
154+
print(f"❌ Error fetching SonarQube metrics: {str(e)}")
155+
156+
return metrics
157+
158+
def create_comment_body(result, status, commit_sha, branch_name, target_branch, sonar_output, metrics):
65159
"""Create formatted comment body for GitHub PR"""
66160

67161
# Determine status emoji and text
@@ -90,7 +184,26 @@ def create_comment_body(result, status, commit_sha, branch_name, target_branch,
90184
- **Target:** `{target_branch}`
91185
- **Analysis Time:** {datetime.now().strftime('%Y-%m-%d %H:%M:%S UTC')}
92186
93-
### 📋 Detailed Results
187+
### � Key Metrics
188+
| Metric | Value |
189+
|--------|-------|
190+
| **Lines of Code (NCLOC)** | {metrics['ncloc']} |
191+
| **Duplicated Lines** | {metrics['duplicated_lines']} |
192+
| **New Violations** | {metrics['new_violations']} |
193+
| **New Code Smells** | {metrics['new_code_smells']} |
194+
| **New Bugs** | {metrics['new_bugs']} |
195+
| **New Vulnerabilities** | {metrics['new_vulnerabilities']} |
196+
| **New Security Hotspots** | {metrics['new_security_hotspots']} |
197+
198+
### 🏆 Quality Ratings
199+
| Category | Rating |
200+
|----------|--------|
201+
| **New Maintainability Rating** | {metrics['new_maintainability_rating']} |
202+
| **Reliability Rating** | {metrics['reliability_rating']} |
203+
| **New Security Rating** | {metrics['new_security_rating']} |
204+
| **Quality Gate Details** | {metrics['quality_gate_details']} |
205+
206+
### �📋 Detailed Results
94207
<details>
95208
<summary>Click to view SonarQube output</summary>
96209
@@ -118,6 +231,9 @@ def main():
118231
parser.add_argument("--branch_name", required=True, help="Source branch name")
119232
parser.add_argument("--target_branch", required=True, help="Target branch name")
120233
parser.add_argument("--sonar_output_file", required=True, help="Path to file containing SonarQube scanner output")
234+
parser.add_argument("--sonar_host", required=True, help="SonarQube server host URL")
235+
parser.add_argument("--sonar_token", required=True, help="SonarQube authentication token")
236+
parser.add_argument("--sonar_project_key", default="matter_sdk", help="SonarQube project key")
121237

122238
args = parser.parse_args()
123239

@@ -133,14 +249,23 @@ def main():
133249
print(f"❌ Error reading SonarQube output file: {str(e)}")
134250
sys.exit(1)
135251

252+
# Fetch SonarQube metrics from SonarQube server
253+
metrics = fetch_sonar_metrics(
254+
args.sonar_host,
255+
args.sonar_token,
256+
args.sonar_project_key,
257+
args.pr_number
258+
)
259+
136260
# Create comment body
137261
comment_body = create_comment_body(
138262
args.result,
139263
args.status,
140264
args.commit_sha,
141265
args.branch_name,
142266
args.target_branch,
143-
sonar_output
267+
sonar_output,
268+
metrics
144269
)
145270

146271
# Post PR comment

jenkins_integration/jenkinsFunctions.groovy

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,14 @@ def send_sonar_results_to_github(commit_sha, result, status, sonar_output, pr_nu
1010
writeFile file: tempFile, text: sonar_output
1111

1212
try {
13+
// Get SonarQube server URL with fallbacks
14+
def sonarHost = env.SONAR_HOST_URL ?: env.SONAR_SERVER_URL ?: "https://sonarqube.silabs.net"
15+
16+
echo "Using SonarQube host: ${sonarHost}"
17+
echo "Available SonarQube environment variables:"
18+
echo "SONAR_HOST_URL: ${env.SONAR_HOST_URL}"
19+
echo "SONAR_SERVER_URL: ${env.SONAR_SERVER_URL}"
20+
1321
sh """
1422
python3 -u jenkins_integration/github/send_sonar_results_to_github.py \\
1523
--github_token \${GITHUB_ACCESS_TOKEN} \\
@@ -21,7 +29,10 @@ def send_sonar_results_to_github(commit_sha, result, status, sonar_output, pr_nu
2129
--status ${status} \\
2230
--branch_name "${branch_name}" \\
2331
--target_branch "${target_branch}" \\
24-
--sonar_output_file "${tempFile}"
32+
--sonar_output_file "${tempFile}" \\
33+
--sonar_host "${sonarHost}" \\
34+
--sonar_token "\${SONAR_SECRET}" \\
35+
--sonar_project_key "github_matter_sdk"
2536
"""
2637
} finally {
2738
// Clean up temporary file

0 commit comments

Comments
 (0)