
    -ni6\                         S r SSKrSSKrSSKrSSKrSSKrSSKrSSKrSSKJ	r	  SSK
JrJr  SSKJr  \R                  " \5      r " S S5      rg)z@
SonarQube scanner integration for running code analysis scans.
    N)Path)DictOptional)datetimec                   8   \ rS rSrSrSS\S\S\4S jjrS S\S\S	\S
\S\	4
S jjr
S\S\S\	4S jrS\4S jrS\SS4S jrS\S\\   4S jrS\S\\   4S jrS\S\\	   4S jrS\S\\   4S jrS\S\4S jrS!S\S\S\S\S\4
S jjrS\S\S\S\4S jrSrg)"SonarQubeScanner   z&Manages SonarQube scanning operations.	sonar_urlsonar_tokenscanner_pathc                    UR                  S5      U l        X l        [        R                  " 5       S:X  Ga  UR                  S5      (       Gd  [        R                  " U5      (       d  US-   n[        R                  " U5      (       a  Un[        R                  SU 35        O[        [        5      R                  R                  R                  5       n[        US-  S-  S-  5      S	S
[        R                   R#                  S5      /nU HC  n[        R                   R%                  U5      (       d  M)  Un[        R                  SU 35          O   X0l        [        R                  " 5       S:H  U l        g)z
Initialize SonarQube scanner.

Args:
    sonar_url: SonarQube server URL
    sonar_token: SonarQube authentication token
    scanner_path: Path to sonar-scanner command (or just "sonar-scanner" if in PATH)
/Windows).batz.exe.cmdr   zUsing Windows batch file: sonar-scannerbinzsonar-scanner.batz0C:\Program Files\SonarQube\bin\sonar-scanner.batz&C:\sonar-scanner\bin\sonar-scanner.batz%~\sonar-scanner\bin\sonar-scanner.batzFound sonar-scanner at: N)rstripr
   r   platformsystemendswithshutilwhichloggerinfor   __file__parentabsolutestrospath
expanduserexistsr   
is_windows)selfr
   r   r   bat_path
script_dircommon_pathsr!   s           src/sonarqube_scanner.py__init__SonarQubeScanner.__init__   s.    #))#.& ??	)(()ABB||L11+f4H||H--'/&@$OP &*(^%:%:%A%A%J%J%L

_ <u DGZ Z[OEGG../WX	( %1D!ww~~d33/3 &.F|n,U V %	 %1 )"//+y8    	repo_pathsonar_properties_pathmax_retriesretry_delayreturnc           
         [         R                  SUR                   35        Sn[        US-   5       H  nUS:  a@  USUS-
  -  -  n[         R                  SU SU SU S	35        [        R
                  " U5        U R                  X5      nUR                  S
5      (       a  Us  $ UR                  SS5      nSU;   d  SU;   a&  Xc:  a!  [         R                  SUSU-  -   S	35        M  Us  $    U(       a  U$ SSS.$ )a'  
Run SonarQube scan on a repository with retry logic for concurrent scan errors.

Args:
    repo_path: Path to repository directory
    sonar_properties_path: Path to sonar-project.properties file
    max_retries: Maximum number of retries for concurrent scan errors (default: 3)
    retry_delay: Initial delay in seconds between retries (default: 60, doubles each retry)
    
Returns:
    Dictionary with scan results including:
    - success: bool
    - task_id: str (if available)
    - analysis_id: str (if available)
    - error: str (if failed)
zStarting SonarQube scan for N   r      zRetry attempt r   z after waiting z seconds...successerror 1Another SonarQube analysis is already in progressalready in progressz/Another analysis is in progress. Will retry in FzScan failed after all retriesr5   r6   )	r   r   namerangetimesleep_execute_scangetwarning)	r%   r-   r.   r/   r0   resultattempt	wait_time	error_msgs	            r)   run_scanSonarQubeScanner.run_scan?   s   " 	29>>2BCD[1_-G{'11+=>	nWIQ{m?S\R]]hij

9%''	IF zz)$$ 

7B/ICyP%28M!PQ\`ael`lQmPnnyz{ M) ..  vaA`%aar,   c           	      0    US-  nUR                  SSS9  US-  nUR                  SSS9  [        R                  SU 35        U R                  U5        [        R
                  R                  5       nU R                  US'   [        [        5      R                  R                  S-  nUR                  SSS9  [        UR                  5       5      US'   [        R                  S	U 35        [        R                  " 5       n[        R                  " U5         U R                  (       aD  U R                   R#                  S
5      (       a$  [$        R&                  " U R                   SSUSSS9nO#[$        R&                  " U R                   /SSUSS9nUR(                  S:X  a  [        R+                  SUR,                   35        U R/                  UR0                  5      n	U R3                  UR0                  5      n
SU	U
UR0                  S.[        R                  " U5        $ UR4                  =(       d    UR0                  n[        R7                  SUR,                   SU 35        SU;   d  SU;   a/  [        R9                  S5        [        R+                  S5        US-  nSU;   d  SU;   d  SU;   aY  [        R9                  S5        US-  nUR                  SSS9  US-  nUR                  SSS9  [        R+                  S5        US-  nSU;   d  SU;   a  [        R9                  S5        U R;                  5       nU(       a  [        R+                  S 5        US!-  nOO[        R9                  S"5        [        R9                  S#[        R<                  R?                  S$5       35        US%-  nS&UUR0                  S'.[        R                  " U5        $ ! [        R                  " U5        f = f! [$        R@                   a*    [        R7                  S(UR,                   35        S&S)S*.s $ [B         a  nS+U R                    3n[        R7                  U5        [        R7                  S,5        [        R7                  S-5        [        R7                  S.5        [        R7                  S/5        S&US*.s S0nA$ S0nAf[D         a  n[        U5      n[        R7                  S1U 35        SU;   d  SU;   a  [        R9                  S5        U R;                  5       nU(       a  [        R+                  S 5        US!-  nOO[        R9                  S"5        [        R9                  S#[        R<                  R?                  S$5       35        US%-  nS&US*.s S0nA$ S0nAff = f)2z
Execute a single SonarQube scan attempt.

Args:
    repo_path: Path to repository directory
    sonar_properties_path: Path to sonar-project.properties file
    
Returns:
    Dictionary with scan results
z.scannerworkT)parentsexist_okz	.sonartmpz(Ensured scanner work directories exist: SONAR_TOKENz.sonar_cacheSONAR_USER_HOMEz!Using SonarQube cache directory: )r   r   i  )capture_outputtextenvtimeoutshell)rM   rN   rO   rP   r   z*SonarQube scan completed successfully for )r5   task_idanalysis_idoutputzSonarQube scan failed for : r8   r9   zBAnother SonarQube analysis is already in progress for this projectzKThis usually means a previous scan is still running on the SonarQube serverz<

Another analysis is in progress. Will retry automatically.zFailed to create temp fileNoSuchFileExceptionzHDetected temp file creation error, ensuring scanner directories exist...z8Scanner work directories created. Please retry the scan.z5

Scanner directories created. Please retry the scan.AccessDeniedExceptionzFailed to extract archivezGDetected cache/permission error, attempting to clear SonarQube cache...z2Cache cleared successfully. Please retry the scan.z'

Cache cleared. Please retry the scan.z;Could not clear cache automatically. Please manually clear:z  ~/.sonar/cachez7

Please clear the SonarQube cache directory and retry.F)r5   r6   rT   zSonarQube scan timed out for zScan timed out after 30 minutesr:   zSonarQube scanner not found: z4Please ensure sonar-scanner is installed and either:z"  1. Added to your system PATH, orzH  2. Set the 'scanning.sonar_scanner_path' config value to the full pathz<   Example: C:\Program Files\SonarQube\bin\sonar-scanner.batNz(Unexpected error during SonarQube scan: )#mkdirr   debug_update_sonar_propertiesr    environcopyr   r   r   r   r   r   getcwdchdirr$   r   r   
subprocessrun
returncoder   r;   _extract_task_idstdout_extract_analysis_idstderrr6   rA   _clear_sonar_cacher!   r"   TimeoutExpiredFileNotFoundError	Exception)r%   r-   r.   scannerwork_dirsonartmp_dirrO   project_cache_diroriginal_cwdrB   rR   rS   rE   cache_clearedes                 r)   r?   SonarQubeScanner._execute_scanl   s   M	'.8O!!$!> +[8Ltd;LLCOCTUV ))*?@ **//#C!%!1!1C !%X 5 5 < <~ M##D4#@%():)C)C)E%FC!"LL<=N<OPQ 99;LHHYK' ??t'8'8'A'ABR'S'S'^^))'+! $"F (^^**+'+! $F $$)KK"LY^^L\ ]^ #33FMMBG"&";";FMM"JK $(#*'2"(--	X &K !' >ILL#=inn=MRPY{![\ KiW[pt}[}'kl$qr!%ee	 4y@DY]fDfju  zC  kC'qr*3n*D'--dT-J'6'D$**4$*G$^_!%^^	 /);?Z^g?g'pq(,(?(?(A("KK(\]%)TTI"NN+hi"NNR0B0BCS0T/U+VW%)ddI $)!*"(-- &&(( 	LL88HIJ :  ! 
	78I8I7JKILL#LLOPLL=>LLcdLL[] "   	AILLCA3GH ')37RV_7_hi $ 7 7 9 KK TU!LLINN#`aNNR(:(:;K(L'M#NO!\\I !" !	s^   DO, C0O O, FO :O, O))O, ,;V)	V2A<R4.V4VC	V
VVc                     [         R                  R                  S5      n[         R                  R                  U5      (       aD  [        R                  SU 35        [        R                  " U5        [        R                  S5        g[        R                  S5        g! [         a7  n[        R                  SU 35        [        R                  S5         SnAg	SnAf[         a"  n[        R                  S
U 35         SnAg	SnAff = f)z
Clear SonarQube cache directory to fix permission/corruption issues.

Returns:
    True if cache was cleared successfully, False otherwise
rX   z$Clearing SonarQube cache directory: z$SonarQube cache cleared successfullyTz(SonarQube cache directory does not existz.Permission denied when trying to clear cache: zJPlease manually clear the cache directory or run with elevated permissionsNFz!Failed to clear SonarQube cache: )r    r!   r"   r#   r   r   r   rmtreerZ   PermissionErrorr6   rj   )r%   	cache_dirrp   s      r)   rg   #SonarQubeScanner._clear_sonar_cache  s    	**+;<Iww~~i((B9+NOi(BCGH 	LLI!MNLLef 	LL<QC@A	s*   BB 	B 
D
)-CD
(DD
properties_pathNc                     [        US5       nUR                  5       nSSS5        SW;   a%  SSKnUR                  SSU R                   3U5      nOUSU R                   S3-  n[        US	5       nUR                  U5        SSS5        g! , (       d  f       Ns= f! , (       d  f       g= f! [         a"  n[        R                  S
U 35         SnAgSnAff = f)z~
Update sonar-project.properties with server URL and token.

Args:
    properties_path: Path to sonar-project.properties file
rNzsonar.host.urlr   zsonar\.host\.url\s*=.*zsonar.host.url=z
sonar.host.url=
wz+Failed to update sonar-project.properties: )	openreadresubr
   writerj   r   rA   )r%   rw   fcontentr~   rp   s         r)   r[   )SonarQubeScanner._update_sonar_properties  s    	Nos+q&&( ,  7*&&-%dnn%56 .t~~.>bAA os+q  ,+) ,+( ,+  	NNNHLMM	NsL   B. BAB. 1BB. 
BB. 
B+'B. +B. .
C8CCrT   c                     SSK nUR                  SXR                  5      nU(       a  UR                  S5      $ UR                  SU5      nU(       a  UR                  S5      $ g)zv
Extract task ID from scanner output.

Args:
    output: Scanner output text
    
Returns:
    Task ID string or None
r   Nz#EXECUTION SUCCESS.*?taskId=([^\s]+)r3   ztaskId[=:]\s*([^\s\n]+))r~   searchDOTALLgroupr%   rT   r~   matchs       r)   rc   !SonarQubeScanner._extract_task_idB  sT     			@&))T;;q>! 		4f=;;q>!r,   c                 `    SSK nUR                  SU5      nU(       a  UR                  S5      $ g)z~
Extract analysis ID from scanner output.

Args:
    output: Scanner output text
    
Returns:
    Analysis ID string or None
r   NzanalysisId[=:]\s*([^\s\n]+)r3   )r~   r   r   r   s       r)   re   %SonarQubeScanner._extract_analysis_idX  s,     			8&A;;q>!r,   project_keyc                 ~    U R                    S3nSU0nSSU R                   30n[        R                  " X#USS9nUR	                  5         UR                  5       nU R                    S3nUSS	.n[        R                  " UUUSS9n	U	R                  S
:X  a  U	R                  5       O0 n
UR                  S0 5      R                  SS5      U
R                  S0 5      R                  S/ 5      [        R                  " 5       R                  5       S.$ ! [         a"  n[        R                  SU 35         SnAgSnAff = f)z
Get scan results from SonarQube API.

Args:
    project_key: SonarQube project key
    
Returns:
    Dictionary with scan metrics and quality gate status
z /api/qualitygates/project_status
projectKeyAuthorizationBearer    paramsheadersrP   z/api/measures/componentzHcoverage,bugs,vulnerabilities,code_smells,duplicated_lines_density,ncloc)	component
metricKeys   projectStatusstatusUNKNOWNr   measures)quality_gatemetrics	timestampz/Failed to get scan results from SonarQube API: N)r
   r   requestsr@   raise_for_statusjsonstatus_coder   now	isoformatrj   r   r6   )r%   r   
status_urlr   r   responsestatus_datametrics_urlmetrics_paramsmetrics_responsemetrics_datarp   s               r)   get_scan_results!SonarQubeScanner.get_scan_resultsh  sF    	 NN++KLJ"K0F&'$2B2B1C(DEG||JwXZ[H%%'"--/K "^^,,CDK(hN
  (||%	  7G6R6RVY6Y+002_aL !, D H HS\ ]'++K<@@RP%\\^557 
  	LLJ1#NO	s   DD 
D<D77D<c                 f    [        US5       nU HU  nUR                  5       R                  S5      (       d  M)  UR                  SS5      S   R                  5       s  sSSS5        $    SSS5        g! , (       d  f       g= f! [         a"  n[
        R                  SU 35         SnAgSnAff = f)z
Extract project key from sonar-project.properties.

Args:
    properties_path: Path to sonar-project.properties file
    
Returns:
    Project key string or None
ry   zsonar.projectKey=r3   NzFailed to read project key: )r|   strip
startswithsplitrj   r   rA   )r%   rw   r   linerp   s        r)   get_project_key SonarQubeScanner.get_project_key  s    	?os+qDzz|../ABB#zz#q1!4::<< ,+ ,  ,+   	?NN9!=>>	?sE   B (A3$A3	B (A3*B 3
B=B B 
B0B++B0c                     U R                    S3nSU0nSSU R                   30n[        R                  " X#USS9nUR	                  5         UR                  5       nUR                  S/ 5      nU H3  nUR                  S5      U:X  d  M  [        R                  S	U S
35          g   [        R                  S	U S35        g! [        R                   aA  n	U	R                  R                  S:X  a   Sn	A	g[        R                  SU	 35         Sn	A	gSn	A	f[         a"  n	[        R                  SU	 35         Sn	A	gSn	A	ff = f)z
Check if a SonarQube project exists.

Args:
    project_key: SonarQube project key
    
Returns:
    True if project exists, False otherwise
z/api/projects/searchprojectsr   r   r   r   
componentskey	Project 'z' exists in SonarQubeTz' not found in SonarQubeFi  Nz"Error checking project existence: z#Failed to check if project exists: )r
   r   r   r@   r   r   r   rZ   	HTTPErrorr   r   rA   rj   )
r%   r   urlr   r   r   datar   r   rp   s
             r)   check_project_exists%SonarQubeScanner.check_project_exists  s(   	^^$$89C +.F&'$2B2B1C(DEG||CQSTH%%'==?D,3J (	==';6LL9[M9N!OP (
 LL9[M1IJK!! 	zz%%,NN?sCD 	NN@DE	s6   BC 
C %C E D4DE D;;E project_namedescription
visibilityc                 :    U R                    S3nSSU R                   30nUUUS.nU(       a  X7S'   [        R                  " XWUSS9nUR                  S:X  a  [
        R                  S	U S
U S35        gUR                  S:X  aV  UR                  n	SU	R                  5       ;   a  [
        R                  SU S35        g[
        R                  SU SU	 35        gUR                  5         g! [        R                   al  n
[
        R                  SU SU
 35        [        U
R                  S5      (       a,  [
        R                  SU
R                  R                   35         Sn
A
gSn
A
f[          a%  n
[
        R                  SU SU
 35         Sn
A
gSn
A
ff = f)a\  
Create a new project in SonarQube.

Args:
    project_key: SonarQube project key (must be unique)
    project_name: Display name for the project
    description: Project description (optional)
    visibility: Project visibility - "private" or "public" (default: private)
    
Returns:
    True if project was created successfully, False otherwise
z/api/projects/creater   r   )projectr;   r   r   r   )r   r   rP   r   z(Successfully created SonarQube project: z ()Ti  zalready existsr   z' already exists in SonarQubezFailed to create project 'z': Fz'HTTP error creating SonarQube project 'rN   z
Response: Nz$Failed to create SonarQube project ')r
   r   r   postr   r   r   rN   lowerrA   r   r   r6   hasattrr   rZ   rj   )r%   r   r   r   r   r   r   r   r   
error_textrp   s              r)   create_projectSonarQubeScanner.create_project  s   $	^^$$89C&'$2B2B1C(DEG '$(D &1]#}}SWbQH##s*F{mSUVbUccdef%%,%]]
#z'7'7'99KK)K=8U VW!;K=J<XY))+!! 	LLB;-sSTRUVWqzz6**z!**//):;< 	LL?}CPQsST	s8   A3C- 6A	C-  C- C- -FA"E((F5FFc                 J   US-  n SU SU SU R                    S3n[        USSS9 nUR                  U5        S	S	S	5        [        R	                  S
UR
                   SU 35        U$ ! , (       d  f       N5= f! [         a  n[        R                  SU 35        e S	nAff = f)z
Generate sonar-project.properties file with default values.

Args:
    repo_path: Path to repository directory
    project_key: SonarQube project key
    project_name: Project display name
    
Returns:
    Path to created sonar-project.properties file
zsonar-project.propertiesz{# SonarQube Project Properties
# Auto-generated by SonarQube Scanner Automation

# Project identification
sonar.projectKey=z
sonar.projectName=zL

# Source code location
sonar.sources=.

# SonarQube server
sonar.host.url=z(

# Encoding
sonar.sourceEncoding=UTF-8
r{   zutf-8)encodingNz'Generated sonar-project.properties for rU   z-Failed to generate sonar-project.properties: )r
   r|   r   r   r   r;   rj   r6   )r%   r-   r   r   rw   properties_contentr   rp   s           r)   generate_sonar_properties*SonarQubeScanner.generate_sonar_properties   s     $&@@	&  . !   "$ osW=*+ > KKA)..AQQSTcSdef""	 >=
  	LLHLM	s-   !A: A).A: )
A73A: :
B"BB")r$   r   r   r
   )r   )   <   )r7   private)__name__
__module____qualname____firstlineno____doc__r   r*   r   intr   rF   r?   boolrg   r[   r   rc   re   r   r   r   r   r   __static_attributes__ r,   r)   r   r      sS   0(9# (9C (9s (9T+b$ +bt +bRU +bhk +buy +bZXt XD XT XtD 2!N !N !NFs x} ,3 8C=  *C *HTN *Xt  &$ $ $L1# 1S 1s 1eh 1y} 1f)4 )c )Y\ )ae )r,   r   )r   r    r`   loggingr=   r   r   r   pathlibr   typingr   r   r   	getLoggerr   r   r   r   r,   r)   <module>r      sF    
        ! 			8	$W Wr,   