
    i#                        d Z ddlZddlZddlZddlZddlZddlmZ ddlm	Z	  G d de
      Zddeded	ee   fd
Zded	ee   fdZdee   d	eeee   f   fdZ ej$                  d      Zded	ee   fdZ ej$                  d      Zh dZded	ee   fdZdeeee   f   d	efdZdee   d	eee	f   fdZd	ej4                  fdZddZedk(  r e        yy)u   diff-aware-qa.py — Git diff 기반 QA 영향 범위 자동 식별 도구

Usage:
    python3 diff-aware-qa.py [--project-dir DIR] [--base-ref REF] [--output json|text]
    N)Path)Anyc                       e Zd ZdZy)GitErroru   git 관련 오류N)__name__
__module____qualname____doc__     F/home/jay/workspace/.worktrees/task-2116-dev1/scripts/diff-aware-qa.pyr   r      s    r   r   project_dirbase_refreturnc                 4   t        |       dz  }|j                         st        d|        dd| d| ddg}t        j                  |dd	      }|j
                  d
k7  r&t        d|j                  j                                t        |j                        S )u]   git diff <base_ref>...HEAD --name-only 를 실행하고 변경 파일 목록을 반환한다.z.gitzNot a git repository: gitz-Cdiffz...HEADz--name-onlyT)capture_outputtextr   zgit diff failed: )
r   existsr   
subprocessrun
returncodestderrstripparse_diff_outputstdout)r   r   git_dircmdresults        r   get_changed_filesr!      s    ;&(G>>/}=>>$Vz-A=
QC^^C4@FA*6==+>+>+@*ABCCV]]++r   rawc                     | j                         D cg c]#  }|j                         s|j                         % c}S c c}w )uT   git diff --name-only 출력을 파싱하여 파일 경로 리스트로 반환한다.)
splitlinesr   )r"   lines     r   r   r   *   s+    %(^^%5FTDJJLFFFs   >>filesc                    g g g g g d}| D ]  }t        |      }|j                  }|j                  j                         }|j	                  d      st        j                  d|      r|d   j                  |       p|dk(  r|d   j                  |       |dv r|d   j                  |       |d	v r|d
   j                  |       |d   j                  |        |S )uL   파일 목록을 backend / frontend / style / test / other 로 분류한다.backendfrontendstyletestothertest_z\.(test|spec)\.r,   .pyr)   ).ts.tsx.jsx.jsr*   )z.cssz.scssz.sassz.lessr+   r-   )r   namesuffixlower
startswithresearchappend)r&   
categoriesfilepathpathr4   r5   s         r   classify_filesr>   2   s     (J  1H~yy""$ ??7#ryy1CT'Jv%%h/u_y!((255z"))(3::w&&x0w&&x01" r   z&@\w+(?:\.\w+)*\s*\(\s*['"]([^'"]+)['"]r<   c                 (   t        |       }|j                  dk7  rg S 	 |j                  dd      }g }t        j                  |      D ]6  }|j                  d      }|j                  d      s&|j                  |       8 |S # t        $ r g cY S w xY w)u^   Python 파일에서 @app.route(), @router.get() 등 라우트 데코레이터를 파싱한다.r/   utf-8ignoreencodingerrors   /)	r   r5   	read_textOSError_ROUTE_PATTERNfinditergroupr7   r:   )r<   r=   contentroutesmatchvalues         r   extract_routes_from_filerP   X   s    >D{{e	..'(.C F((1 !AC MM% 	! M  	s   B BBzBexport\s+default\s+(?:function|class|const)\s+([A-Z][A-Za-z0-9_]*)>   r3   r0   r2   r1   c                 n   t        |       }|j                  t        vrg S 	 |j                  dd      }g }t
        j                  |      D ]"  }|j                  |j                  d             $ |s2|j                  }|r$|d   j                         r|j                  |       |S # t        $ r g cY S w xY w)uh   TS/TSX 파일에서 export default 컴포넌트명을 추출한다. 없으면 파일명을 사용한다.r@   rA   rB   rE   r   )r   r5   _FRONTEND_SUFFIXESrG   rH   _EXPORT_DEFAULT_PATTERNrJ   r:   rK   stemisupper)r<   r=   rL   
componentsrN   rT   s         r   extract_components_from_filerW   u   s    >D{{,,	..'(.C J(11': *%++a.)* yyDGOO%d#  	s   B& &B43B4r;   c                     g }dddddd}|j                         D ]<  \  }}t        | j                  |g             }|dkD  s'|j                  | d|        > |sy	d
j	                  |      dz   S )u>   변경 분류 결과를 한 줄 요약 문자열로 만든다.u   백엔드 파일u   프론트엔드 컴포넌트u   스타일 파일u   테스트 파일u   기타 파일r(   r   u   개 u   변경된 파일 없음, u    변경)itemslengetr:   join)r;   parts	label_mapkeylabelcounts         r   build_summaryrc      s    E%2#" I  oo' 0
UJNN3+,19LLE7$ug./0
 (99Ui''r   changed_filesc                 D   t        |       }g }|d   D ]  }|j                  t        |              t               }g }|D ])  }||vs|j	                  |       |j                  |       + g }|d   D ]  }|j                  t        |              t               }g }	|D ])  }
|
|vs|j	                  |
       |	j                  |
       + g }|j                  |       |j                  |	       |d   D ]  }|j                  d|         t        |      }| ||	|||dS )uD   변경 파일 목록을 받아 영향 분석 결과를 반환한다.r)   r*   r,   u   테스트: )rd   affected_routesaffected_componentsr;   
qa_targetssummary)r>   extendrP   setaddr:   rW   rc   )rd   r;   rf   r<   seenunique_routesrrg   
seen_compsunique_componentscrh   ri   s                r   analyze_changesrs      s_   .J!#Oy) C7ABC UD!M $D=HHQK  #$
 &(z* K""#?#IJK5J#%  (JNN1$$Q'( Jm$'(v& 4Kz234 J'G '(0   r   c                      t        j                  dt         j                        } | j                  ddd       | j                  ddd	       | j                  d
ddgdd       | S )Nu5   git diff 기반 QA 영향 범위 자동 식별 도구)descriptionformatter_classz--project-dir.u;   git 프로젝트 디렉토리 (기본: 현재 디렉토리))defaulthelpz
--base-refmainu+   diff 기준 브랜치/커밋 (기본: main)z--outputjsonr   u   출력 형식 (기본: json))choicesrx   ry   )argparseArgumentParserRawDescriptionHelpFormatteradd_argument)parsers    r   build_parserr      sn    $$K <<F ;xy
f;hi

VV,<fSqrMr   c                     t               } | j                         }	 t        |j                  |j                        }t              }|j                  dk(  r"t        t        j                  |dd             y t        d	t        |d
          d       t        ddj                  |d         xs d        t        ddj                  |d         xs d        t        d|d           |d   r$t        d       |d   D ]  }t        d|         y y # t
        $ r>}t        d| t        j                         t        j                  d       Y d }~d }~ww xY w)N)r   r   zError: )filerE   r{   F   )ensure_asciiindentu   변경 파일: rd   u   개u   영향받는 라우트: rY   rf   u   없음u   영향받는 컴포넌트: rg   u   요약: ri   rh   u
   QA 타겟:z  - )r   
parse_argsr!   r   r   r   printsysr   exitrs   outputr{   dumpsr[   r]   )r   argsrd   excr    targets         r   rz   rz      sI   ^FD)d6F6FQUQ^Q^_
 ]+F{{fdjjeA>?F?$; <=SAB(6:K3L)M)YQY(Z[\+DIIf=R6S,T,`X`+abc	*+,-,, . 'VHo&'    uoCJJ/s   !D 	E 3EE__main__)rw   rz   )r   N)r
   r}   r{   r8   r   r   pathlibr   typingr   	Exceptionr   strlistr!   r   dictr>   compilerI   rP   rS   rR   rW   rc   rs   r~   r   rz   r   r   r   r   <module>r      sR     	  
  y ,3 , ,c ,G3 G49 G$s) S$s)^(< B 1
s tCy 0 %"**%jk 3 3 49 8(d3S	>2 (s (0)49 )c3h )^h-- '2 zF r   