1+ #!/usr/bin/env python3
2+ """
3+ Script to post SonarQube static analysis results to GitHub PR as a comment.
4+ """
5+
6+ import argparse
7+ import json
8+ import os
9+ import requests
10+ import sys
11+ from datetime import datetime
12+
13+ def post_pr_comment (github_token , repo_owner , repo_name , pr_number , comment_body ):
14+ """Post a comment to GitHub PR"""
15+ url = f"https://api.github.com/repos/{ repo_owner } /{ repo_name } /issues/{ pr_number } /comments"
16+
17+ headers = {
18+ "Authorization" : f"token { github_token } " ,
19+ "Accept" : "application/vnd.github.v3+json" ,
20+ "Content-Type" : "application/json"
21+ }
22+
23+ payload = {"body" : comment_body }
24+
25+ response = requests .post (url , headers = headers , json = payload )
26+
27+ if response .status_code == 201 :
28+ print (f"✅ Successfully posted SonarQube results to PR #{ pr_number } " )
29+ return True
30+ else :
31+ print (f"❌ Failed to post comment to PR #{ pr_number } " )
32+ print (f"Status: { response .status_code } " )
33+ print (f"Response: { response .text } " )
34+ return False
35+
36+ def post_commit_status (github_token , repo_owner , repo_name , commit_sha , state , description , target_url ):
37+ """Post commit status to GitHub"""
38+ url = f"https://api.github.com/repos/{ repo_owner } /{ repo_name } /statuses/{ commit_sha } "
39+
40+ headers = {
41+ "Authorization" : f"token { github_token } " ,
42+ "Accept" : "application/vnd.github.v3+json" ,
43+ "Content-Type" : "application/json"
44+ }
45+
46+ payload = {
47+ "state" : state ,
48+ "target_url" : target_url ,
49+ "description" : description ,
50+ "context" : "ci/sonarqube-analysis"
51+ }
52+
53+ response = requests .post (url , headers = headers , json = payload )
54+
55+ if response .status_code == 201 :
56+ print (f"✅ Successfully posted commit status for { commit_sha [:8 ]} " )
57+ return True
58+ else :
59+ print (f"❌ Failed to post commit status for { commit_sha [:8 ]} " )
60+ print (f"Status: { response .status_code } " )
61+ print (f"Response: { response .text } " )
62+ return False
63+
64+ def create_comment_body (result , status , commit_sha , branch_name , target_branch , sonar_output ):
65+ """Create formatted comment body for GitHub PR"""
66+
67+ # Determine status emoji and text
68+ if result == "PASS" :
69+ result_emoji = "✅"
70+ result_text = "**PASSED**"
71+ else :
72+ result_emoji = "❌"
73+ result_text = "**FAILED**"
74+
75+ # Truncate output if too long - show last 2000 characters for most relevant info
76+ max_output_length = 2000
77+ if len (sonar_output ) > max_output_length :
78+ truncated_output = "[Output truncated - showing last 2000 characters]\n \n ..." + sonar_output [- max_output_length :]
79+ else :
80+ truncated_output = sonar_output
81+
82+ comment_body = f"""## 🔍 SonarQube Static Analysis Results
83+
84+ **Result:** { result_emoji } { result_text }
85+ **Quality Gate Status:** { status }
86+ **Commit SHA:** `{ commit_sha } `
87+
88+ ### 📊 Analysis Summary
89+ - **Branch:** `{ branch_name } `
90+ - **Target:** `{ target_branch } `
91+ - **Analysis Time:** { datetime .now ().strftime ('%Y-%m-%d %H:%M:%S UTC' )}
92+
93+ ### 📋 Detailed Results
94+ <details>
95+ <summary>Click to view SonarQube output</summary>
96+
97+ ```
98+ { truncated_output }
99+ ```
100+
101+ </details>
102+
103+ ---
104+ *🤖 Automated comment by Jenkins CI*"""
105+
106+ return comment_body
107+
108+ def main ():
109+ parser = argparse .ArgumentParser (description = "Post SonarQube results to GitHub PR" )
110+ parser .add_argument ("--github_token" , required = True , help = "GitHub access token" )
111+ parser .add_argument ("--repo_owner" , default = "SiliconLabsSoftware" , help = "GitHub repository owner" )
112+ parser .add_argument ("--repo_name" , default = "matter_extension" , help = "GitHub repository name" )
113+ parser .add_argument ("--pr_number" , required = True , help = "Pull request number" )
114+ parser .add_argument ("--commit_sha" , required = True , help = "Git commit SHA" )
115+ parser .add_argument ("--result" , required = True , choices = ["PASS" , "FAIL" ], help = "SonarQube analysis result" )
116+ parser .add_argument ("--status" , required = True , help = "SonarQube quality gate status" )
117+
118+ parser .add_argument ("--branch_name" , required = True , help = "Source branch name" )
119+ parser .add_argument ("--target_branch" , required = True , help = "Target branch name" )
120+ parser .add_argument ("--sonar_output" , required = True , help = "SonarQube scanner output" )
121+
122+ args = parser .parse_args ()
123+
124+ try :
125+ # Create comment body
126+ comment_body = create_comment_body (
127+ args .result ,
128+ args .status ,
129+ args .commit_sha ,
130+ args .branch_name ,
131+ args .target_branch ,
132+ args .sonar_output
133+ )
134+
135+ # Post PR comment
136+ comment_success = post_pr_comment (
137+ args .github_token ,
138+ args .repo_owner ,
139+ args .repo_name ,
140+ args .pr_number ,
141+ comment_body
142+ )
143+
144+ # Post PR comment only (skip commit status due to permissions)
145+ if comment_success :
146+ print ("✅ GitHub PR comment posted successfully" )
147+ sys .exit (0 )
148+ else :
149+ print ("❌ Failed to post GitHub PR comment" )
150+ sys .exit (1 )
151+
152+ except Exception as e :
153+ print (f"❌ Error posting to GitHub: { str (e )} " )
154+ sys .exit (1 )
155+
156+ if __name__ == "__main__" :
157+ main ()
0 commit comments