import argparse import subprocess import cgi import os import sys import shutil from vector.lib.platform.vcast_platform import vcast_platform from vector.apps.DataAPI.api import Api from vector.apps.DataAPI.cover_api import CoverApi from xml.sax.saxutils import escape from vector.apps.DataAPI.models import TestCase import glob import time global COVERED_INDEX, TOTAL_INDEX, PERCENT_INDEX,UNIT_INDEX, SUBP_INDEX, VG_INDEX COVERED_INDEX = 0 TOTAL_INDEX = 1 PERCENT_INDEX = 2 UNIT_INDEX = 0 SUBP_INDEX = 1 VG_INDEX = 2 # column constants UNIT_NAME_COL = 0 SUBPROG_COL = 1 TEST_CASE_COL = 2 TC_STATUS_COL = 3 testCasePassString =" \n" testCaseFailString =""" """ global envName, manageProjectName global testCaseCount testCaseCount = 0 envName = "" manageProjectName = "" global stIndex,brIndex,pairIndex,pathIndex,baIndex stIndex = brIndex = pairIndex = pathIndex = baIndex = fnIndex = -1 DEBUGGING = False #combine test results def bambooCombineTestResults(manageProjectName): f=open("xml_data/test_results_"+manageProjectName+"_combined.xml","w") f.write("\n") f.write("\n") for testResults in glob.glob('xml_data/test_results*.xml'): if "combined" in testResults: continue data = open(testResults,"r").readlines()[2:-1] wrData = "".join(data) f.write(wrData) f.write("\n\n") f.close() def bambooUpdateSummary(myData,line): data=line.split(" ") for metric in data[1:]: type = metric.split("=")[0] value = [int(s) for s in metric.split("\"") if s.isdigit()][0] try: myData[type] += value except: myData[type] = value return myData def bambooCombineCoverageResults(manageProjectName): time_string = str(int(time.time() * 1000)) cloverfile=open("xml_data/coverage_results_" + manageProjectName + "_combined.xml","w") cloverfile.write("\n") cloverfile.write( "\n"%(time_string)) cloverfile.write( " \n" %(manageProjectName,time_string)) items = ["packages","files","classes","complexity","loc","ncloc", "statements","coveredstatements","conditionals","coveredconditionals", "elements","coveredelements","methods","coveredmethods","testduration", "testfailures","testpasses","testruns"] summaryData = {} for item in items: summaryData[item] = 0 wrData = "" for covResults in glob.glob('xml_data/coverage_results*.xml'): if "combined" in covResults: continue try: data = open(covResults,"r").readlines()[2:-2] summaryData = bambooUpdateSummary(summaryData,data[0]) except IndexError as e: pass wrData += "".join(data[1:]) cloverfile.write(wrData) cloverfile.write(" \n") cloverfile.write("") cloverfile.close() def bambooCleanupXMLFiles(): shutil.rmtree("xml_data", ignore_errors = True) def writeJunitHeader(junitfile,dataArray): global envName junitfile.write("\n") junitfile.write("\n") errors = 0 failed = 0 for data in dataArray: if 'ABNORMAL' in data[TC_STATUS_COL]: errors += 1 elif not 'PASS' in data[TC_STATUS_COL]: failed += 1 junitfile.write(" \n" % (errors,len(dataArray), failed, envName)) def writeJunitTestCase(junitfile, unit, subp, tc_name, passFail): global jobNamePrefix global testCaseCount testCaseCount += 1 tc_name = tc_name if 'PASS' in passFail: successFailure = 'success' else: successFailure = 'failure' # if gUseExecRpt: # try: # exec_link = os.getenv('BUILD_URL') + "artifact/execution/" + manageProject + "_" + jobNamePrefix + "_execution_results_report.html#section" + str(1+testCaseCount*2) # except: # exec_link = "No Report found" # additional_msg = " See Execution Report: " + exec_link # passFail = passFail.rstrip() + additional_msg if 'ABNORMAL' in passFail: print "Abnormal Termination on Environment\n" unit_subp = unit + "." + subp if 'PASS' in passFail: junitfile.write(testCasePassString % (tc_name, unit_subp)) else: junitfile.write(testCaseFailString % (tc_name, unit_subp, passFail)) def writeJunitFooter(junitfile): junitfile.write(" \n") junitfile.write("\n") def determineCoverage(titles): global stIndex,brIndex,pairIndex,pathIndex,baIndex #determine which coverages are present and which index into the tables they are try: stIndex = titles.index('Statements Covered') except ValueError: stIndex = -1 try: brIndex = titles.index('Branches Covered') except ValueError: brIndex = -1 try: pairIndex = titles.index('Pairs Covered') except ValueError: pairIndex = -1 try: pathIndex = titles.index('Paths Covered') except ValueError: pathIndex = -1 try: baIndex = titles.index('ByAnalysis Covered') except ValueError: baIndex = -1 try: fnIndex = titles.index('SubprogramCoverage Covered') except ValueError: fnIndex = -1 def countUnits(data): unitName = "" unitCount = 0 for row in data: # if we have a different unit name -- bump up the unit count if row[UNIT_INDEX] != unitName: unitCount += 1 unitName = row[UNIT_INDEX] return unitCount def countSubp(data,unitName): subpCount = 0 for row in data: if isinstance(row,list): # if we have a different unit name -- bump up the unit count if row[UNIT_INDEX] == unitName or unitName == 'all': subpCount += 1 else: subpCount = 1 break return subpCount def calulatePercentages(statement,branch,pair,path,byAnalysis,func,Vg): try: statement [PERCENT_INDEX] = 100 * statement [COVERED_INDEX] / statement[TOTAL_INDEX] except: pass try: branch [PERCENT_INDEX] = 100 * branch [COVERED_INDEX] / branch[TOTAL_INDEX] except: pass try: pair [PERCENT_INDEX] = 100 * pair [COVERED_INDEX] / pair[TOTAL_INDEX] except: pass try: path [PERCENT_INDEX] = 100 * path [COVERED_INDEX] / path[TOTAL_INDEX] except: pass try: byAnalysis[PERCENT_INDEX] = 100 * byAnalysis[COVERED_INDEX] / byAnalysis[TOTAL_INDEX] except: pass try: func[PERCENT_INDEX] = 100 * func[COVERED_INDEX] / func[TOTAL_INDEX] except: pass return statement,branch,pair,path,byAnalysis,func,Vg def getCoverageTotals(data,unitName): global stIndex,brIndex,pairIndex,pathIndex,baIndex,fnIndex statement = [0,0,0] branch = [0,0,0] pair = [0,0,0] path = [0,0,0] byAnalysis = [0,0,0] func = [0,0,0] Vg = 0 #loop over all the data for row in data: # if we have a different unit name -- bump up the unit count if row[UNIT_INDEX] == unitName or unitName == 'all': try: Vg += int(row[VG_INDEX]) except: pass #if statement coverage is available -- bump up the statement count if stIndex != -1: try: statement[COVERED_INDEX] += int(row[stIndex+COVERED_INDEX]) statement[TOTAL_INDEX ] += int(row[stIndex+TOTAL_INDEX ]) except: pass #if branch coverage is available -- bump up the branch count if brIndex != -1: try: branch[COVERED_INDEX] += int(row[brIndex+COVERED_INDEX]) branch[TOTAL_INDEX ] += int(row[brIndex+TOTAL_INDEX ]) except: pass #if pair coverage is available -- bump up the pair count if pairIndex != -1: try: pair[COVERED_INDEX] += int(row[pairIndex+COVERED_INDEX]) pair[TOTAL_INDEX ] += int(row[pairIndex+TOTAL_INDEX ]) except: pass #if path coverage is available -- bump up the path count if pathIndex != -1: try: path[COVERED_INDEX] += int(row[pathIndex+COVERED_INDEX]) path[TOTAL_INDEX ] += int(row[pathIndex+TOTAL_INDEX ]) except: pass #if byAnalysis coverage is available -- bump up the byAnalysis count if baIndex != -1: try: byAnalysis[COVERED_INDEX] += int(row[baIndex+COVERED_INDEX]) byAnalysis[TOTAL_INDEX ] += int(row[baIndex+TOTAL_INDEX ]) except: pass #if fnIndex coverage is available -- bump up the function coverage count if fnIndex != -1: try: func[COVERED_INDEX] += int(row[fnIndex+COVERED_INDEX]) func[TOTAL_INDEX ] += int(row[fnIndex+TOTAL_INDEX ]) except: pass return calulatePercentages(statement,branch,pair,path,byAnalysis,func,Vg) def getFunctionData(data): global stIndex,brIndex,pairIndex,pathIndex,baIndex,fnIndex statement = [0,0,0] branch = [0,0,0] pair = [0,0,0] path = [0,0,0] byAnalysis = [0,0,0] func = [0,0,0] Vg = data[VG_INDEX] if stIndex != -1 and data[stIndex+TOTAL_INDEX]: statement = [int(data[stIndex+COVERED_INDEX]) ,int(data[stIndex+TOTAL_INDEX]) ,0] if brIndex != -1 and data[brIndex+TOTAL_INDEX]: branch = [int(data[brIndex+COVERED_INDEX]) ,int(data[brIndex+TOTAL_INDEX]) ,0] if pairIndex != -1 and data[pairIndex+TOTAL_INDEX]: pair = [int(data[pairIndex+COVERED_INDEX]),int(data[pairIndex+TOTAL_INDEX]),0] if pathIndex != -1 and data[pathIndex+TOTAL_INDEX]: path = [int(data[pathIndex+COVERED_INDEX]),int(data[pathIndex+TOTAL_INDEX]),0] if baIndex != -1 and data[baIndex+TOTAL_INDEX]: byAnalysis = [int(data[baIndex+COVERED_INDEX]) ,int(data[baIndex+TOTAL_INDEX]) ,0] if fnIndex != -1 and data[fnIndex+TOTAL_INDEX]: func = [int(data[fnIndex+COVERED_INDEX]) ,int(data[fnIndex+TOTAL_INDEX]) ,0] return calulatePercentages(statement,branch,pair,path,byAnalysis,func,Vg) cloverString = "\n" def writeCloverStat(cloverfile,data,unitName, summary): pkgStr = "" fileStr = "" classStr = "" Vg = 0 # Package,File,Classes if summary == 1: unitCount = countUnits(data) subpCount = countSubp(data,'all') pkgStr = "packages=\"1\" " fileStr = "files=\"%d\" " % (unitCount) classStr = "classes=\"%d\" " % (subpCount) statement,branch,pair,path,byAnalysis,func,Vg = getCoverageTotals(data,'all') indent = 2 # File,Classes elif summary == 2: unitCount = countUnits(data) subpCount = countSubp(data,unitName) pkgStr = "" fileStr = "files=\"%d\" " % (unitCount) classStr = "classes=\"%d\" " % (subpCount) statement,branch,pair,path,byAnalysis,func,Vg = getCoverageTotals(data,unitName) indent = 4 # Classes elif summary == 3: subpCount = countSubp(data,unitName) pkgStr = "" fileStr = "" classStr = "classes=\"%d\" " % (subpCount) statement,branch,pair,path,byAnalysis,func,Vg = getCoverageTotals(data,unitName) indent = 6 else: subpCount = countSubp(data,unitName) pkgStr = "" fileStr = "" classStr = "" statement,branch,pair,path,byAnalysis,func,Vg = getFunctionData(data) indent = 10 try: int(Vg) except: Vg = 0 cloverfile.write (" " * indent + cloverString % ( #package & files pkgStr, fileStr, classStr, #complexity int(Vg), #Lines of code totol and non-covered statement[TOTAL_INDEX], statement[TOTAL_INDEX]-statement[COVERED_INDEX], #statements total & covered statement[TOTAL_INDEX], statement[COVERED_INDEX], #conditionals total & covered branch[TOTAL_INDEX], branch[COVERED_INDEX], #elements total and covered branch[TOTAL_INDEX]+statement[TOTAL_INDEX], branch[COVERED_INDEX]+statement[COVERED_INDEX], #methods/functions total and covered func[TOTAL_INDEX], func[COVERED_INDEX] ) ) def writeCloverHeader(cloverfile): global manageProjectName time_string = str(int(time.time() * 1000)) cloverfile.write( "\n") cloverfile.write( "\n"%(time_string)) cloverfile.write( " \n" %(manageProjectName,time_string)) def writeCloverData(cloverfile,data): global envName global manageProjectName writeCloverStat(cloverfile,data,'all',1) cloverfile.write (" \n") writeCloverStat(cloverfile,data,'all',2) unitName = "" for row in data: row[UNIT_NAME_COL] = escape(row[UNIT_NAME_COL]) row[SUBPROG_COL] = escape(row[SUBPROG_COL]) row[TEST_CASE_COL] = escape(row[TEST_CASE_COL]) # if we have a different unit name -- bump up the unit count if row[UNIT_INDEX] != unitName: if unitName: cloverfile.write(" \n") unitName = row[UNIT_INDEX] subpName = row[SUBP_INDEX].replace("%2C",",") cloverfile.write(" \n" %( unitName)) writeCloverStat(cloverfile,data,unitName,3) cloverfile.write(" \n" % (subpName)) writeCloverStat(cloverfile,row,unitName,4) cloverfile.write(" \n") else: subpName = row[SUBP_INDEX].replace("%2C",",") cloverfile.write(" \n" % (subpName)) writeCloverStat(cloverfile,row,unitName,4) cloverfile.write(" \n") cloverfile.write (" \n") cloverfile.write (" \n") def writeCloverFooter(cloverfile): cloverfile.write (" \n") cloverfile.write ("\n") def writeCoverageDataClover(dataArray, filename): #parse the title to determine the coverage info titles = dataArray[0] determineCoverage(titles) #open the emma format file cloverfile = open(filename+".xml","w") #write out the header information for emma format writeCloverHeader(cloverfile) #write out the data for the emma file writeCloverData(cloverfile, dataArray[1:]) #write out the footer information for emma format writeCloverFooter(cloverfile) cloverfile.close() def writeJunitTestResults(dataArray, filename): titles = dataArray[0] junitfile = open(filename+".xml","w") writeJunitHeader(junitfile,dataArray[1:]) for data in dataArray[1:]: writeJunitTestCase(junitfile, data[UNIT_NAME_COL],data[SUBPROG_COL].replace("%2C",","),data[TEST_CASE_COL].replace("%2C",","),data[TC_STATUS_COL]) writeJunitFooter(junitfile) junitfile.close() def getEnvironmentList(ManageProjectName, level = None, environment = None): # Create command to create list of environments # for a given VectorCAST project manage = get_manage_cmd() command = [manage, "--project=" + ManageProjectName, "--build-directory-name"] command = insert_level_cmd(command, level, environment) o = subprocess.check_output(command) vceList = [] vcpList = [] envname = "" buildDir = "" lines = o.split("\n") for line in lines: if "Environment:" in line: envname = line.split(":")[-1].strip() elif "Build Directory: " in line: buildDir = line.split("Build Directory: ")[-1].strip() vceFile = buildDir + os.sep + envname + ".vce" vcpFile = buildDir + os.sep + envname + ".vcp" # determine .vcp for .vce if os.path.isfile(vceFile): vceList.append(vceFile) elif os.path.isfile(vcpFile): vcpList.append(vcpFile) return vceList, vcpList def getTCEntry(tc, SpecialTCName = None): # Unit, Subprogram, TestCases, Pass/Fail if SpecialTCName: unit_name = SpecialTCName func_name = SpecialTCName else: unit_name = tc.function.unit.name func_name = tc.function.display_name unit_name = cgi.escape(unit_name) func_name = cgi.escape(func_name) tc_name = cgi.escape(tc.name) if tc.passed: pfs = "PASS " else: pfs = "FAIL " exp_total = tc.history.summary.expected_total exp_pass = exp_total - tc.history.summary.expected_fail pfs += str(exp_pass) + " / " + str(exp_total) #print envName + ": " + unit_name + "," + func_name+ "," +tc_name+ "," + pfs return ([unit_name,func_name,tc_name,pfs]) def getCoverageEntry(function): unit_name = function.file.name func_name = function.name complexity = function.complexity metrics = function.cover_data.metrics if function.has_covered_objects: funcs = "1" cov_funcs = "1" pct = "100%" else: funcs = "0" cov_funcs = "0" pct = "0%" return [unit_name,func_name,str(complexity), cov_funcs, funcs, pct, str(metrics.aggregate_covered_statements), str(metrics.statements), str(metrics.aggregate_covered_statements_pct), str(metrics.aggregate_covered_branches), str(metrics.branches), str(metrics.aggregate_covered_branches_pct)] def writeCoverageResults(envList): global envName count = 0 for envFile in envList: envName = os.path.splitext(os.path.basename(envFile))[0] count += 1 if envFile.endswith(".vce"): api = Api(envFile) fileList = api.Unit.filter(is_uut = True) else: api = CoverApi(envFile) fileList = api.File.all() functionCoverageInfoList = [] functionCoverageInfoList.append(["Unit","Subprogram","Complexity", "FunctionCoverage Covered","FunctionCoverage Total","FunctionCoverage Percent", "Statements Covered","Statements Total","Statements Percent", "Branches Covered","Branches Total","Branches Percent"]) for unit in fileList: for func in unit.all_functions: if func.has_coverage_data: functionCoverageInfoList.append(getCoverageEntry(func)) writeCoverageDataClover( functionCoverageInfoList, "xml_data/coverage_results_" + str(count) ) def writeTestResults(vceList): global envName count = 0 for vceFile in vceList: envName = os.path.splitext(os.path.basename(vceFile))[0] count += 1 api = Api(vceFile) unitTestEntryList = [] unitTestEntryList.append(["Unit","Subprogram","TestCases","Pass/Fail"]) for tc in api.TestCase.all(): if tc.for_compound_only: continue if tc.kind == TestCase.KINDS['compound']: unitTestEntryList.append( getTCEntry(tc, "<>") ) elif tc.kind == TestCase.KINDS['init']: unitTestEntryList.append( getTCEntry(tc, "<>") ) for unit in api.Unit.all(): if unit.is_uut: for func in unit.functions: if not func.is_non_testable_stub: for tc in func.testcases: if not tc.is_csv_map and not tc.for_compound_only: unitTestEntryList.append( getTCEntry(tc) ) writeJunitTestResults( unitTestEntryList, "xml_data/test_results_" + str(count) ) def generate_reports(project, level = None, environment = None): # Release-locks cmd_to_run = [get_manage_cmd(), "--project=" + project, "--release-locks"] run_command(cmd_to_run) # Generate coverage report print("Generating Management Reports") cmd_to_run = [get_manage_cmd(), "--project=" + project, "--clicast-args report custom management"] cmd_to_run = insert_level_cmd(cmd_to_run, level, environment) out_mgt = run_command(cmd_to_run, True) # Generate test case execution result report print("Generating Test Case Execution Reports") cmd_to_run = [get_manage_cmd(), "--project=" + project, "--clicast-args report custom actual"] cmd_to_run = insert_level_cmd(cmd_to_run, level, environment) out_tst = run_command(cmd_to_run, True) # Aggregate both outputs out = out_mgt + out_tst # Save the output of the manage command for debug purposes outFile = open("build.log", "w") outFile.write("".join(out)) outFile.close() # Parse the output to detail location of reports and VectorCAST Project # level for environment report_dict = parse_report_gen_output(out) return report_dict def parse_report_gen_output(out = None): # Key: Environment Name # Tuple: [(level, [execution_results_report.html, management_report.html])] report_dict = {} for line in out: # Parse for the environment name if "COMMAND:" in line: info = line.split("-e ")[1].split(" ") env_name = info[0] # Parse for the level of the environment. # This'll be used for file names of the HTML artifacts if "TEST SUITE" in line: info = line.split(": ")[1].rstrip() level = info.split("/") # Get the HTML file name that was created if "HTML report was saved" in line: # Strip out anything that isn't the html full file path report_full_file_path = line.rstrip()[34:-2] # Existing entry for environment if env_name in report_dict.keys(): same_level = False entry_list = report_dict[env_name] for entry in entry_list: old_level = entry[0] report_list = entry[1] if old_level == level: report_list.append(report_full_file_path) same_level = True break # Existing environment but new different level if not same_level: report_list = [] report_list.append(report_full_file_path) entry_list.append((level, report_list)) # New environment entry else: report_list = [] report_dict_entry = [] report_list.append(report_full_file_path) report_dict_entry.append((level, report_list)) report_dict[env_name] = report_dict_entry return report_dict def copy_report_artifacts(report_dict): if not os.path.exists("management"): os.mkdir("management") if not os.path.exists("execution"): os.mkdir("execution") for v_list in report_dict.values(): for v in v_list: level = v[0] reports_list = v[1] for r in reports_list: # Create a unique report name because there might environments # with the same name but exist in different VectorCAST Project levels new_report_name = "_".join(level) new_report_name += "_" + os.path.basename(r) if os.path.basename(r).endswith("_management_report.html"): shutil.move(r, os.path.join("management", new_report_name)) if os.path.basename(r).endswith("_execution_results_report.html"): shutil.move(r, os.path.join("execution", new_report_name)) def insert_level_cmd(command, level = None, environment = None): if level: command.insert(2, "--level=" + level) if environment and level: command.insert(3, "--environment=" + environment) return command def get_manage_cmd(): vplat = vcast_platform() manage = os.path.join(os.getenv("VECTORCAST_DIR"), vplat.manage) return manage def run_command(cmd, capture_cmd = False): if isinstance(cmd, list): cmd = " ".join(cmd) print("Calling {:s} ... ".format(cmd)) cmd_output = [] cmd_split = cmd.split(" ") process = subprocess.Popen(cmd_split, stdout=subprocess.PIPE) while True: line = process.stdout.readline() if line != '': sys.stdout.write(line) if capture_cmd: cmd_output.append(line) sys.stdout.flush() else: break process.wait() exit_code = process.returncode print("\n{:s}".format(cmd)) print("Exit Code: {:s}".format(str(exit_code))) print("Command is done running!\n") return cmd_output def move_folder(dir_path="", base_folder=""): script_dir = os.path.dirname(os.path.normpath(__file__)) src_folder = os.path.join(script_dir, base_folder) dst_folder = os.path.join(dir_path, base_folder) dst_folder_old = dst_folder + "_old" if os.path.exists(dst_folder): # Renaming and removing folder is faster operation in Windows os.rename(dst_folder, dst_folder_old) shutil.rmtree(dst_folder_old, True) shutil.move(src_folder, dst_folder) def copy_to_bamboo_working_dir(bamboo_dir): print("") bamboo_vcast_reports_folder = os.path.join(bamboo_dir, "target") dst_juint_folder = os.path.join(bamboo_vcast_reports_folder, "junit") dst_clover_folder = os.path.join(bamboo_vcast_reports_folder, "clover") if not os.path.exists(bamboo_vcast_reports_folder): os.mkdir(bamboo_vcast_reports_folder) if not os.path.exists(dst_juint_folder): os.mkdir(dst_juint_folder) if not os.path.exists(dst_clover_folder): os.mkdir(dst_clover_folder) # Move the generated xml files to the bamboo working directory for f in glob.glob('xml_data/*_combined.xml'): if "coverage_results" in f: shutil.copy(f, dst_clover_folder) elif "test_results" in f: shutil.copy(f, dst_juint_folder) print("Moved VectorCAST XML files to Bamboo working directory {:s}".format(bamboo_dir)) # Move the generated HTML files to the bamboo working directory move_folder(bamboo_vcast_reports_folder, "execution") move_folder(bamboo_vcast_reports_folder, "management") print("Moved VectorCAST HTML files to Bamboo working directory {:s}".format(bamboo_dir)) def run(vcast_project, level = None): global manageProjectName manageProjectName = os.path.splitext(os.path.basename(vcast_project))[0] vceList, vcpList = getEnvironmentList(vcast_project, level) # What if there is existing XML data from another VectorCAST Project? # Make sure the folder is clean (Rename and remove is faster) if not os.path.exists("xml_data"): os.mkdir("xml_data") print "processing test results..." writeTestResults(vceList) print "processing coverage results..." writeCoverageResults(vceList) writeCoverageResults(vcpList) print "combining results..." bambooCombineTestResults(manageProjectName) bambooCombineCoverageResults(manageProjectName) print("Generate VectorCAST reports") # Create a dictionary of the execution test results and coverage reports # Key: environment_name # Values: List of tuple with (level, [execution_results_report.html, management_report.html]) report_dict = generate_reports(vcast_project) # Copy reports to be used as Bamboo artifacts copy_report_artifacts(report_dict) def main(): if DEBUGGING: vcast_project = r"C:\tmp\bamboo_wrkspace\enterprise_testing_demo.vcm" cleanup = True bamboo_dir = None else: parser = argparse.ArgumentParser() parser.add_argument('VectorCAST_Project', help='VectorCAST Project') parser.add_argument('-l', '--level', help='VectorCAST Project level') parser.add_argument('-d', '--bamboo_dir', action="store", required=True, help='Base directory of Bamboo Job folder') parser.add_argument('--no_cleanup', help='Do not cleanup temporary files.', action='store_false') args = parser.parse_args() vcast_project = args.VectorCAST_Project cleanup = args.no_cleanup level = args.level if args.bamboo_dir: bamboo_dir = os.path.normpath(args.bamboo_dir) if not os.path.exists(bamboo_dir): print("Bamboo directory {:s} does not exist".format(bamboo_dir)) print('Now exiting...') return 1 run(vcast_project, level) if bamboo_dir: copy_to_bamboo_working_dir(bamboo_dir) if cleanup: print "cleaning up..." bambooCleanupXMLFiles() if __name__ == "__main__": sys.exit(main())