├── LICENSE ├── README ├── sh2ju.sh ├── sh2ju_example.sh └── shell2junit-1.0.0.zip /LICENSE: -------------------------------------------------------------------------------- 1 | Shell2Junit License Information 2 | 3 | Feb, 2010 4 | 5 | shell2junit library and sample code is licensed under Apache License, v.2.0. 6 | 7 | (c) 2009 Manolo Carrasco (Manuel Carrasco Moñino) 8 | 9 | ===== 10 | 11 | Apache License 12 | Version 2.0, January 2004 13 | http://www.apache.org/licenses/ 14 | 15 | 1. Definitions. 16 | 17 | "License" shall mean the terms and conditions for use, reproduction, and 18 | distribution as defined by Sections 1 through 9 of this document. 19 | 20 | "Licensor" shall mean the copyright owner or entity authorized by the 21 | copyright owner that is granting the License. 22 | 23 | "Legal Entity" shall mean the union of the acting entity and all other 24 | entities that control, are controlled by, or are under common control with 25 | that entity. For the purposes of this definition, "control" means (i) the 26 | power, direct or indirect, to cause the direction or management of such 27 | entity, whether by contract or otherwise, or (ii) ownership of fifty percent 28 | (50%) or more of the outstanding shares, or (iii) beneficial ownership of 29 | such entity. 30 | 31 | "You" (or "Your") shall mean an individual or Legal Entity exercising 32 | permissions granted by this License. 33 | 34 | "Source" form shall mean the preferred form for making modifications, 35 | including but not limited to software source code, documentation source, and 36 | configuration files. 37 | 38 | "Object" form shall mean any form resulting from mechanical transformation 39 | or translation of a Source form, including but not limited to compiled 40 | object code, generated documentation, and conversions to other media types. 41 | 42 | "Work" shall mean the work of authorship, whether in Source or Object form, 43 | made available under the License, as indicated by a copyright notice that is 44 | included in or attached to the work (an example is provided in the Appendix 45 | below). 46 | 47 | "Derivative Works" shall mean any work, whether in Source or Object form, 48 | that is based on (or derived from) the Work and for which the editorial 49 | revisions, annotations, elaborations, or other modifications represent, as a 50 | whole, an original work of authorship. For the purposes of this License, 51 | Derivative Works shall not include works that remain separable from, or 52 | merely link (or bind by name) to the interfaces of, the Work and Derivative 53 | Works thereof. 54 | 55 | "Contribution" shall mean any work of authorship, including the original 56 | version of the Work and any modifications or additions to that Work or 57 | Derivative Works thereof, that is intentionally submitted to Licensor for 58 | inclusion in the Work by the copyright owner or by an individual or Legal 59 | Entity authorized to submit on behalf of the copyright owner. For the 60 | purposes of this definition, "submitted" means any form of electronic, 61 | verbal, or written communication sent to the Licensor or its 62 | representatives, including but not limited to communication on electronic 63 | mailing lists, source code control systems, and issue tracking systems that 64 | are managed by, or on behalf of, the Licensor for the purpose of discussing 65 | and improving the Work, but excluding communication that is conspicuously 66 | marked or otherwise designated in writing by the copyright owner as "Not a 67 | Contribution." 68 | 69 | "Contributor" shall mean Licensor and any individual or Legal Entity on 70 | behalf of whom a Contribution has been received by Licensor and subsequently 71 | incorporated within the Work. 72 | 73 | 2. Grant of Copyright License. Subject to the terms and conditions of this 74 | License, each Contributor hereby grants to You a perpetual, worldwide, 75 | non-exclusive, no-charge, royalty-free, irrevocable copyright license to 76 | reproduce, prepare Derivative Works of, publicly display, publicly perform, 77 | sublicense, and distribute the Work and such Derivative Works in Source or 78 | Object form. 79 | 80 | 3. Grant of Patent License. Subject to the terms and conditions of this 81 | License, each Contributor hereby grants to You a perpetual, worldwide, 82 | non-exclusive, no-charge, royalty-free, irrevocable (except as stated in 83 | this section) patent license to make, have made, use, offer to sell, sell, 84 | import, and otherwise transfer the Work, where such license applies only to 85 | those patent claims licensable by such Contributor that are necessarily 86 | infringed by their Contribution(s) alone or by combination of their 87 | Contribution(s) with the Work to which such Contribution(s) was submitted. 88 | If You institute patent litigation against any entity (including a 89 | cross-claim or counterclaim in a lawsuit) alleging that the Work or a 90 | Contribution incorporated within the Work constitutes direct or contributory 91 | patent infringement, then any patent licenses granted to You under this 92 | License for that Work shall terminate as of the date such litigation is 93 | filed. 94 | 95 | 4. Redistribution. You may reproduce and distribute copies of the Work or 96 | Derivative Works thereof in any medium, with or without modifications, and 97 | in Source or Object form, provided that You meet the following conditions: 98 | 99 | a. You must give any other recipients of the Work or Derivative Works a copy 100 | of this License; and 101 | 102 | b. You must cause any modified files to carry prominent notices stating that 103 | You changed the files; and 104 | 105 | c. You must retain, in the Source form of any Derivative Works that You 106 | distribute, all copyright, patent, trademark, and attribution notices from 107 | the Source form of the Work, excluding those notices that do not pertain to 108 | any part of the Derivative Works; and 109 | 110 | d. If the Work includes a "NOTICE" text file as part of its distribution, 111 | then any Derivative Works that You distribute must include a readable copy 112 | of the attribution notices contained within such NOTICE file, excluding 113 | those notices that do not pertain to any part of the Derivative Works, in at 114 | least one of the following places: within a NOTICE text file distributed as 115 | part of the Derivative Works; within the Source form or documentation, if 116 | provided along with the Derivative Works; or, within a display generated by 117 | the Derivative Works, if and wherever such third-party notices normally 118 | appear. The contents of the NOTICE file are for informational purposes only 119 | and do not modify the License. You may add Your own attribution notices 120 | within Derivative Works that You distribute, alongside or as an addendum to 121 | the NOTICE text from the Work, provided that such additional attribution 122 | notices cannot be construed as modifying the License. 123 | 124 | You may add Your own copyright statement to Your modifications and may 125 | provide additional or different license terms and conditions for use, 126 | reproduction, or distribution of Your modifications, or for any such 127 | Derivative Works as a whole, provided Your use, reproduction, and 128 | distribution of the Work otherwise complies with the conditions stated in 129 | this License. 130 | 131 | 5. Submission of Contributions. Unless You explicitly state otherwise, any 132 | Contribution intentionally submitted for inclusion in the Work by You to the 133 | Licensor shall be under the terms and conditions of this License, without 134 | any additional terms or conditions. Notwithstanding the above, nothing 135 | herein shall supersede or modify the terms of any separate license agreement 136 | you may have executed with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, except 140 | as required for reasonable and customary use in describing the origin of the 141 | Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in 144 | writing, Licensor provides the Work (and each Contributor provides its 145 | Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 146 | KIND, either express or implied, including, without limitation, any 147 | warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or 148 | FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining 149 | the appropriateness of using or redistributing the Work and assume any risks 150 | associated with Your exercise of permissions under this License. 151 | 152 | 8. Limitation of Liability. In no event and under no legal theory, whether 153 | in tort (including negligence), contract, or otherwise, unless required by 154 | applicable law (such as deliberate and grossly negligent acts) or agreed to 155 | in writing, shall any Contributor be liable to You for damages, including 156 | any direct, indirect, special, incidental, or consequential damages of any 157 | character arising as a result of this License or out of the use or inability 158 | to use the Work (including but not limited to damages for loss of goodwill, 159 | work stoppage, computer failure or malfunction, or any and all other 160 | commercial damages or losses), even if such Contributor has been advised of 161 | the possibility of such damages. 162 | 163 | 9. Accepting Warranty or Additional Liability. While redistributing the Work 164 | or Derivative Works thereof, You may choose to offer, and charge a fee for, 165 | acceptance of support, warranty, indemnity, or other liability obligations 166 | and/or rights consistent with this License. However, in accepting such 167 | obligations, You may act only on Your own behalf and on Your sole 168 | responsibility, not on behalf of any other Contributor, and only if You 169 | agree to indemnify, defend, and hold each Contributor harmless for any 170 | liability incurred by, or claims asserted against, such Contributor by 171 | reason of your accepting any such warranty or additional liability. 172 | 173 | -------------------------------------------------------------------------------- /README: -------------------------------------------------------------------------------- 1 | - Shell2junit is a simple utility which facilitates to generate junit reports for batch processes executed in shell scripts. 2 | - The reports can be easily parsed in Jenkins and other CI software in order to monitor and generate trends and alerts. 3 | - This page[1] teaches how to do it in Jenkins. 4 | 5 | [1] http://manolocarrasco.blogspot.com/2010/02/hudson-publish-bach.html 6 | -------------------------------------------------------------------------------- /sh2ju.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | ### Copyright 2010 Manuel Carrasco Moñino. (manolo at apache.org) 3 | ### 4 | ### Licensed under the Apache License, Version 2.0. 5 | ### You may obtain a copy of it at 6 | ### http://www.apache.org/licenses/LICENSE-2.0 7 | 8 | ### 9 | ### A library for shell scripts which creates reports in jUnit format. 10 | ### These reports can be used in Jenkins, or any other CI. 11 | ### 12 | ### Usage: 13 | ### - Include this file in your shell script 14 | ### - Use juLog to call your command any time you want to produce a new report 15 | ### Usage: juLog command arguments 16 | ### options: 17 | ### -class="MyClass" : a class name which will be shown in the junit report 18 | ### -name="TestName" : the test name which will be shown in the junit report 19 | ### -error="RegExp" : a regexp which sets the test as failure when the output matches it 20 | ### -ierror="RegExp" : same as -error but case insensitive 21 | ### - Junit reports are left in the folder 'result' under the directory where the script is executed. 22 | ### - Configure Jenkins to parse junit files from the generated folder 23 | ### 24 | 25 | asserts=00; errors=0; total=0; content="" 26 | date=`which gdate 2>/dev/null || which date` 27 | 28 | # create output folder 29 | juDIR=`pwd`/results 30 | mkdir -p "$juDIR" || exit 31 | 32 | # The name of the suite is calculated based in your script name 33 | suite="" 34 | 35 | # A wrapper for the eval method witch allows catching seg-faults and use tee 36 | errfile=/tmp/evErr.$$.log 37 | eVal() { 38 | eval "$1" 39 | # stdout and stderr may currently be inverted (see below) so echo may write to stderr 40 | echo $? 2>&1 | tr -d "\n" > $errfile 41 | } 42 | 43 | # Method to clean old tests 44 | juLogClean() { 45 | echo "+++ Removing old junit reports from: $juDIR " 46 | rm -f "$juDIR"/TEST-* 47 | } 48 | 49 | # Execute a command and record its results 50 | juLog() { 51 | suite=""; 52 | errfile=/tmp/evErr.$$.log 53 | date=`which gdate 2>/dev/null || which date` 54 | asserts=00; errors=0; total=0; content="" 55 | 56 | # parse arguments 57 | ya=""; icase="" 58 | while [ -z "$ya" ]; do 59 | case "$1" in 60 | -name=*) name=`echo "$1" | sed -e 's/-name=//'`; shift;; 61 | -class=*) class=`echo "$1" | sed -e 's/-class=//'`; shift;; 62 | -ierror=*) ereg=`echo "$1" | sed -e 's/-ierror=//'`; icase="-i"; shift;; 63 | -error=*) ereg=`echo "$1" | sed -e 's/-error=//'`; shift;; 64 | *) ya=1;; 65 | esac 66 | done 67 | 68 | # use first arg as name if it was not given 69 | if [ -z "$name" ]; then 70 | name="$asserts-$1" 71 | shift 72 | fi 73 | 74 | if [[ "$class" = "" ]]; then 75 | class="default" 76 | fi 77 | 78 | echo "name is: $name" 79 | echo "class is: $class" 80 | 81 | suite=$class 82 | 83 | # calculate command to eval 84 | [ -z "$1" ] && return 85 | cmd="$1"; shift 86 | while [ -n "$1" ] 87 | do 88 | cmd="$cmd \"$1\"" 89 | shift 90 | done 91 | 92 | # eval the command sending output to a file 93 | outf=/var/tmp/ju$$.txt 94 | errf=/var/tmp/ju$$-err.txt 95 | >$outf 96 | echo "" | tee -a $outf 97 | echo "+++ Running case: $class.$name " | tee -a $outf 98 | echo "+++ working dir: "`pwd` | tee -a $outf 99 | echo "+++ command: $cmd" | tee -a $outf 100 | ini=`$date +%s.%N` 101 | # execute the command, temporarily swapping stderr and stdout so they can be tee'd to separate files, 102 | # then swapping them back again so that the streams are written correctly for the invoking process 103 | ((eVal "$cmd" | tee -a $outf) 3>&1 1>&2 2>&3 | tee $errf) 3>&1 1>&2 2>&3 104 | evErr=`cat $errfile` 105 | rm -f $errfile 106 | end=`$date +%s.%N` 107 | echo "+++ exit code: $evErr" | tee -a $outf 108 | 109 | # set the appropriate error, based in the exit code and the regex 110 | [ $evErr != 0 ] && err=1 || err=0 111 | out=`cat $outf | sed -e 's/^\([^+]\)/| \1/g'` 112 | if [ $err = 0 -a -n "$ereg" ]; then 113 | H=`echo "$out" | egrep $icase "$ereg"` 114 | [ -n "$H" ] && err=1 115 | fi 116 | echo "+++ error: $err" | tee -a $outf 117 | rm -f $outf 118 | 119 | errMsg=`cat $errf` 120 | rm -f $errf 121 | # calculate vars 122 | asserts=`expr $asserts + 1` 123 | errors=`expr $errors + $err` 124 | time=`echo "$end - $ini" | bc -l` 125 | total=`echo "$total + $time" | bc -l` 126 | 127 | # write the junit xml report 128 | ## failure tag 129 | [ $err = 0 ] && failure="" || failure=" 130 | 131 | " 132 | ## testcase tag 133 | content="$content 134 | 135 | $failure 136 | 137 | 140 | 141 | 142 | 145 | 146 | 147 | " 148 | ## testsuite block 149 | 150 | if [[ -e "$juDIR/TEST-$suite.xml" ]]; then 151 | 152 | # file exists. Need to append to it. If we remove the testsuite end tag, we can just add it in after. 153 | sed -i "s^^^g" $juDIR/TEST-$suite.xml ## remove testSuite so we can add it later 154 | cat <> "$juDIR/TEST-$suite.xml" 155 | $content 156 | 157 | EOF 158 | 159 | else 160 | # no file exists. Adding a new file 161 | cat < "$juDIR/TEST-$suite.xml" 162 | 163 | $content 164 | 165 | EOF 166 | fi 167 | 168 | } 169 | 170 | -------------------------------------------------------------------------------- /sh2ju_example.sh: -------------------------------------------------------------------------------- 1 | #/bin/sh 2 | 3 | #### Include the library 4 | . `dirname $0`/sh2ju.sh 5 | 6 | #### Clean old reports 7 | juLogClean 8 | 9 | #### Success command 10 | juLog -name=myTrueCommand true 11 | 12 | #### Failure 13 | juLog -name=myFalseCommand false 14 | 15 | #### Sleep 16 | juLog -name=mySleepCommand sleep 5 17 | 18 | #### The test fails because the word 'world' is found in command output 19 | juLog -name=myErrorCommand -ierror=world echo Hello World 20 | 21 | #### A sql command 22 | juLog -name=mySqlCommand psql -h localhost -U postgres -c 'select now()' 23 | 24 | #### A call to a customized method 25 | myCmd() { 26 | ls -l $* 27 | return 0 28 | } 29 | 30 | juLog -name=myCustomizedMethod myCmd '*.sh' 31 | 32 | #### Success command with a class defined 33 | juLog -name=myTrueCommand -class=TestFunctionality true 34 | 35 | 36 | -------------------------------------------------------------------------------- /shell2junit-1.0.0.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/manolo/shell2junit/9168abaf4366b115528498bc025179bec5ed75b0/shell2junit-1.0.0.zip --------------------------------------------------------------------------------