generateHtmlReport.py 41.4 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
#/*
# * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
# * contributor license agreements.  See the NOTICE file distributed with
# * this work for additional information regarding copyright ownership.
# * The OpenAirInterface Software Alliance licenses this file to You under
# * the OAI Public License, Version 1.1  (the "License"); you may not use this file
# * except in compliance with the License.
# * You may obtain a copy of the License at
# *
# *	  http://www.openairinterface.org/?page_id=698
# *
# * Unless required by applicable law or agreed to in writing, software
# * distributed under the License is distributed on an "AS IS" BASIS,
# * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# * See the License for the specific language governing permissions and
# * limitations under the License.
# *-------------------------------------------------------------------------------
# * For more information about the OpenAirInterface (OAI) Software Alliance:
# *	  contact@openairinterface.org
# */
#---------------------------------------------------------------------

23
import glob
24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78
import os
import re
import sys
import subprocess

class HtmlReport():
	def __init__(self):
		self.job_name = ''
		self.job_id = ''
		self.job_url = ''
		self.job_start_time = 'TEMPLATE_TIME'
		self.git_url = ''
		self.git_src_branch = ''
		self.git_src_commit = ''
		self.git_src_commit_msg = None
		self.git_pull_request = False
		self.git_target_branch = ''
		self.git_target_commit = ''
		self.nb_warnings = 0
		self.warning_rows = ''

	def generate(self):
		cwd = os.getcwd()
		self.file = open(cwd + '/test_results_oai_amf.html', 'w')
		self.generateHeader()

		self.coding_formatting_log()

		self.analyze_sca_log()

		self.buildSummaryHeader()
		self.initialGitSetup()
		self.installLibsPackagesRow()
		self.buildCompileRows()
		self.copyToTargetImage()
		self.copyConfToolsToTargetImage()
		self.imageSizeRow()
		self.buildSummaryFooter()

		self.generateFooter()
		self.file.close()

	def generateHeader(self):
		# HTML Header
		self.file.write('<!DOCTYPE html>\n')
		self.file.write('<html class="no-js" lang="en-US">\n')
		self.file.write('<head>\n')
		self.file.write('  <meta name="viewport" content="width=device-width, initial-scale=1">\n')
		self.file.write('  <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css">\n')
		self.file.write('  <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>\n')
		self.file.write('  <script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js"></script>\n')
		self.file.write('  <title>OAI Core Network Test Results for ' + self.job_name + ' job build #' + self.job_id + '</title>\n')
		self.file.write('</head>\n')
		self.file.write('<body><div class="container">\n')
		self.file.write('  <table width = "100%" style="border-collapse: collapse; border: none;">\n')
ismail's avatar
ismail committed
79 80 81 82 83 84 85 86 87 88 89
		self.file.write('   <tr style="border-collapse: collapse; border: none;">\n')
		self.file.write('     <td style="border-collapse: collapse; border: none;">\n')
		self.file.write('       <a href="http://www.openairinterface.org/">\n')
		self.file.write('          <img src="http://www.openairinterface.org/wp-content/uploads/2016/03/cropped-oai_final_logo2.png" alt="" border="none" height=50 width=150>\n')
		self.file.write('          </img>\n')
		self.file.write('        </a>\n')
		self.file.write('      </td>\n')
		self.file.write('      <td style="border-collapse: collapse; border: none; vertical-align: center;">\n')
		self.file.write('        <b><font size = "6">Job Summary -- Job: ' + self.job_name + ' -- Build-ID: <a href="' + self.job_url + '">' + self.job_id + '</a></font></b>\n')
		self.file.write('      </td>\n')
		self.file.write('    </tr>\n')
90 91 92 93
		self.file.write('  </table>\n')
		self.file.write('  <br>\n')

		# Build Info Summary
94 95
		buildSummary = ''
		buildSummary += '  <table class="table-bordered" width = "80%" align = "center" border = "1">\n'
ismail's avatar
ismail committed
96 97
		buildSummary += '    <tr>\n'
		buildSummary += '      <td bgcolor="lightcyan" > <span class="glyphicon glyphicon-time"></span> Build Start Time</td>\n'
98
		#date_formatted = re.sub('\..*', '', self.created)
ismail's avatar
ismail committed
99 100 101 102
		buildSummary += '      <td>' + self.job_start_time + '</td>\n'
		buildSummary += '    </tr>\n'
		buildSummary += '    <tr>\n'
		buildSummary += '      <td bgcolor="lightcyan" > <span class="glyphicon glyphicon-wrench"></span> Build Trigger</td>\n'
103
		if self.git_pull_request:
ismail's avatar
ismail committed
104
			buildSummary += '      <td>Pull Request</td>\n'
105
		else:
ismail's avatar
ismail committed
106 107 108 109 110 111
			buildSummary += '      <td>Push Event</td>\n'
		buildSummary += '    </tr>\n'
		buildSummary += '    <tr>\n'
		buildSummary += '      <td bgcolor="lightcyan" > <span class="glyphicon glyphicon-cloud-upload"></span> GIT Repository</td>\n'
		buildSummary += '      <td><a href="' + self.git_url + '">' + self.git_url + '</a></td>\n'
		buildSummary += '    </tr>\n'
112
		if self.git_pull_request:
113
			buildSummary += '	 <tr>\n'
Raphael Defosseux's avatar
Raphael Defosseux committed
114
			buildSummary += '      <td bgcolor="lightcyan" > <span class="glyphicon glyphicon-log-out"></span> Merge Request URL</td>\n'
115 116 117 118 119 120 121 122
			buildSummary += '	   <td><a href="TEMPLATE_MERGE_REQUEST_LINK">TEMPLATE_MERGE_REQUEST_LINK</a></td>\n'
			buildSummary += '	 </tr>\n'
			buildSummary += '	 <tr>\n'
			buildSummary += '	   <td bgcolor="lightcyan" > <span class="glyphicon glyphicon-header"></span> Merge Request Title</td>\n'
			buildSummary += '	   <td>TEMPLATE_MERGE_REQUEST_TEMPLATE</td>\n'
			buildSummary += '	 </tr>\n'
			buildSummary += '	 <tr>\n'
			buildSummary += '	   <td bgcolor="lightcyan" > <span class="glyphicon glyphicon-log-out"></span> Source Branch</td>\n'
ismail's avatar
ismail committed
123 124 125 126 127 128
			buildSummary += '      <td>' + self.git_src_branch + '</td>\n'
			buildSummary += '    </tr>\n'
			buildSummary += '    <tr>\n'
			buildSummary += '      <td bgcolor="lightcyan" > <span class="glyphicon glyphicon-tag"></span> Source Commit ID</td>\n'
			buildSummary += '      <td>' + self.git_src_commit + '</td>\n'
			buildSummary += '    </tr>\n'
129
			if (self.git_src_commit_msg is not None):
ismail's avatar
ismail committed
130 131 132 133 134 135 136 137 138 139 140 141
				buildSummary += '    <tr>\n'
				buildSummary += '      <td bgcolor="lightcyan" > <span class="glyphicon glyphicon-comment"></span> Source Commit Message</td>\n'
				buildSummary += '      <td>' + self.git_src_commit_msg + '</td>\n'
				buildSummary += '    </tr>\n'
			buildSummary += '    <tr>\n'
			buildSummary += '      <td bgcolor="lightcyan" > <span class="glyphicon glyphicon-log-in"></span> Target Branch</td>\n'
			buildSummary += '      <td>' + self.git_target_branch + '</td>\n'
			buildSummary += '    </tr>\n'
			buildSummary += '    <tr>\n'
			buildSummary += '      <td bgcolor="lightcyan" > <span class="glyphicon glyphicon-tag"></span> Target Commit ID</td>\n'
			buildSummary += '      <td>' + self.git_target_commit + '</td>\n'
			buildSummary += '    </tr>\n'
142
		else:
ismail's avatar
ismail committed
143 144 145 146 147 148 149 150
			buildSummary += '    <tr>\n'
			buildSummary += '      <td bgcolor="lightcyan" > <span class="glyphicon glyphicon-tree-deciduous"></span> Branch</td>\n'
			buildSummary += '      <td>' + self.git_src_branch + '</td>\n'
			buildSummary += '    </tr>\n'
			buildSummary += '    <tr>\n'
			buildSummary += '      <td bgcolor="lightcyan" > <span class="glyphicon glyphicon-tag"></span> Commit ID</td>\n'
			buildSummary += '      <td>' + self.git_src_commit + '</td>\n'
			buildSummary += '    </tr>\n'
151
			if (self.git_src_commit_msg is not None):
ismail's avatar
ismail committed
152 153 154 155
				buildSummary += '    <tr>\n'
				buildSummary += '      <td bgcolor="lightcyan" > <span class="glyphicon glyphicon-comment"></span> Commit Message</td>\n'
				buildSummary += '      <td>' + self.git_src_commit_msg + '</td>\n'
				buildSummary += '    </tr>\n'
156 157 158 159 160
		buildSummary += '  </table>\n'
		buildSummary += '  <br>\n'
		self.file.write(buildSummary)

		cwd = os.getcwd()
161 162 163
		for reportFile in glob.glob('./*results_oai_*.html'):
			if reportFile == './test_results_oai_amf.html':
				continue
164
			newEpcReport = open(cwd + '/' + str(reportFile) + '.new', 'w')
165
			buildSummaryDone = True
Raphael Defosseux's avatar
Raphael Defosseux committed
166
			with open(cwd + '/' + str(reportFile), 'r') as originalEpcReport:
167
				for line in originalEpcReport:
168
					result = re.search('Deployment Summary', line)
169 170 171 172 173 174
					if (result is not None) and buildSummaryDone:
						newEpcReport.write(buildSummary)
						buildSummaryDone = False
					newEpcReport.write(line)
				originalEpcReport.close()
			newEpcReport.close()
175
			os.rename(cwd + '/' + str(reportFile) + '.new', cwd + '/' + str(reportFile))
176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197

	def generateFooter(self):
		self.file.write('  <div class="well well-lg">End of Build Report -- Copyright <span class="glyphicon glyphicon-copyright-mark"></span> 2020 <a href="http://www.openairinterface.org/">OpenAirInterface</a>. All Rights Reserved.</div>\n')
		self.file.write('</div></body>\n')
		self.file.write('</html>\n')

	def coding_formatting_log(self):
		cwd = os.getcwd()
		self.file.write('  <h2>OAI Coding / Formatting Guidelines Check</h2>\n')
		if os.path.isfile(cwd + '/src/oai_rules_result.txt'):
			cmd = 'grep NB_FILES_FAILING_CHECK ' + cwd + '/src/oai_rules_result.txt | sed -e "s#NB_FILES_FAILING_CHECK=##"'
			nb_fail = subprocess.check_output(cmd, shell=True, universal_newlines=True)
			cmd = 'grep NB_FILES_CHECKED ' + cwd + '/src/oai_rules_result.txt | sed -e "s#NB_FILES_CHECKED=##"'
			nb_total = subprocess.check_output(cmd, shell=True, universal_newlines=True)
			if int(nb_fail.strip()) == 0:
				self.file.write('  <div class="alert alert-success">\n')
				if self.git_pull_request:
					self.file.write('    <strong>All modified files in Pull-Request follow OAI rules. <span class="glyphicon glyphicon-ok-circle"></span> -> (' + nb_total.strip() + ' were checked)</strong>\n')
				else:
					self.file.write('    <strong>All files in repository follow OAI rules. <span class="glyphicon glyphicon-ok-circle"></span> -> (' + nb_total.strip() + ' were checked)</strong>\n')
				self.file.write('  </div>\n')
			else:
198
				self.file.write('  <div class="alert alert-danger">\n')
199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219
				if self.git_pull_request:
					self.file.write('    <strong>' + nb_fail.strip() + ' modified files in Pull-Request DO NOT follow OAI rules. <span class="glyphicon glyphicon-warning-sign"></span> -> (' + nb_total.strip() + ' were checked)</strong>\n')
				else:
					self.file.write('    <strong>' + nb_fail.strip() + ' files in repository DO NOT follow OAI rules. <span class="glyphicon glyphicon-warning-sign"></span> -> (' + nb_total.strip() + ' were checked)</strong>\n')
				self.file.write('  </div>\n')

				if os.path.isfile(cwd + '/src/oai_rules_result_list.txt'):
					self.file.write('  <button data-toggle="collapse" data-target="#oai-formatting-details">More details on formatting check</button>\n')
					self.file.write('  <div id="oai-formatting-details" class="collapse">\n')
					self.file.write('  <p>Please apply the following command to this(ese) file(s): </p>\n')
					self.file.write('  <p style="margin-left: 30px"><strong><code>cd src && clang-format -i filename(s)</code></strong></p>\n')
					self.file.write('  <table class="table-bordered" width = "60%" align = "center" border = 1>\n')
					self.file.write('    <tr><th bgcolor = "lightcyan" >Filename</th></tr>\n')
					with open(cwd + '/src/oai_rules_result_list.txt', 'r') as filelist:
						for line in filelist:
							self.file.write('    <tr><td>' + line.strip() + '</td></tr>\n')
						filelist.close()
					self.file.write('  </table>\n')
					self.file.write('  </div>\n')
		else:
			self.file.write('  <div class="alert alert-danger">\n')
ismail's avatar
ismail committed
220
			self.file.write('     <strong>Was NOT performed (with CLANG-FORMAT tool). <span class="glyphicon glyphicon-ban-circle"></span></strong>\n')
221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278
			self.file.write('  </div>\n')

		self.file.write('  <br>\n')

	def analyze_sca_log(self):
		cwd = os.getcwd()
		if os.path.isfile(cwd + '/archives/cppcheck_build.log'):
			self.file.write('  <h2>Static Code Analysis</h2>\n')
		if os.path.isfile(cwd + '/archives/cppcheck.xml'):
			nb_errors = 0
			nb_warnings = 0
			nb_uninitvar = 0
			nb_uninitStructMember = 0
			nb_memleak = 0
			nb_doubleFree = 0
			nb_resourceLeak = 0
			nb_nullPointer = 0
			nb_arrayIndexOutOfBounds = 0
			nb_bufferAccessOutOfBounds = 0
			nb_unknownEvaluationOrder = 0
			with open(cwd + '/archives/cppcheck.xml', 'r') as xmlfile:
				for line in xmlfile:
					result = re.search('severity="warning"', line)
					if result is not None:
						nb_warnings += 1
					result = re.search('severity="error"', line)
					if result is not None:
						nb_errors += 1
						result = re.search('uninitvar', line)
						if result is not None:
							nb_uninitvar += 1
						result = re.search('uninitStructMember', line)
						if result is not None:
							nb_uninitStructMember += 1
						result = re.search('memleak', line)
						if result is not None:
							nb_memleak += 1
						result = re.search('doubleFree', line)
						if result is not None:
							nb_doubleFree += 1
						result = re.search('resourceLeak', line)
						if result is not None:
							nb_resourceLeak += 1
						result = re.search('nullPointer', line)
						if result is not None:
							nb_nullPointer += 1
						result = re.search('arrayIndexOutOfBounds', line)
						if result is not None:
							nb_arrayIndexOutOfBounds += 1
						result = re.search('bufferAccessOutOfBounds', line)
						if result is not None:
							nb_bufferAccessOutOfBounds += 1
						result = re.search('unknownEvaluationOrder', line)
						if result is not None:
							nb_unknownEvaluationOrder += 1
				xmlfile.close()
			if (nb_errors == 0) and (nb_warnings == 0):
				self.file.write('   <div class="alert alert-success">\n')
ismail's avatar
ismail committed
279
				self.file.write('     <strong>CPPCHECK found NO error and NO warning <span class="glyphicon glyphicon-ok-circle"></span></strong>\n')
280 281 282
				self.file.write('   </div>\n')
			elif (nb_errors == 0):
				self.file.write('   <div class="alert alert-warning">\n')
ismail's avatar
ismail committed
283
				self.file.write('     <strong>CPPCHECK found NO error and ' + str(nb_warnings) + ' warnings <span class="glyphicon glyphicon-warning-sign"></span></strong>\n')
284 285 286
				self.file.write('   </div>\n')
			else:
				self.file.write('   <div class="alert alert-danger">\n')
ismail's avatar
ismail committed
287
				self.file.write('     <strong>CPPCHECK found ' +  str(nb_errors) + ' errors and ' + str(nb_warnings) + ' warnings <span class="glyphicon glyphicon-ban-circle"></span></strong>\n')
288 289 290 291 292 293
				self.file.write('   </div>\n')
			if (nb_errors > 0) or (nb_warnings > 0):
				self.file.write('   <button data-toggle="collapse" data-target="#oai-cppcheck-details">More details on CPPCHECK results</button>\n')
				self.file.write('   <div id="oai-cppcheck-details" class="collapse">\n')
				self.file.write('   <br>\n')
				self.file.write('   <table class="table-bordered" width = "80%" align = "center" border = "1">\n')
ismail's avatar
ismail committed
294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345
				self.file.write('     <tr bgcolor = "#33CCFF" >\n')
				self.file.write('   	<th>Error / Warning Type</th>\n')
				self.file.write('   	<th>Nb Errors</th>\n')
				self.file.write('   	<th>Nb Warnings</th>\n')
				self.file.write('     </tr>\n')
				self.file.write('     <tr>\n')
				self.file.write('   	<td>Uninitialized variable</td>\n')
				self.file.write('   	<td>' + str(nb_uninitvar) + '</td>\n')
				self.file.write('   	<td>N/A</td>\n')
				self.file.write('     </tr>\n')
				self.file.write('     <tr>\n')
				self.file.write('       <td>Uninitialized struct member</td>\n')
				self.file.write('       <td>' + str(nb_uninitStructMember) + '</td>\n')
				self.file.write('       <td>N/A</td>\n')
				self.file.write('     </tr>\n')
				self.file.write('     <tr>\n')
				self.file.write('       <td>Memory leak</td>\n')
				self.file.write('       <td>' + str(nb_memleak) + '</td>\n')
				self.file.write('       <td>N/A</td>\n')
				self.file.write('     </tr>\n')
				self.file.write('     <tr>\n')
				self.file.write('       <td>Memory is freed twice</td>\n')
				self.file.write('       <td>' + str(nb_doubleFree) + '</td>\n')
				self.file.write('       <td>N/A</td>\n')
				self.file.write('     </tr>\n')
				self.file.write('     <tr>\n')
				self.file.write('       <td>Resource leak</td>\n')
				self.file.write('       <td>' + str(nb_resourceLeak) + '</td>\n')
				self.file.write('       <td>N/A</td>\n')
				self.file.write('     </tr>\n')
				self.file.write('     <tr>\n')
				self.file.write('       <td>Possible null pointer dereference</td>\n')
				self.file.write('       <td>' + str(nb_nullPointer) + '</td>\n')
				self.file.write('       <td>N/A</td>\n')
				self.file.write('     </tr>\n')
				self.file.write('     <tr>\n')
				self.file.write('       <td>Array access  out of bounds</td>\n')
				self.file.write('       <td>' + str(nb_arrayIndexOutOfBounds) + '</td>\n')
				self.file.write('       <td>N/A</td>\n')
				self.file.write('     </tr>\n')
				self.file.write('     <tr>\n')
				self.file.write('   	<td>Buffer is accessed out of bounds</td>\n')
				self.file.write('   	<td>' + str(nb_bufferAccessOutOfBounds) + '</td>\n')
				self.file.write('   	<td>N/A</td>\n')
				self.file.write('     </tr>\n')
				self.file.write('     <tr>\n')
				self.file.write('       <td>Expression depends on order of evaluation of side effects</td>\n')
				self.file.write('       <td>' + str(nb_unknownEvaluationOrder) + '</td>\n')
				self.file.write('       <td>N/A</td>\n')
				self.file.write('     </tr>\n')
				self.file.write('     <tr>\n')
				self.file.write('       <td>Others</td>\n')
346 347
				nb_others = nb_uninitvar + nb_uninitStructMember + nb_memleak + nb_doubleFree + nb_resourceLeak + nb_nullPointer + nb_arrayIndexOutOfBounds + nb_arrayIndexOutOfBounds + nb_bufferAccessOutOfBounds + nb_unknownEvaluationOrder
				nb_others = nb_errors - nb_others
ismail's avatar
ismail committed
348 349 350 351 352 353 354 355
				self.file.write('   	<td>' + str(nb_others) + '</td>\n')
				self.file.write('   	<td>' + str(nb_warnings) + '</td>\n')
				self.file.write('     </tr>\n')
				self.file.write('     <tr bgcolor = "#33CCFF" >\n')
				self.file.write('   	<th>Total</th>\n')
				self.file.write('   	<th>' + str(nb_errors) + '</th>\n')
				self.file.write('   	<th>' + str(nb_warnings) + '</th>\n')
				self.file.write('     </tr>\n')
356 357 358 359 360 361 362 363
				self.file.write('   </table>\n')
				self.file.write('   <br>\n')
				self.file.write('   <p>Full details in artifact (cppcheck.xml) </p>\n')
				self.file.write('   <p style="margin-left: 30px">Graphical Interface tool : <strong><code>cppcheck-gui -l cppcheck.xml</code></strong></p>\n')
				self.file.write('   <br>\n')
				self.file.write('   </div>\n')
		else:
			self.file.write('  <div class="alert alert-danger">\n')
ismail's avatar
ismail committed
364
			self.file.write('     <strong>Was NOT performed (with CPPCHECK tool). <span class="glyphicon glyphicon-ban-circle"></span></strong>\n')
365 366 367
			self.file.write('  </div>\n')

	def buildSummaryHeader(self):
368
		self.file.write('  <h2>Docker / Podman Image Build Summary</h2>\n')
369
		self.file.write('  <table class="table-bordered" width = "100%" align = "center" border = "1">\n')
ismail's avatar
ismail committed
370 371 372
		self.file.write('     <tr bgcolor="#33CCFF" >\n')
		self.file.write('   	<th>Stage Name</th>\n')
		self.file.write('   	<th>Image Kind</th>\n')
373 374
		self.file.write('		<th>OAI AMF <font color="Gold">Ubuntu18</font> Image</th>\n')
		self.file.write('		<th>OAI AMF <font color="Gold">RHEL8</font> Image</th>\n')
ismail's avatar
ismail committed
375
		self.file.write('     </tr>\n')
376 377 378 379

	def buildSummaryFooter(self):
		self.file.write('  </table>\n')
		self.file.write('  <br>\n')
Raphael Defosseux's avatar
Raphael Defosseux committed
380
		if len(self.warning_rows) > 0:
381 382 383 384 385 386 387 388 389 390 391 392 393 394 395
			self.file.write('  <h3>Compilation Warnings Details</h3>\n')
			self.file.write('  <button data-toggle="collapse" data-target="#oai-compilation-details">Details for Compilation Errors and Warnings </button>\n')
			self.file.write('  <div id="oai-compilation-details" class="collapse">\n')
			self.file.write('  <table class="table-bordered">\n')
			self.file.write('    <tr bgcolor = "#33CCFF" >\n')
			self.file.write('      <th>File</th>\n')
			self.file.write('      <th>Line Number</th>\n')
			self.file.write('      <th>Status</th>\n')
			self.file.write('      <th>Message</th>\n')
			self.file.write(self.warning_rows)
			self.file.write('    </tr>\n')
			self.file.write('  </table>\n')
			self.file.write('  </div>\n')

	def initialGitSetup(self):
ismail's avatar
ismail committed
396 397
		self.file.write('    <tr>\n')
		self.file.write('      <td bgcolor="lightcyan" >Initial Git Setup</td>\n')
398 399 400 401 402 403
		self.analyze_docker_build_git_part('AMF')
		self.file.write('	 </tr>\n')

	def analyze_docker_build_git_part(self, nfType):
		if nfType != 'AMF':
			self.file.write('      <td>N/A</td>\n')
404
			self.file.write('      <td colspan="2">Wrong NF Type for this Report</td>\n')
405 406 407 408
			return

		self.file.write('      <td>Builder Image</td>\n')
		cwd = os.getcwd()
409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435
		variants = ['docker', 'podman']
		for variant in variants:
			logFileName = 'amf_' + variant + '_image_build.log'
			if os.path.isfile(cwd + '/archives/' + logFileName):
				status = False
				section_start_pattern = 'git config --global http'
				section_end_pattern = 'WORKDIR /openair-amf/build/scripts'
				section_status = False
				with open(cwd + '/archives/' + logFileName, 'r') as logfile:
					for line in logfile:
						result = re.search(section_start_pattern, line)
						if result is not None:
							section_status = True
						result = re.search(section_end_pattern, line)
						if result is not None:
							section_status = False
							status = True
					logfile.close()

				if status:
					cell_msg = '      <td bgcolor="LimeGreen"><pre style="border:none; background-color:LimeGreen"><b>'
					cell_msg += 'OK:\n'
					cell_msg += ' -- All Git Operations went successfully</b></pre></td>\n'
				else:
					cell_msg = '	  <td bgcolor="Tomato"><pre style="border:none; background-color:Tomato"><b>'
					cell_msg += 'KO::\n'
					cell_msg += ' -- Some Git Operations went WRONG</b></pre></td>\n'
436
			else:
437 438
				cell_msg = '      <td bgcolor="Tomato"><pre style="border:none; background-color:Tomato"><b>'
				cell_msg += 'KO: logfile (' + logFileName + ') not found</b></pre></td>\n'
439

440
			self.file.write(cell_msg)
441 442

	def installLibsPackagesRow(self):
ismail's avatar
ismail committed
443 444
		self.file.write('    <tr>\n')
		self.file.write('      <td bgcolor="lightcyan" >SW libs and packages Installation</td>\n')
445 446 447 448 449 450
		self.analyze_install_log('AMF')
		self.file.write('	 </tr>\n')

	def analyze_install_log(self, nfType):
		if nfType != 'AMF':
			self.file.write('      <td>N/A</td>\n')
451
			self.file.write('      <td colspan="2">Wrong NF Type for this Report</td>\n')
452 453 454 455 456
			return

		self.file.write('      <td>Builder Image</td>\n')

		cwd = os.getcwd()
457 458
		variants = ['docker', 'podman']
		for variant in variants:
459
			logFileName = 'amf_' + variant + '_image_build.log'
460 461 462 463 464 465 466 467 468 469 470 471 472 473
			if os.path.isfile(cwd + '/archives/' + logFileName):
				status = False
				section_start_pattern = 'build_amf --install-deps --force'
				section_end_pattern = 'build_amf --clean --Verbose --build-type Release --jobs'
				section_status = False
				package_install = False
				folly_build_start = False
				folly_build_status = False
				spdlog_build_start = False
				spdlog_build_status = False
				pistache_build_start = False
				pistache_build_status = False
				json_build_start = False
				json_build_status = False
474 475
				cpprest_build_start = False
				cpprest_build_status = False
476
				base_image = False
477 478
				with open(cwd + '/archives/' + logFileName, 'r') as logfile:
					for line in logfile:
479 480 481
						result = re.search('FROM oai-amf-base', line)
						if result is not None:
							base_image = True
482
						result = re.search(section_start_pattern, line)
483
						if result is not None:
484 485
							section_status = True
						result = re.search(section_end_pattern, line)
486
						if result is not None:
487
							section_status = True
488 489 490 491
						if section_status:
							result = re.search('AMF deps installation successful', line)
							if result is not None:
								status = True
492
							result = re.search('distro libs installation complete', line)
493 494
							if result is not None:
								package_install = True
495
							result = re.search('Starting to install cpprestsdk', line)
496
							if result is not None:
497 498 499
								cpprest_build_start = True
							result = re.search('cpprestsdk installation complete', line)
							if result is not None and cpprest_build_start:
500
								cpprest_build_status = True
501
							result = re.search('Starting to install folly', line)
502
							if result is not None:
503 504 505
								folly_build_start = True
							result = re.search('folly installation complete', line)
							if result is not None and folly_build_start:
506
								folly_build_status = True
507
							result = re.search('Starting to install spdlog', line)
508 509
							if result is not None:
								spdlog_build_start = True
510 511
							result = re.search('spdlog installation complete', line)
							if result is not None and spdlog_build_start:
512
								spdlog_build_status = True
513
							result = re.search('Starting to install pistache', line)
514
							if result is not None:
515 516 517
								pistache_build_start = True
							result = re.search('pistache installation complete', line)
							if result is not None and pistache_build_start:
518
								pistache_build_status = True
519
							result = re.search('Starting to install Nlohmann Json', line)
520 521
							if result is not None:
								json_build_status = True
522
							result = re.search('Nlohmann Json installation complete', line)
523 524 525
							if result is not None:
								json_build_status = True
					logfile.close()
526 527 528 529
				if base_image:
					cell_msg = '      <td bgcolor="LimeGreen"><pre style="border:none; background-color:LimeGreen"><b>'
					cell_msg += 'N/A:\n'
				elif status:
530 531 532 533 534 535
					cell_msg = '	  <td bgcolor="LimeGreen"><pre style="border:none; background-color:LimeGreen"><b>'
					cell_msg += 'OK:\n'
				else:
					cell_msg = '	  <td bgcolor="Tomato"><pre style="border:none; background-color:Tomato"><b>'
					cell_msg += 'KO:\n'
				cell_msg += ' -- build_amf --install-deps --force\n'
536 537 538
				if base_image:
					cell_msg += '   ** Packages Installation: N/A\n'
				elif package_install:
539 540 541
					cell_msg += '   ** Packages Installation: OK\n'
				else:
					cell_msg += '   ** Packages Installation: KO\n'
542 543 544 545 546 547
				if base_image:
					cell_msg += '   ** cpprestsdk Installation: N/A\n'
				elif cpprest_build_status:
					cell_msg += '   ** cpprestsdk Installation: OK\n'
				else:
					cell_msg += '   ** cpprestsdk Installation: KO\n'
548 549 550
				if base_image:
					cell_msg += '   ** folly Installation: N/A\n'
				elif folly_build_status:
551 552 553
					cell_msg += '   ** folly Installation: OK\n'
				else:
					cell_msg += '   ** folly Installation: KO\n'
554 555 556
				if base_image:
					cell_msg += '   ** spdlog Installation: N/A\n'
				elif spdlog_build_status:
557 558 559
					cell_msg += '   ** spdlog Installation: OK\n'
				else:
					cell_msg += '   ** spdlog Installation: KO\n'
560 561 562
				if base_image:
					cell_msg += '   ** pistache Installation: N/A\n'
				elif pistache_build_status:
563 564 565
					cell_msg += '   ** pistache Installation: OK\n'
				else:
					cell_msg += '   ** pistache Installation: KO\n'
566 567 568
				if base_image:
					cell_msg += '   ** Nlohmann Json Installation: N/A\n'
				elif json_build_status:
569 570 571 572
					cell_msg += '   ** Nlohmann Json Installation: OK\n'
				else:
					cell_msg += '   ** Nlohmann Json Installation: KO\n'
				cell_msg += '</b></pre></td>\n'
573 574
			else:
				cell_msg = '	  <td bgcolor="Tomato"><pre style="border:none; background-color:Tomato"><b>'
575
				cell_msg += 'KO: logfile (' + logFileName + ') not found</b></pre></td>\n'
576

577
			self.file.write(cell_msg)
578 579 580 581 582 583 584 585 586 587 588 589 590 591

	def buildCompileRows(self):
		self.file.write('	 <tr>\n')
		self.file.write('	   <td rowspan=2 bgcolor="lightcyan" >cNF Compile / Build</td>\n')
		self.analyze_build_log('AMF', True)
		self.file.write('	 </tr>\n')
		self.file.write('	 <tr>\n')
		self.analyze_compile_log('AMF', True)
		self.file.write('	 </tr>\n')

	def analyze_build_log(self, nfType, imageKind):
		if nfType != 'AMF':
			if imageKind:
				self.file.write('      <td>N/A</td>\n')
592
			self.file.write('	   <td colspan="2">Wrong NF Type for this Report</td>\n')
593 594 595 596 597 598
			return

		if imageKind:
			self.file.write('      <td>Builder Image</td>\n')

		cwd = os.getcwd()
599 600
		variants = ['docker', 'podman']
		for variant in variants:
601
			logFileName = 'amf_' + variant + '_image_build.log'
602 603 604 605
			if os.path.isfile(cwd + '/archives/' + logFileName):
				status = False
				if nfType == 'AMF':
					section_start_pattern = 'build_amf --clean --Verbose --build-type Release --jobs'
606
					section_end_pattern = 'FROM .* as oai-amf$'
607 608 609 610 611
					pass_pattern = 'amf installed'
				section_status = False
				with open(cwd + '/archives/' + logFileName, 'r') as logfile:
					for line in logfile:
						result = re.search(section_start_pattern, line)
612
						if result is not None:
613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628
							section_status = True
						result = re.search(section_end_pattern, line)
						if result is not None:
							section_status = False
						if section_status:
							result = re.search(pass_pattern, line)
							if result is not None:
								status = True
					logfile.close()
				if status:
					cell_msg = '	  <td bgcolor="LimeGreen"><pre style="border:none; background-color:LimeGreen"><b>'
					cell_msg += 'OK:\n'
				else:
					cell_msg = '	  <td bgcolor="Tomato"><pre style="border:none; background-color:Tomato"><b>'
					cell_msg += 'KO:\n'
				cell_msg += ' -- ' + section_start_pattern + '</b></pre></td>\n'
629 630
			else:
				cell_msg = '	  <td bgcolor="Tomato"><pre style="border:none; background-color:Tomato"><b>'
631
				cell_msg += 'KO: logfile (' + logFileName + ') not found</b></pre></td>\n'
632

633
			self.file.write(cell_msg)
634 635 636 637 638 639 640 641 642 643 644 645

	def analyze_compile_log(self, nfType, imageKind):
		if nfType != 'AMF':
			if imageKind:
				self.file.write('      <td>N/A</td>\n')
			self.file.write('	   <td>Wrong NF Type for this Report</td>\n')
			return

		if imageKind:
			self.file.write('      <td>Builder Image</td>\n')

		cwd = os.getcwd()
646 647
		variants = ['docker', 'podman']
		for variant in variants:
648
			logFileName = 'amf_' + variant + '_image_build.log'
649 650
			nb_errors = 0
			nb_warnings = 0
651 652
			added_separator = False

653 654 655
			if os.path.isfile(cwd + '/archives/' + logFileName):
				if nfType == 'AMF':
					section_start_pattern = 'build_amf --clean --Verbose --build-type Release --jobs'
656
					section_end_pattern = 'FROM .* as oai-amf$'
657 658 659 660
				section_status = False
				with open(cwd + '/archives/' + logFileName, 'r') as logfile:
					for line in logfile:
						result = re.search(section_start_pattern, line)
661
						if result is not None:
662 663
							section_status = True
						result = re.search(section_end_pattern, line)
664
						if result is not None:
665 666 667 668 669 670
							section_status = False
						if section_status:
							result = re.search('error:', line)
							if result is not None:
								nb_errors += 1
							result = re.search('warning:', line)
671 672 673
							if result is not None:
								nb_warnings += 1
							result = re.search('error:|warning:', line)
674 675 676 677 678 679 680 681
							if result is not None:
								correctLine = re.sub("^.*/openair-amf","/openair-amf",line.strip())
								wordsList = correctLine.split(None,2)
								filename = re.sub(":[0-9]*:[0-9]*:","", wordsList[0])
								linenumber = re.sub(filename + ':',"", wordsList[0])
								linenumber = re.sub(':[0-9]*:',"", linenumber)
								error_warning_status = re.sub(':',"", wordsList[1])
								error_warning_msg = re.sub('^.*' + error_warning_status + ':', '', correctLine)
682

683
								if not added_separator and variant == 'docker':
684
									self.warning_rows += '<tr><td colspan="4" align = "center" bgcolor = "LightGray"><b>Ubuntu 18</b></td></tr>\n'
685 686
									added_separator = True
								if not added_separator and variant == 'podman':
687
									self.warning_rows += '<tr><td colspan="4" align = "center" bgcolor = "LightGray"><b>RHEL 8</b></td></tr>\n'
688
									added_separator = True
689 690 691 692 693 694 695 696 697 698 699 700
								self.warning_rows += '<tr><td>' + filename + '</td><td>' + linenumber + '</td><td>' + error_warning_status + '</td><td>' + error_warning_msg + '</td></tr>\n'
					logfile.close()
				if nb_warnings == 0 and nb_errors == 0:
					cell_msg = '	   <td bgcolor="LimeGreen"><pre style="border:none; background-color:LimeGreen"><b>'
				elif nb_warnings < 20 and nb_errors == 0:
					cell_msg = '	   <td bgcolor="Orange"><pre style="border:none; background-color:Orange"><b>'
				else:
					cell_msg = '	   <td bgcolor="Tomato"><pre style="border:none; background-color:Tomato"><b>'
				if nb_errors > 0:
					cell_msg += str(nb_errors) + ' errors found in compile log\n'
				cell_msg += str(nb_warnings) + ' warnings found in compile log</b></pre></td>\n'
				self.nb_warnings = nb_warnings
701
			else:
702 703
				cell_msg = '	  <td bgcolor="Tomato"><pre style="border:none; background-color:Tomato"><b>'
				cell_msg += 'KO: logfile (' + logFileName + ') not found</b></pre></td>\n'
704

705
			self.file.write(cell_msg)
706 707 708 709 710 711 712 713 714 715

	def copyToTargetImage(self):
		self.file.write('	 <tr>\n')
		self.file.write('	   <td bgcolor="lightcyan" >SW libs Installation / Copy from Builder</td>\n')
		self.analyze_copy_log('AMF')
		self.file.write('	 </tr>\n')

	def analyze_copy_log(self, nfType):
		if nfType != 'AMF':
			self.file.write('      <td>N/A</td>\n')
716
			self.file.write('	   <td colspan="2">Wrong NF Type for this Report</td>\n')
717 718 719 720 721
			return

		self.file.write('      <td>Target Image</td>\n')

		cwd = os.getcwd()
722 723
		variants = ['docker', 'podman']
		for variant in variants:
724
			logFileName = 'amf_' + variant + '_image_build.log'
725
			if os.path.isfile(cwd + '/archives/' + logFileName):
726
				section_start_pattern = 'FROM .* as oai-amf$'
727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746
				section_end_pattern = 'WORKDIR /openair-amf/etc'
				section_status = False
				status = False
				with open(cwd + '/archives/' + logFileName, 'r') as logfile:
					for line in logfile:
						result = re.search(section_start_pattern, line)
						if result is not None:
							section_status = True
						result = re.search(section_end_pattern, line)
						if result is not None:
							section_status = False
							status = True
					logfile.close()
				if status:
					cell_msg = '	   <td bgcolor="LimeGreen"><pre style="border:none; background-color:LimeGreen"><b>'
					cell_msg += 'OK:\n'
				else:
					cell_msg = '	   <td bgcolor="Tomato"><pre style="border:none; background-color:Tomato"><b>'
					cell_msg += 'KO:\n'
				cell_msg += '</b></pre></td>\n'
747
			else:
748 749
				cell_msg = '	  <td bgcolor="Tomato"><pre style="border:none; background-color:Tomato"><b>'
				cell_msg += 'KO: logfile (' + logFileName + ') not found</b></pre></td>\n'
750

751
			self.file.write(cell_msg)
752 753 754 755 756 757 758 759 760 761

	def copyConfToolsToTargetImage(self):
		self.file.write('	 <tr>\n')
		self.file.write('	   <td bgcolor="lightcyan" >Copy Template Conf / Tools from Builder</td>\n')
		self.analyze_copy_conf_tool_log('AMF')
		self.file.write('	 </tr>\n')

	def analyze_copy_conf_tool_log(self, nfType):
		if nfType != 'AMF':
			self.file.write('      <td>N/A</td>\n')
762
			self.file.write('	   <td colspan="2">Wrong NF Type for this Report</td>\n')
763 764 765 766 767
			return

		self.file.write('      <td>Target Image</td>\n')

		cwd = os.getcwd()
768 769
		variants = ['docker', 'podman']
		for variant in variants:
770
			logFileName = 'amf_' + variant + '_image_build.log'
771 772
			if os.path.isfile(cwd + '/archives/' + logFileName):
				section_start_pattern = 'WORKDIR /openair-amf/etc'
773 774 775 776
				if variant == 'docker':
					section_end_pattern = 'Successfully tagged oai-amf'
				else:
					section_end_pattern = 'COMMIT oai-amf:' 
777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795
				section_status = False
				status = False
				with open(cwd + '/archives/' + logFileName, 'r') as logfile:
					for line in logfile:
						result = re.search(section_start_pattern, line)
						if result is not None:
							section_status = True
						result = re.search(section_end_pattern, line)
						if result is not None:
							section_status = False
							status = True
					logfile.close()
				if status:
					cell_msg = '	   <td bgcolor="LimeGreen"><pre style="border:none; background-color:LimeGreen"><b>'
					cell_msg += 'OK:\n'
				else:
					cell_msg = '	   <td bgcolor="Tomato"><pre style="border:none; background-color:Tomato"><b>'
					cell_msg += 'KO:\n'
				cell_msg += '</b></pre></td>\n'
796
			else:
797 798
				cell_msg = '	  <td bgcolor="Tomato"><pre style="border:none; background-color:Tomato"><b>'
				cell_msg += 'KO: logfile (' + logFileName + ') not found</b></pre></td>\n'
799

800
			self.file.write(cell_msg)
801 802 803 804 805 806 807 808 809 810 811

	def imageSizeRow(self):
		self.file.write('	 <tr>\n')
		self.file.write('	   <td bgcolor="lightcyan" >Image Size</td>\n')
		self.analyze_image_size_log('AMF', True)
		self.file.write('	 </tr>\n')

	def analyze_image_size_log(self, nfType, imageKind):
		if nfType != 'AMF':
			if imageKind:
				self.file.write('      <td>N/A</td>\n')
812
			self.file.write('	   <td colspan="2">Wrong NF Type for this Report</td>\n')
813 814 815 816 817 818
			return

		if imageKind:
			self.file.write('      <td>Target Image</td>\n')

		cwd = os.getcwd()
819 820
		variants = ['docker', 'podman']
		for variant in variants:
821
			logFileName = 'amf_' + variant + '_image_build.log'
822 823
			if os.path.isfile(cwd + '/archives/' + logFileName):
				if nfType == 'AMF':
824 825 826 827 828 829
					if variant == 'docker':
						section_start_pattern = 'Successfully tagged oai-amf'
						section_end_pattern = 'OAI-AMF DOCKER IMAGE BUILD'
					else:
						section_start_pattern = 'COMMIT oai-amf:'
						section_end_pattern = 'OAI-AMF PODMAN RHEL8 IMAGE BUILD'
830 831 832 833 834
				section_status = False
				status = False
				with open(cwd + '/archives/' + logFileName, 'r') as logfile:
					for line in logfile:
						result = re.search(section_start_pattern, line)
835
						if result is not None:
836 837 838
							section_status = True
						result = re.search(section_end_pattern, line)
						if result is not None:
839
							section_status = True
840 841 842 843 844
						if section_status:
							if nfType == 'AMF':
								if self.git_pull_request:
									result = re.search('oai-amf *ci-tmp', line)
								else:
845
									result = re.search('oai-amf *develop', line)
846
							if result is not None and not status:
Raphael Defosseux's avatar
Raphael Defosseux committed
847
								result = re.search('ago  *([0-9A-Z ]+)', line)
848 849
								if result is not None:
									size = result.group(1)
Raphael Defosseux's avatar
Raphael Defosseux committed
850 851
									if variant == 'docker':
										size = re.sub('MB', ' MB', size)
852 853 854 855 856 857 858 859 860
									status = True
					logfile.close()
				if status:
					cell_msg = '	   <td bgcolor="LimeGreen"><pre style="border:none; background-color:LimeGreen"><b>'
					cell_msg += 'OK:  ' + size + '\n'
				else:
					cell_msg = '	   <td bgcolor="Tomato"><pre style="border:none; background-color:Tomato"><b>'
					cell_msg += 'KO:\n'
				cell_msg += '</b></pre></td>\n'
861
			else:
862 863
				cell_msg = '	  <td bgcolor="Tomato"><pre style="border:none; background-color:Tomato"><b>'
				cell_msg += 'KO: logfile (' + logFileName + ') not found</b></pre></td>\n'
864

865
			self.file.write(cell_msg)
866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948

def Usage():
	print('----------------------------------------------------------------------------------------------------------------------')
	print('generateHtmlReport.py')
	print('   Generate an HTML report for the Jenkins pipeline on openair-amf.')
	print('----------------------------------------------------------------------------------------------------------------------')
	print('Usage: python3 generateHtmlReport.py [options]')
	print('  --help  Show this help.')
	print('---------------------------------------------------------------------------------------------- Mandatory Options -----')
	print('  --job_name=[Jenkins Job name]')
	print('  --job_id=[Jenkins Job Build ID]')
	print('  --job_url=[Jenkins Job Build URL]')
	print('  --git_url=[Git Repository URL]')
	print('  --git_src_branch=[Git Source Branch Name]')
	print('  --git_src_commit=[Git Source Commit SHA-ONE]')
	print('----------------------------------------------------------------------------------------------- Optional Options -----')
	print('  --git_pull_request=True')
	print('  --git_target_branch=[Git Target Branch Name]')
	print('  --git_target_commit=[Git Target Commit SHA-ONE]')

#--------------------------------------------------------------------------------------------------------
#
# Start of main
#
#--------------------------------------------------------------------------------------------------------

argvs = sys.argv
argc = len(argvs)

HTML = HtmlReport()

while len(argvs) > 1:
	myArgv = argvs.pop(1)
	if re.match('^\-\-help$', myArgv, re.IGNORECASE):
		Usage()
		sys.exit(0)
	elif re.match('^\-\-job_name=(.+)$', myArgv, re.IGNORECASE):
		matchReg = re.match('^\-\-job_name=(.+)$', myArgv, re.IGNORECASE)
		HTML.job_name = matchReg.group(1)
	elif re.match('^\-\-job_id=(.+)$', myArgv, re.IGNORECASE):
		matchReg = re.match('^\-\-job_id=(.+)$', myArgv, re.IGNORECASE)
		HTML.job_id = matchReg.group(1)
	elif re.match('^\-\-job_url=(.+)$', myArgv, re.IGNORECASE):
		matchReg = re.match('^\-\-job_url=(.+)$', myArgv, re.IGNORECASE)
		HTML.job_url = matchReg.group(1)
	elif re.match('^\-\-git_url=(.+)$', myArgv, re.IGNORECASE):
		matchReg = re.match('^\-\-git_url=(.+)$', myArgv, re.IGNORECASE)
		HTML.git_url = matchReg.group(1)
	elif re.match('^\-\-git_src_branch=(.+)$', myArgv, re.IGNORECASE):
		matchReg = re.match('^\-\-git_src_branch=(.+)$', myArgv, re.IGNORECASE)
		HTML.git_src_branch = matchReg.group(1)
	elif re.match('^\-\-git_src_commit=(.+)$', myArgv, re.IGNORECASE):
		matchReg = re.match('^\-\-git_src_commit=(.+)$', myArgv, re.IGNORECASE)
		HTML.git_src_commit = matchReg.group(1)
	elif re.match('^\-\-git_src_commit_msg=(.+)$', myArgv, re.IGNORECASE):
		# Not Mandatory
		matchReg = re.match('^\-\-git_src_commit_msg=(.+)$', myArgv, re.IGNORECASE)
		HTML.git_src_commit_msg = matchReg.group(1)
	elif re.match('^\-\-git_pull_request=(.+)$', myArgv, re.IGNORECASE):
		# Can be silent: would be false!
		matchReg = re.match('^\-\-git_pull_request=(.+)$', myArgv, re.IGNORECASE)
		if matchReg.group(1) == 'true' or matchReg.group(1) == 'True':
			HTML.git_pull_request = True
	elif re.match('^\-\-git_target_branch=(.+)$', myArgv, re.IGNORECASE):
		matchReg = re.match('^\-\-git_target_branch=(.+)$', myArgv, re.IGNORECASE)
		HTML.git_target_branch = matchReg.group(1)
	elif re.match('^\-\-git_target_commit=(.+)$', myArgv, re.IGNORECASE):
		matchReg = re.match('^\-\-git_target_commit=(.+)$', myArgv, re.IGNORECASE)
		HTML.git_target_commit = matchReg.group(1)
	else:
		sys.exit('Invalid Parameter: ' + myArgv)

if HTML.job_name == '' or HTML.job_id == '' or HTML.job_url == '':
	sys.exit('Missing Parameter in job description')

if HTML.git_url == '' or HTML.git_src_branch == '' or HTML.git_src_commit == '':
	sys.exit('Missing Parameter in Git Repository description')

if HTML.git_pull_request:
	if HTML.git_target_commit == '' or HTML.git_target_branch == '':
		 sys.exit('Missing Parameter in Git Pull Request Repository description')

HTML.generate()