a ì)gñ5ã@s¨ddlmZmZmZeZdZddlZddlZddl Z ddl m Z ddl mZmZddlmZddlmZmZmZmZmZGdd „d eƒZGd d „d ƒZGd d „d ƒZdS)é)Úabsolute_importÚdivisionÚprint_functiona name: junit type: aggregate short_description: write playbook output to a JUnit file. version_added: historical description: - This callback writes playbook output to a JUnit formatted XML file. - "Tasks show up in the report as follows: 'ok': pass 'failed' with 'EXPECTED FAILURE' in the task name: pass 'failed' with 'TOGGLE RESULT' in the task name: pass 'ok' with 'TOGGLE RESULT' in the task name: failure 'failed' due to an exception: error 'failed' for other reasons: failure 'skipped': skipped" options: output_dir: name: JUnit output dir default: ~/.ansible.log description: Directory to write XML files to. env: - name: JUNIT_OUTPUT_DIR task_class: name: JUnit Task class default: False description: Configure the output to be one class per yaml file env: - name: JUNIT_TASK_CLASS task_relative_path: name: JUnit Task relative path default: none description: Configure the output to use relative paths to given directory version_added: "2.8" env: - name: JUNIT_TASK_RELATIVE_PATH replace_out_of_tree_path: name: Replace out of tree path default: none description: Replace the directory portion of an out-of-tree relative task path with the given placeholder version_added: "2.12.3" env: - name: JUNIT_REPLACE_OUT_OF_TREE_PATH fail_on_change: name: JUnit fail on change default: False description: Consider any tasks reporting "changed" as a junit test failure env: - name: JUNIT_FAIL_ON_CHANGE fail_on_ignore: name: JUnit fail on ignore default: False description: Consider failed tasks as a junit test failure even if ignore_on_error is set env: - name: JUNIT_FAIL_ON_IGNORE include_setup_tasks_in_report: name: JUnit include setup tasks in report default: True description: Should the setup tasks be included in the final report env: - name: JUNIT_INCLUDE_SETUP_TASKS_IN_REPORT hide_task_arguments: name: Hide the arguments for a task default: False description: Hide the arguments for a task version_added: "2.8" env: - name: JUNIT_HIDE_TASK_ARGUMENTS test_case_prefix: name: Prefix to find actual test cases default: description: Consider a task only as test case if it has this value as prefix. Additionally failing tasks are recorded as failed test cases. version_added: "2.8" env: - name: JUNIT_TEST_CASE_PREFIX requirements: - enable in configuration N)Ú constants)Úto_bytesÚto_text)Ú CallbackBase)ÚTestCaseÚ TestErrorÚ TestFailureÚ TestSuiteÚ TestSuitescs²eZdZdZdZdZdZdZ‡fdd„Zdd „Z d d „Z d d „Z dd„Z dd„Z dd„Zdd„Zdd„Zdd„Zdd„Zdd„Zd)dd „Zd!d"„Zd#d$„Zd%d&„Zd'd(„Z‡ZS)*ÚCallbackModulea This callback writes playbook output to a JUnit formatted XML file. Tasks show up in the report as follows: 'ok': pass 'failed' with 'EXPECTED FAILURE' in the task name: pass 'failed' with 'TOGGLE RESULT' in the task name: pass 'ok' with 'TOGGLE RESULT' in the task name: failure 'failed' due to an exception: error 'failed' for other reasons: failure 'skipped': skipped This plugin makes use of the following environment variables: JUNIT_OUTPUT_DIR (optional): Directory to write XML files to. Default: ~/.ansible.log JUNIT_TASK_CLASS (optional): Configure the output to be one class per yaml file Default: False JUNIT_TASK_RELATIVE_PATH (optional): Configure the output to use relative paths to given directory Default: none JUNIT_FAIL_ON_CHANGE (optional): Consider any tasks reporting "changed" as a junit test failure Default: False JUNIT_FAIL_ON_IGNORE (optional): Consider failed tasks as a junit test failure even if ignore_on_error is set Default: False JUNIT_INCLUDE_SETUP_TASKS_IN_REPORT (optional): Should the setup tasks be included in the final report Default: True JUNIT_HIDE_TASK_ARGUMENTS (optional): Hide the arguments for a task Default: False JUNIT_TEST_CASE_PREFIX (optional): Consider a task only as test case if it has this value as prefix. Additionally failing tasks are recorded as failed test cases. Default: g@Z aggregateZjunitTcstt|ƒ ¡t dtj d¡¡|_t dd¡ ¡|_ t dd¡|_ t dd¡ ¡|_ t dd¡ ¡|_ t d d ¡ ¡|_ t d d¡ ¡|_t d d¡|_t d d¡|_d|_d|_d|_d|_d|_i|_|jdurât|jƒ|_tj |j¡süt |j¡dS)NZJUNIT_OUTPUT_DIRz~/.ansible.logZJUNIT_TASK_CLASSÚFalseZJUNIT_TASK_RELATIVE_PATHÚZJUNIT_FAIL_ON_CHANGEZJUNIT_FAIL_ON_IGNOREZ#JUNIT_INCLUDE_SETUP_TASKS_IN_REPORTÚTrueZJUNIT_HIDE_TASK_ARGUMENTSZJUNIT_TEST_CASE_PREFIXZJUNIT_REPLACE_OUT_OF_TREE_PATHF)ÚsuperrÚ__init__ÚosÚgetenvÚpathÚ expanduserÚ _output_dirÚlowerÚ _task_classÚ_task_relative_pathÚ_fail_on_changeÚ_fail_on_ignoreÚ_include_setup_tasks_in_reportÚ_hide_task_argumentsÚ_test_case_prefixÚ_replace_out_of_tree_pathÚ_playbook_pathÚ_playbook_nameÚ _play_nameÚ _task_dataZdisabledrÚexistsÚmakedirs)Úself©Ú __class__©úB/usr/lib/python3.9/site-packages/ansible/plugins/callback/junit.pyrŒs(  zCallbackModule.__init__cCsˆ|j}||jvrdS|j}| ¡ ¡}| ¡}|j}|jsn|jdkrnd  dd„|j   ¡Dƒ¡}|rn|d|7}t |||||ƒ|j|<dS)z2 record the start of a task for one or more hosts NÚfalsez, css|]}d|VqdS)z%s=%sNr+)Ú.0Úar+r+r,Ú µóz-CallbackModule._start_task..ú ) Ú_uuidr%r$Úget_nameÚstripZget_pathÚactionZno_logrÚjoinÚargsÚitemsÚTaskData)r(ÚtaskÚuuidÚplayÚnamerr6r8r+r+r,Ú _start_task§s   zCallbackModule._start_taskcCsÄ|jj}t|dƒr$|jj}|jj}nd}d}|j|}|jdkrZ|dkrZ|j dd¡rZd}|dkrrd|jvrrd}n$d |jvr–|dkrŠd}n |dkr–d}|j  |j ¡s¬|dkrÀ|  t ||||ƒ¡d S) z0 record the results of a task for a single host Ú_hostZincludeÚtrueÚokZchangedFÚfailedzEXPECTED FAILUREz TOGGLE RESULTN) Z_taskr3Úhasattrr@r>r%rÚ_resultÚgetÚ startswithr Úadd_hostÚHostData)r(ÚstatusÚresultÚ task_uuidÚ host_uuidZ host_nameÚ task_datar+r+r,Ú _finish_task»s$     zCallbackModule._finish_taskc CsÆd|j|j|jf}|j|j}|jrL|jrLttj t |jƒt |jƒ¡ƒ}n|j}|j dur€|  d¡r€|j ttj  t |ƒ¡ƒ}|j dkr˜t dd|¡}|jdkr¸t|||t|jƒdS|jj}| d d ¡}|j|d d }| |¡}|jd krþt||||dSt|||d } |jdkr˜d|vrV|d ¡ d¡d} |d} | j t| | d¡n@d|vr~|d} | j t| |d¡n| j td||d¡n*|jdkrÂd|vr¸|d} nd} | | _| S)z7 build a TestCase from the given TaskData and HostData z [%s] %s: %sNz../rAz \.yml:[0-9]+$rÚincluded)r>Ú classnameÚtimeZ system_outÚrcr)ÚindentrB)r>rQrRrCÚ exceptionÚ éÿÿÿÿ)ÚmessageÚoutputÚmsgzrc=%sÚskippedZ skip_reason) r>r=ÚfinishÚstartrrrrÚrelpathrr!rGÚbasenamerÚreÚsubrJr ÚstrrKrErFZ _dump_resultsÚ_cleanse_stringr5ÚsplitÚerrorsÚappendr Zfailuresr r[) r(rNÚ host_datar>ZdurationZjunit_classnameÚresrSÚdumpZ test_caserXrYr+r+r,Ú_build_test_caseØsB              zCallbackModule._build_test_casecCstt|ddddS)z] convert surrogate escapes to the unicode replacement character to avoid XML encoding errors Úsurrogateescape©reÚreplace)rr)r(Úvaluer+r+r,rc szCallbackModule._cleanse_stringc CsÖg}|j ¡D]F\}}|jtjvr.|jdkr.q|j ¡D]\}}| | ||¡¡q8qt |j |d}t |gd}|  ¡}t j |jd|j t ¡f¡} t| dƒ"} |  t|dd¡Wdƒn1sÈ0YdS) zF generate a TestSuite report from the collected TaskData and HostData r-)r>Zcases)Zsuitesz %s-%s.xmlÚwbZsurrogate_or_strictrlN)r%r9r6ÚCZ _ACTION_SETUPrrgrfrjr r#r Z to_pretty_xmlrrr7rrRÚopenÚwriter) r(Z test_casesrLrNrMrgZ test_suiteZ test_suitesÚreportZ output_fileZxmlr+r+r,Ú_generate_report s  zCallbackModule._generate_reportcCs(|j|_tj tj |j¡¡d|_dS)Nr)Z _file_namer"rrÚsplitextr_r#)r(Zplaybookr+r+r,Úv2_playbook_on_start"sz#CallbackModule.v2_playbook_on_startcCs| ¡|_dS©N)r4r$)r(r=r+r+r,Úv2_playbook_on_play_start&sz(CallbackModule.v2_playbook_on_play_startcCs| |¡dSrw©r?©r(r;r+r+r,Úv2_runner_on_no_hosts)sz$CallbackModule.v2_runner_on_no_hostscCs| |¡dSrwry)r(r;Zis_conditionalr+r+r,Úv2_playbook_on_task_start,sz(CallbackModule.v2_playbook_on_task_startcCs| |¡dSrwryrzr+r+r,Ú!v2_playbook_on_cleanup_task_start/sz0CallbackModule.v2_playbook_on_cleanup_task_startcCs| |¡dSrwryrzr+r+r,Ú!v2_playbook_on_handler_task_start2sz0CallbackModule.v2_playbook_on_handler_task_startFcCs,|r|jdkr| d|¡n | d|¡dS)NrArBrC)rrO)r(rKÚ ignore_errorsr+r+r,Úv2_runner_on_failed5sz"CallbackModule.v2_runner_on_failedcCs| d|¡dS)NrB©rO©r(rKr+r+r,Úv2_runner_on_ok;szCallbackModule.v2_runner_on_okcCs| d|¡dS)Nr[rr‚r+r+r,Úv2_runner_on_skipped>sz#CallbackModule.v2_runner_on_skippedcCs| d|¡dS)NrPr)r(Z included_filer+r+r,Úv2_playbook_on_includeAsz%CallbackModule.v2_playbook_on_includecCs | ¡dSrw)rt)r(Zstatsr+r+r,Úv2_playbook_on_statsDsz#CallbackModule.v2_playbook_on_stats)F)Ú__name__Ú __module__Ú __qualname__Ú__doc__ZCALLBACK_VERSIONZ CALLBACK_TYPEZ CALLBACK_NAMEZCALLBACK_NEEDS_ENABLEDrr?rOrjrcrtrvrxr{r|r}r~r€rƒr„r…r†Ú __classcell__r+r+r)r,rfs,  1 rc@s eZdZdZdd„Zdd„ZdS)r:z( Data about an individual task. cCs8||_||_||_||_d|_i|_t ¡|_||_dSrw)r<r>rr=r]rgrRr6)r(r<r>rr=r6r+r+r,rMs zTaskData.__init__cCs^|j|jvrN|jdkr2d|j|jj|jf|_ntd|j|j|j|jfƒ‚||j|j<dS)NrPz%s %sz'%s: %s: %s: duplicate host callback: %s)r<rgrJrKÚ Exceptionrr=r>)r(Úhostr+r+r,rHWs   zTaskData.add_hostN)r‡rˆr‰rŠrrHr+r+r+r,r:Hs r:c@seZdZdZdd„ZdS)rIz( Data about an individual host. cCs&||_||_||_||_t ¡|_dSrw)r<r>rJrKrRr\)r(r<r>rJrKr+r+r,rgs zHostData.__init__N)r‡rˆr‰rŠrr+r+r+r,rIbsrI)Z __future__rrrÚtypeZ __metaclass__Z DOCUMENTATIONrrRr`ZansiblerrpZansible.module_utils._textrrZansible.plugins.callbackrZansible.utils._junit_xmlr r r r r rr:rIr+r+r+r,ÚsN   c