
    VBib3                         S r SSKrSSKrSSKrSSKJrJrJr  SSKJr  SSK	J
r
Jr  \R                  " \5      r " S S5      rg)z
Bitbucket API client for repository management and change detection.
Uses Bitbucket Cloud REST API 2.0 with read-only access.
    N)ListDictOptional)datetime)urlparseparse_qsc            	           \ rS rSrSrSS\S\S\S\4S jjrSS	\S
\\   S\S\4S jjr	S\
\   4S jrS\S\\   4S jrS\S\\   4S jrSS\S\S\\   4S jjrS\S\\   S\4S jrSS\S\S\\   4S jjrSrg)BitbucketClient   z>Read-only client for interacting with Bitbucket Cloud API 2.0.N	workspaceusernameapp_password	api_tokenc                 r   Xl         SU l        U(       a'  U(       d  [        S5      eX l        X@l        X$4U l        O9U(       a'  U(       d  [        S5      eX l        X0l        X#4U l        O[        S5      e[        R                  " 5       U l	        U R
                  U R                  l        SU l
        SU l        g)a  
Initialize Bitbucket client with read-only access.

Supports two authentication methods:
1. App Password: username + app_password
2. API Token: api_token (username will be your email if using token)

Args:
    workspace: Bitbucket workspace name
    username: Bitbucket username/email (required for app password, optional for API token)
    app_password: Bitbucket app password (alternative to api_token)
    api_token: Atlassian API token (alternative to app_password)
zhttps://api.bitbucket.org/2.0z1Username (email) is required when using API tokenz,Username is required when using app passwordz1Either app_password or api_token must be providedr   g?N)r   base_url
ValueErrorr   r   authr   requestsSessionsessionlast_request_timemin_request_interval)selfr   r   r   r   s        0C:\wamp64\www\sonar_scan\src\bitbucket_client.py__init__BitbucketClient.__init__   s     #7  !TUU$M&N!-DI !OPP$M ,!0DIPQQ'') II!"$'!    endpointparamsmethodreturnc           	         UR                  5       S:w  a  [        S5      e[        R                  " 5       U R                  -
  nX@R                  :  a#  [        R
                  " U R                  U-
  5        U R                   SUR                  S5       3n U R                  R                  XRSS9n[        R                  " 5       U l        UR                  S:X  an  [        UR                  R                  SS5      5      n[        R                  S	U S
35        [        R
                  " U5        U R                  R                  XRSS9nUR                  5         UR!                  5       $ ! ["        R$                   a  nUR&                  R                  S:X  a0  [        R)                  SU SUR&                  R*                   35        OF[        R-                  SU SUR&                  R                   SUR&                  R*                   35        [/        UR&                  S5      (       a,  [        R)                  SUR&                  R0                   35        e SnAf["        R2                   ay  n[        R-                  SU SU 35        [/        US5      (       aG  [/        UR&                  S5      (       a,  [        R)                  SUR&                  R0                   35        e SnAff = f)a-  
Make authenticated read-only request to Bitbucket API 2.0.

Args:
    endpoint: API endpoint (relative to base_url)
    params: Query parameters
    method: HTTP method (only GET allowed for read-only)
    
Returns:
    JSON response data
    
Raises:
    requests.RequestException: If request fails
GETz+Read-only client only supports GET requests/   )r   timeouti  zRetry-After<   zRate limited. Waiting z seconds...  zBitbucket API 404 for : z!Bitbucket API request failed for  textz
Response: Nresponse)upperr   timer   r   sleepr   lstripr   getstatus_codeintheadersloggerwarningraise_for_statusjsonr   	HTTPErrorr,   debugreasonerrorhasattrr+   RequestException)	r   r   r   r    time_since_lasturlr,   retry_afteres	            r   _make_requestBitbucketClient._make_request<   s?     <<>U"JKK ))+(>(>>666JJt00?BCq!5 67	||''B'GH%)YY[D" ##s*!("2"2"6"6}b"IJ!7}KPQ

;'<<++C+K%%'==?"!! 	zz%%,5hZr!**BSBSATUV@
"QZZMcMcLddefgfpfpfwfwexyzqzz6**z!**//):;<(( 	LL<XJbLMq*%%'!**f*E*Ez!**//):;<		s'   CE' 'K#;CIK#*A4KK#c           	         / nSU R                    3nSS0n Sn U(       a  [        U5      nUR                  R                  SS5      R	                  S5      n[        [        UR                  5      5      nUR                  5        VVs0 s H1  u  pxU[        U[        5      (       a  [        U5      S:X  a  US	   OU_M3     nnnU R                  X#5      n	OU R                  X#5      n	UR                  U	R                  S
/ 5      5        U	R                  S5      nU(       d  OGM	  [        R!                  S[        U5       SU R                    35        U$ s  snnf ! ["         a$  n
[        R%                  SU
 35        / s Sn
A
$ Sn
A
ff = f)z
Get all repositories in the workspace using API 2.0 pagination.

Returns:
    List of repository dictionaries with name, slug, and clone URLs
repositories/pagelend   Nz/2.0/ r$      r   valuesnextzFound z repositories in workspace zFailed to fetch repositories: )r   r   pathreplacer0   dictr   queryitems
isinstancelistlenrC   extendr1   r5   info	Exceptionr<   )r   reposr   r   next_urlparsedquery_paramskvdatarB   s              r   get_all_repositories$BitbucketClient.get_all_repositoriesr   sq    "4>>"23S!	H &h/F%{{227B?FFsKH#'(>#?L *6););)=?)=  At)<)<Q11RSS)=  ?--h?D  --h?DTXXh34  88F+) , KK&U,GGWXYL?   	LL9!=>I	s1   A1E 8E BE E 
F#F<FF	repo_slugc                      SU R                    SU 3nU R                  U5      $ ! [         a%  n[        R	                  SU SU 35         SnAgSnAff = f)z
Get detailed information about a specific repository.

Args:
    repo_slug: Repository slug/name
    
Returns:
    Repository information dictionary
rF   r$   z$Failed to fetch repository info for r)   N)r   rC   rW   r5   r<   )r   ra   r   rB   s       r   get_repository_info#BitbucketClient.get_repository_info   s\    	&t~~&6a	{CH%%h// 	LL?	{"QCPQ	s   "% 
AAAc                 T    U R                  U5      nU(       a]  UR                  S5      nU(       a:  [        U[        5      (       a  UR                  S5      O
[	        U5      nU(       a  U$ SU;   a  US   $ g! [
         a%  n[        R                  SU SU 35         SnAgSnAff = f)z
Get the default branch for a repository.

Args:
    repo_slug: Repository slug/name
    
Returns:
    Default branch name (e.g., "main", "master") or None

mainbranchnamedefault_branchz!Failed to get default branch for r)   N)rc   r1   rR   rO   strrW   r5   r:   )r   ra   	repo_inforf   branch_namerB   s         r   get_default_branch"BitbucketClient.get_default_branch   s    	O00;I&]]<8
<FzSW<X<X*.."8^abl^mK"** $y0$%566   	OLL<YKr!MNN	Os   A)A8 ,
A8 8
B'B""B'branchc           
      X   / nU(       a  UR                  U5        U R                  U5      nU(       a  XC;  a  UR                  U5        S H  nXS;  d  M
  UR                  U5        M     U H  n SU R                   SU SU 3nSS0nU R                  Xx5      n	U	(       a  SU	;   a  [	        U	S   5      S:  a{  U	S   S   n
[
        R                  S	U S
U 35        U
R                  S5      U
R                  S5      U
R                  SS5      U
R                  S0 5      R                  SS5      US.s  $ M  M  M     [
        R                  SU SSR                  U5       S35        g! [        R                   a{  nUR                  R                  S:X  a#  [
        R                  SU SU S35         SnAGMM  [
        R                  SU SU SUR                  R                   35         SnAGM  SnAf[         a*  n[
        R                  SU SU SU 35         SnAGM  SnAff = f)z
Get the latest commit for a repository branch using API 2.0.

Args:
    repo_slug: Repository slug/name
    branch: Branch name (if None, will try to get default branch, then try main/master)
    
Returns:
    Latest commit information with date
)mainmasterdeveloprF   r$   z	/commits/rG   rJ   rK   r   zFound latest commit on branch 'z' for hashdatemessagerI   authorraw)rs   rt   ru   rv   rn   r(   zBranch 'z' not found for z, trying next branchNz'HTTP error getting commits for branch 'z' in r)   z"Error getting commits for branch 'z$Could not find any valid branch for z	 (tried: z, ))appendrl   r   rC   rT   r5   r:   r1   r   r9   r,   r2   r6   rW   join)r   ra   rn   branches_to_tryrh   common_branchrk   r   r   r^   latest_commitrB   s               r   get_latest_commit!BitbucketClient.get_latest_commit   s7     ""6* 00;nC"">2 ;M3&&}5 ; +K*4>>*:!I;iP[}]#Q))(;H,T(^1Dq1H$(N1$5MLL#B;-vV_U`!ab - 1 1& 9 - 1 1& 9#0#4#4Y#C"/"3"3Hb"A"E"EeR"P"-  2I,4 +< 	=i[	RVR[R[\kRlQmmnop %% ::))S0LL8K=8HSg!hi!HUZ[dZeeghihrhrh~h~g   A  B A+eT]S^^`ab`cdes+   0CE((H)<6G292G22H)?H$$H)last_scan_datec                 b   Uc  gU R                  U5      nU(       d  gUR                  S5      nU(       d  g [        R                  " UR	                  SS5      5      nUR
                  (       a  UR	                  SS9nXR:  $ ! [         a"  n[        R                  SU 35         SnAgSnAff = f)	z
Check if repository has changes since last scan date.

Args:
    repo_slug: Repository slug/name
    last_scan_date: Last scan datetime (None if never scanned)
    
Returns:
    True if repository has new commits since last scan
NTFrt   Zz+00:00)tzinfozFailed to parse commit date: )	r~   r1   r   fromisoformatrN   r   rW   r5   r6   )r   ra   r   r}   commit_date_strcommit_daterB   s          r   has_changes_since!BitbucketClient.has_changes_since  s     !..y9'++F3
	"001H1Hh1WXK!!)111>// 	NN:1#>?	s   A	B 
B.B))B.rj   protocolc                     UR                  S0 5      nUR                  S/ 5      nU H+  nUR                  S5      U:X  d  M  UR                  S5      s  $    g)z
Get clone URL for repository.

Args:
    repo_info: Repository information dictionary
    protocol: Clone protocol (https or ssh)
    
Returns:
    Clone URL string
linksclonerg   hrefN)r1   )r   rj   r   r   clone_linkslinks         r   get_clone_urlBitbucketClient.get_clone_url(  sS     gr*ii,Dxx8+xx''   r   )	r   r   r   r   r   r   r   r   r   )NNN)Nr#   )N)https)__name__
__module____qualname____firstlineno____doc__ri   r   r   r   rC   r   r_   rc   rl   r~   r   boolr   r   __static_attributes__ r   r   r
   r
      s    H((# (( ((3 ((be ((T4c 48D> 4RU 4bf 4l'd4j 'RS Xd^ "C HSM :;3 ; ;xPT~ ;z 3  @R  W[  Dt s RU  r   r
   )r   r   loggingr.   typingr   r   r   r   urllib.parser   r   	getLoggerr   r5   r
   r   r   r   <module>r      s=       ' '  +			8	$k kr   