2525"""
2626import sys
2727import json
28+ import csv
29+ from typing import TextIO
30+ from threading import Thread , Lock
31+ from queue import Queue
2832
2933from cli import options
3034
31- from sonar .util .types import ConfigSettings
3235from sonar import errcodes , exceptions
3336from sonar .util import types
3437import sonar .logging as log
4750 options .WHAT_PORTFOLIOS ,
4851]
4952
53+ _WRITE_LOCK = Lock ()
54+
5055
5156def _audit_sif (sysinfo , audit_settings ):
5257 log .info ("Auditing SIF file '%s'" , sysinfo )
@@ -67,40 +72,86 @@ def _audit_sif(sysinfo, audit_settings):
6772 return (server_id , sif_obj .audit (audit_settings ))
6873
6974
75+ def write_problems (queue : Queue [list [problem .Problem ]], fd : TextIO , settings : types .ConfigSettings ) -> None :
76+ """
77+ Thread to write problems in a CSV file
78+ """
79+ csvwriter = csv .writer (fd , delimiter = settings .get ("CSV_DELIMITER" , "," ))
80+ server_id = settings .get ("SERVER_ID" , None )
81+ with_url = settings .get ("WITH_URL" , False )
82+ while True :
83+ problems = queue .get ()
84+ if problems is None :
85+ queue .task_done ()
86+ break
87+ for p in problems :
88+ data = []
89+ if server_id is not None :
90+ data = [server_id ]
91+ data += list (p .to_json (with_url ).values ())
92+ csvwriter .writerow (data )
93+ queue .task_done ()
94+ log .info ("Writing audit probelms complete" )
95+
96+
7097def _audit_sq (
71- sq : platform .Platform , settings : ConfigSettings , what_to_audit : list [str ] = None , key_list : types .KeyList = None
98+ sq : platform .Platform , settings : types . ConfigSettings , what_to_audit : list [str ] = None , key_list : types .KeyList = None
7299) -> list [problem .Problem ]:
73100 """Audits a SonarQube/Cloud platform"""
74101 problems = []
102+ q = Queue (maxsize = 0 )
75103 everything = False
76104 if not what_to_audit :
77105 everything = True
78106 what_to_audit = options .WHAT_AUDITABLE
79- if options .WHAT_PROJECTS in what_to_audit :
80- problems += projects .audit (endpoint = sq , audit_settings = settings , key_list = key_list )
81- if options .WHAT_PROFILES in what_to_audit :
82- problems += qualityprofiles .audit (endpoint = sq , audit_settings = settings )
83- if options .WHAT_GATES in what_to_audit :
84- problems += qualitygates .audit (endpoint = sq , audit_settings = settings )
85- if options .WHAT_SETTINGS in what_to_audit :
86- problems += sq .audit (audit_settings = settings )
87- if options .WHAT_USERS in what_to_audit :
88- problems += users .audit (endpoint = sq , audit_settings = settings )
89- if options .WHAT_GROUPS in what_to_audit :
90- problems += groups .audit (endpoint = sq , audit_settings = settings )
91- if options .WHAT_PORTFOLIOS in what_to_audit :
92- try :
93- problems += portfolios .audit (endpoint = sq , audit_settings = settings , key_list = key_list )
94- except exceptions .UnsupportedOperation :
95- if not everything :
96- log .warning ("No portfolios in %s edition, audit of portfolios ignored" , sq .edition ())
97- if options .WHAT_APPS in what_to_audit :
98- try :
99- problems += applications .audit (endpoint = sq , audit_settings = settings , key_list = key_list )
100- except exceptions .UnsupportedOperation :
101- if not everything :
102- log .warning ("No applications in %s edition, audit of portfolios ignored" , sq .edition ())
103107
108+ with util .open_file (settings .get ("FILE" , None ), mode = "w" ) as fd :
109+ worker = Thread (target = write_problems , args = (q , fd , settings ))
110+ worker .daemon = True
111+ worker .name = "WriteProblems"
112+ worker .start ()
113+ if options .WHAT_PROJECTS in what_to_audit :
114+ pbs = projects .audit (endpoint = sq , audit_settings = settings , key_list = key_list , write_q = q )
115+ q .put (pbs )
116+ problems += pbs
117+ if options .WHAT_PROFILES in what_to_audit :
118+ pbs = qualityprofiles .audit (endpoint = sq , audit_settings = settings )
119+ q .put (pbs )
120+ problems += pbs
121+ if options .WHAT_GATES in what_to_audit :
122+ pbs = qualitygates .audit (endpoint = sq , audit_settings = settings )
123+ q .put (pbs )
124+ problems += pbs
125+ if options .WHAT_SETTINGS in what_to_audit :
126+ pbs = sq .audit (audit_settings = settings )
127+ q .put (pbs )
128+ problems += pbs
129+ if options .WHAT_USERS in what_to_audit :
130+ pbs = users .audit (endpoint = sq , audit_settings = settings )
131+ q .put (pbs )
132+ problems += pbs
133+ if options .WHAT_GROUPS in what_to_audit :
134+ pbs = groups .audit (endpoint = sq , audit_settings = settings )
135+ q .put (pbs )
136+ problems += pbs
137+ if options .WHAT_PORTFOLIOS in what_to_audit :
138+ try :
139+ pbs = portfolios .audit (endpoint = sq , audit_settings = settings , key_list = key_list )
140+ q .put (pbs )
141+ problems += pbs
142+ except exceptions .UnsupportedOperation :
143+ if not everything :
144+ log .warning ("No portfolios in %s edition, audit of portfolios ignored" , sq .edition ())
145+ if options .WHAT_APPS in what_to_audit :
146+ try :
147+ pbs = applications .audit (endpoint = sq , audit_settings = settings , key_list = key_list )
148+ q .put (pbs )
149+ problems += pbs
150+ except exceptions .UnsupportedOperation :
151+ if not everything :
152+ log .warning ("No applications in %s edition, audit of portfolios ignored" , sq .edition ())
153+ q .put (None )
154+ q .join ()
104155 return problems
105156
106157
@@ -138,16 +189,22 @@ def main():
138189 config .configure ()
139190 sys .exit (0 )
140191
192+ ofile = kwargs .pop (options .REPORT_FILE )
193+ settings ["FILE" ] = ofile
194+ settings ["CSV_DELIMITER" ] = kwargs [options .CSV_SEPARATOR ]
195+ settings ["WITH_URL" ] = kwargs [options .WITH_URL ]
196+
141197 if kwargs .get ("sif" , None ) is not None :
142198 err = errcodes .SIF_AUDIT_ERROR
143199 try :
144200 (server_id , problems ) = _audit_sif (kwargs ["sif" ], settings )
201+ settings ["SERVER_ID" ] = server_id
145202 except json .decoder .JSONDecodeError :
146203 util .exit_fatal (f"File { kwargs ['sif' ]} does not seem to be a legit JSON file, aborting..." , err )
147204 except FileNotFoundError :
148205 util .exit_fatal (f"File { kwargs ['sif' ]} does not exist, aborting..." , err )
149206 except PermissionError :
150- util .exit_fatal (f"No permissiont to open file { kwargs ['sif' ]} , aborting..." , err )
207+ util .exit_fatal (f"No permission to open file { kwargs ['sif' ]} , aborting..." , err )
151208 except sif .NotSystemInfo :
152209 util .exit_fatal (f"File { kwargs ['sif' ]} does not seem to be a system info or support info file, aborting..." , err )
153210 else :
@@ -157,6 +214,7 @@ def main():
157214 except exceptions .ConnectionError as e :
158215 util .exit_fatal (e .message , e .errcode )
159216 server_id = sq .server_id ()
217+ settings ["SERVER_ID" ] = server_id
160218 util .check_token (kwargs [options .TOKEN ])
161219 key_list = kwargs [options .KEYS ]
162220 if key_list is not None and len (key_list ) > 0 and "projects" in util .csv_to_list (kwargs [options .WHAT ]):
@@ -168,7 +226,6 @@ def main():
168226 except exceptions .ObjectNotFound as e :
169227 util .exit_fatal (e .message , errcodes .NO_SUCH_KEY )
170228
171- ofile = kwargs .pop (options .REPORT_FILE )
172229 if problems :
173230 log .warning ("%d issues found during audit" , len (problems ))
174231 else :
0 commit comments