def makeImageLink(self, graphFile): image = HTMLgen.Image(filename=graphFile, src=graphFile, height=100, width=150, border=0) return HTMLgen.Href(graphFile, image)
def getLinksToOverview(self, version, testName, extraVersion, linkFromDetailsToOverview): links = HTMLgen.Container() for targetFile, linkName in linkFromDetailsToOverview: testId = makeTestId(version, extraVersion, testName) links.append(HTMLgen.Href(targetFile + "#" + testId, linkName)) return links
def generateExtraVersionHeader(self, extraVersion): bgColour = self.colourFinder.find("column_header_bg") extraVersionElement = HTMLgen.Container(HTMLgen.Name(extraVersion), extraVersion) columnHeader = HTMLgen.TH(extraVersionElement, colspan=len(self.tags) + 1, bgcolor=bgColour) return HTMLgen.TR(columnHeader)
def generateSummaries(self, extraVersion=None): bgColour = self.colourFinder.find("column_header_bg") row = [HTMLgen.TD("Summary", bgcolor=bgColour)] for tag in self.tags: categoryHandler = self.categoryHandlers[tag] detailPageName = getDetailPageName(self.pageVersion, tag) summary = categoryHandler.generateHTMLSummary( detailPageName + "#" + self.version, extraVersion) row.append(HTMLgen.TD(summary, bgcolor=bgColour)) return HTMLgen.TR(*row)
def writeCommentListPage(self): filename = os.path.join(self.pageDir, "commentlist.html") plugins.log.info("Writing comment html page at " + filename + "...") doc = HTMLgen.SimpleDocument( title="All Comments", stylesheet="../javascript/commentliststyle.css", xhtml=True, meta='<meta charset="' + locale.getpreferredencoding() + '">') for scriptFile in ["jquery.js", "comment.js", "commentlist.js"]: doc.append(HTMLgen.Script(src="../javascript/" + scriptFile)) doc.write(filename)
def getHeaderLine(self, tests, version, linkFromDetailsToOverview): testName, state, extraVersion = tests[0] if len(tests) == 1: linksToOverview = self.getLinksToOverview( version, testName, extraVersion, linkFromDetailsToOverview) headerText = "TEST " + repr(state) + " " + testName + " (" container = HTMLgen.Container(headerText, linksToOverview) return HTMLgen.Heading(4, container, ")") else: headerText = str(len(tests)) + " TESTS " + repr(state) return HTMLgen.Heading(4, headerText)
def generateHTMLSummary(self, detailPageRef, extraVersion=None): numTests, summaryData = self.getSummaryData(extraVersion) container = HTMLgen.Container() for cat, count in summaryData: summary = HTMLgen.Text(self.getDescription(cat, count)) if cat == "success": container.append(summary) else: linkTarget = detailPageRef + getCategoryDescription(cat)[-1] container.append(HTMLgen.Href(linkTarget, summary)) testCountSummary = HTMLgen.Text(self.getTestCountDescription(numTests)) return HTMLgen.Container(testCountSummary, container)
def generateJenkinsChanges(self, pageDir): cacheDir = os.path.join(os.path.dirname(pageDir), "jenkins_changes") bgColour = self.colourFinder.find("changes_header_bg") row = [HTMLgen.TD("Changes", bgcolor=bgColour)] hasData = False prevTag = None for tag in self.tags: allChanges = self.findJenkinsChanges(prevTag, tag, cacheDir) cont = HTMLgen.Container() aborted = False for i, (authorOrMessage, target, bugs) in enumerate(allChanges): if i: cont.append(HTMLgen.BR()) if target: cont.append(HTMLgen.Href(target, authorOrMessage)) else: cont.append(HTMLgen.Font(authorOrMessage, color="red")) aborted = "Aborted" in authorOrMessage for bugText, bugTarget in bugs: cont.append(HTMLgen.Href(bugTarget, bugText)) hasData = True row.append(HTMLgen.TD(cont, bgcolor=bgColour)) if not aborted: prevTag = tag if hasData: return HTMLgen.TR(*row)
def getFilterScripts(self, pageColours): finder = ColourFinder(self.getConfigValue) rowHeaderColour = finder.find("row_header_bg") successColour = finder.find("success_bg") # Always put green at the start, we often want to filter that sortedColours = sorted(pageColours, key=lambda c: (c != successColour, c)) scriptCode = "var TEST_ROW_HEADER_COLOR = " + repr(rowHeaderColour) + ";\n" + \ "var Colors = " + repr(sortedColours) + ";" return [ HTMLgen.Script(code=scriptCode), HTMLgen.Script(src="../javascript/jquery.js"), HTMLgen.Script(src="../javascript/filter.js"), HTMLgen.Script(src="../javascript/comment.js") ]
def generateTestRows(self, testName, extraVersion, results): bgColour = self.colourFinder.find("row_header_bg") testId = makeTestId(self.version, extraVersion, testName) description = self.descriptionInfo.get(testName, "") container = HTMLgen.Container(HTMLgen.Name(testId), testName) rows = [] testRow = [ HTMLgen.TD(container, bgcolor=bgColour, title=self.escapeForHtml(description)) ] # Don't add empty rows to the table foundData = False bgcol = None for tag in self.tags: cellContent, bgcol, hasData = self.generateTestCell( tag, testName, testId, results) testRow.append(HTMLgen.TD(cellContent, bgcolor=bgcol)) foundData |= hasData if foundData: # We only filter based on the final column self.usedColours.add(bgcol) rows.append(HTMLgen.TR(*testRow)) else: return rows for resourceName in self.resourceNames: foundData = False resourceRow = [ HTMLgen.TD(HTMLgen.Emphasis("(" + resourceName + ")"), align="right") ] for tag in self.tags: cellContent, bgcol, hasData = self.generateTestCell( tag, testName, testId, results, resourceName) resourceRow.append( HTMLgen.TD(HTMLgen.Emphasis(cellContent), bgcolor=bgcol, align="right")) foundData |= hasData if foundData: rows.append(HTMLgen.TR(*resourceRow)) return rows
def addVersionSection(self, version, categoryHandler, linkFromDetailsToOverview): self.totalCategoryHandler.update(categoryHandler) container = HTMLgen.Container() container.append(HTMLgen.HR()) container.append(self.getSummaryHeading(version, categoryHandler)) for desc, testInfo in categoryHandler.getTestsWithDescriptions(): fullDescription = self.getFullDescription( testInfo, version, linkFromDetailsToOverview) if fullDescription: container.append(HTMLgen.Name(version + desc)) container.append( HTMLgen.Heading( 3, "Detailed information for the tests that " + desc + ":")) container.append(fullDescription) self.versionSections.append(container)
def createPage(self): style = "body,td {color: #000000;font-size: 11px;font-family: Helvetica;} th {color: #000000;font-size: 13px;font-family: Helvetica;}" title = "Test results for " + self.pageTitle return HTMLgen.SimpleDocument(title=title, style=style, xhtml=True, meta='<meta charset="' + locale.getpreferredencoding() + '">')
def getFullDescription(self, tests, version, linkFromDetailsToOverview): freeTextData = self.getFreeTextData(tests) if len(freeTextData) == 0: return fullText = HTMLgen.Container() for freeText, tests in freeTextData: tests.sort(key=lambda info: info[0]) for testName, _, extraVersion in tests: fullText.append( HTMLgen.Name(makeTestId(version, extraVersion, testName))) fullText.append( self.getHeaderLine(tests, version, linkFromDetailsToOverview)) self.appendFreeText(fullText, freeText) if len(tests) > 1: for line in self.getTestLines(tests, version, linkFromDetailsToOverview): fullText.append(line) return fullText
def getTestLines(self, tests, version, linkFromDetailsToOverview): lines = [] for testName, _, extraVersion in tests: linksToOverview = self.getLinksToOverview( version, testName, extraVersion, linkFromDetailsToOverview) headerText = testName + " (" container = HTMLgen.Container(headerText, linksToOverview, ")<br>") lines.append(container) return lines
def generateTestCell(self, tag, testName, testId, results, resourceName=""): state = results.get(tag) cellText, success, fgcol, bgcol = self.getCellData(state, resourceName) cellContent = HTMLgen.Font(cellText, color=fgcol) if success: return cellContent, bgcol, cellText != "N/A" else: linkTarget = getDetailPageName(self.pageVersion, tag) + "#" + testId tooltip = "'" + testName + "' failure for " + getDisplayText(tag) return HTMLgen.Href(linkTarget, cellContent, title=tooltip, style="color:black"), bgcol, True
def appendFreeText(self, fullText, freeText): freeText = freeText.replace("<", "<").replace(">", ">") linkMarker = "URL=http" if linkMarker in freeText: currFreeText = "" for line in freeText.splitlines(): if linkMarker in line: fullText.append( HTMLgen.RawText("<PRE>" + currFreeText.strip() + "</PRE>")) currFreeText = "" words = line.strip().split() linkTarget = words[-1][4:] # strip off the URL= newLine = " ".join(words[:-1]) fullText.append(HTMLgen.Href(linkTarget, newLine)) fullText.append(HTMLgen.BR()) else: currFreeText += line + "\n" else: currFreeText = freeText if currFreeText: fullText.append(HTMLgen.RawText("<PRE>" + currFreeText + "</PRE>"))
def generate(self, loggedTests, pageDir, repositoryDirs): table = HTMLgen.TableLite(border=0, cellpadding=4, cellspacing=2, width="100%") table.append(self.generateTableHead(repositoryDirs)) table.append(self.generateSummaries()) if os.getenv("JENKINS_URL"): changeRow = self.generateJenkinsChanges(pageDir) if changeRow: table.append(changeRow) hasRows = False for extraVersion, testInfo in list(loggedTests.items()): currRows = [] for test in sorted(testInfo.keys()): results = testInfo[test] rows = self.generateTestRows(test, extraVersion, results) if rows: currRows += rows if len(currRows) == 0: continue else: hasRows = True # Add an extra line in the table only if there are several versions. if len(loggedTests) > 1: fullVersion = self.version if extraVersion: fullVersion += "." + extraVersion table.append(self.generateExtraVersionHeader(fullVersion)) table.append(self.generateSummaries(extraVersion)) for row in currRows: table.append(row) if hasRows: table.append(HTMLgen.BR()) return table
def addTable(self, page, resourceNames, categoryHandlers, version, loggedTests, selector, tableHeader, filePath, graphHeading, repositoryDirs): graphDirname, graphFileRef = self.getGraphFileParts(filePath, version) testTable = self.getTestTable(self.getConfigValue, resourceNames, self.descriptionInfo, selector.selectedTags, categoryHandlers, self.pageVersion, version, os.path.join(graphDirname, graphFileRef)) table = testTable.generate(loggedTests, self.pageDir, repositoryDirs) if table: cells = [] if tableHeader: page.append(HTMLgen.HR()) cells.append(self.makeTableHeaderCell(tableHeader)) graphLink = None fullPath = os.path.abspath(os.path.join(graphDirname, graphFileRef)) if testTable.generateGraph(fullPath, graphHeading): graphLink = self.makeImageLink(graphFileRef.replace("\\", "/")) cells.append(HTMLgen.TD(graphLink)) if len(cells): row = HTMLgen.TR(*cells) initialTable = HTMLgen.TableLite(align="center") initialTable.append(row) page.append(initialTable) extraVersions = list(loggedTests.keys())[1:] if len(extraVersions) > 0: page.append(testTable.generateExtraVersionLinks(extraVersions)) page.append(table) return True, graphLink, testTable.usedColours else: return False, None, []
def __init__(self, tag, pageTitle, pageSubTitles): tagText = getDisplayText(tag) pageDetailTitle = "Detailed test results for " + pageTitle + ": " + tagText self.document = HTMLgen.SimpleDocument( title=TitleWithDateStamp(pageDetailTitle), meta='<meta charset="' + locale.getpreferredencoding() + '">') headerText = tagText + " - detailed test results for " + pageTitle self.document.append(HTMLgen.Heading(1, headerText, align='center')) for subTitle, command in pageSubTitles: self.document.append(HTMLgen.Center(HTMLgen.Emphasis(subTitle))) self.document.append( HTMLgen.Center( HTMLgen.Paragraph(command, style='font-family:monospace'))) self.totalCategoryHandler = CategoryHandler() self.versionSections = []
def generate(self, repositoryDirs, subPageNames, archiveUnused): minorVersionHeader = HTMLgen.Container() allMonthSelectors = set() latestMonth = None pageToGraphs = {} for version, repositoryDirInfo in list(repositoryDirs.items()): self.diag.info("Generating " + version) tagData, stateFiles, successFiles = self.findTestStateFilesAndTags( repositoryDirInfo) if len(stateFiles) > 0 or len(successFiles) > 0: tags = list(tagData.keys()) tags.sort(key=self.tagSortKey) selectors = self.makeSelectors(subPageNames, tags) monthSelectors = SelectorByMonth.makeInstances(tags) allMonthSelectors.update(monthSelectors) allSelectors = selectors + list(reversed(monthSelectors)) # If we already have month pages, we only regenerate the current one if len(self.getExistingMonthPages()) == 0: selectors = allSelectors else: currLatestMonthSel = monthSelectors[-1] if latestMonth is None or currLatestMonthSel.linkName == latestMonth: selectors.append(monthSelectors[-1]) latestMonth = currLatestMonthSel.linkName selectedTags = set() unusedTags = set(tags) for selector in selectors: currTags = set(selector.selectedTags) selectedTags.update(currTags) if archiveUnused: unusedTags.difference_update(currTags) tags = [t for t in tags if t in selectedTags] if archiveUnused and unusedTags: plugins.log.info( "Automatic repository cleaning will now remove old data for the following runs:" ) for tag in sorted(unusedTags, key=self.tagSortKey): plugins.log.info("- " + tag) plugins.log.info( "(To disable automatic repository cleaning in future, please run with the --manualarchive flag when collating the HTML report.)" ) self.removeUnused(unusedTags, tagData) loggedTests = OrderedDict() categoryHandlers = {} self.diag.info("Processing " + str(len(stateFiles)) + " teststate files") relevantFiles = 0 for stateFile, repository in stateFiles: tag = self.getTagFromFile(stateFile) if len(tags) == 0 or tag in tags: relevantFiles += 1 testId, state, extraVersion = self.processTestStateFile( stateFile, repository) loggedTests.setdefault(extraVersion, OrderedDict()).setdefault( testId, OrderedDict())[tag] = state categoryHandlers.setdefault( tag, CategoryHandler()).registerInCategory( testId, state.category, extraVersion, state) if relevantFiles % 100 == 0: self.diag.info("- Processed " + str(relevantFiles) + " files with matching tags so far") self.diag.info("Processed " + str(relevantFiles) + " relevant teststate files") self.diag.info("Processing " + str(len(successFiles)) + " success files") for successFile, repository in successFiles: testId = self.getTestIdentifier(successFile, repository) extraVersion = self.findExtraVersion(repository) with open(successFile) as f: fileTags = set() for line in f: parts = line.strip().split(" ", 1) if len(parts) != 2: continue tag, text = parts if tag in fileTags: sys.stderr.write( "WARNING: more than one result present for tag '" + tag + "' in file " + successFile + "!\n") sys.stderr.write("Ignoring later ones\n") continue fileTags.add(tag) if len(tags) == 0 or tag in tags: loggedTests.setdefault( extraVersion, OrderedDict()).setdefault( testId, OrderedDict())[tag] = text categoryHandlers.setdefault( tag, CategoryHandler()).registerInCategory( testId, "success", extraVersion, text) self.diag.info("Processed " + str(len(successFiles)) + " success files") versionToShow = self.removePageVersion(version) hasData = False for sel in selectors: filePath = self.getPageFilePath(sel) if filePath in self.pagesOverview: page, pageColours = self.pagesOverview[filePath] else: page = self.createPage() pageColours = set() self.pagesOverview[filePath] = page, pageColours tableHeader = self.getTableHeader(version, repositoryDirs) heading = self.getHeading(versionToShow) hasNewData, graphLink, tableColours = self.addTable( page, self.resourceNames, categoryHandlers, version, loggedTests, sel, tableHeader, filePath, heading, repositoryDirInfo) hasData |= hasNewData pageColours.update(tableColours) if graphLink: pageToGraphs.setdefault(page, []).append(graphLink) if hasData and versionToShow: link = HTMLgen.Href("#" + version, versionToShow) minorVersionHeader.append(link) # put them in reverse order, most relevant first linkFromDetailsToOverview = [ sel.getLinkInfo(self.pageVersion) for sel in allSelectors ] for tag in tags: details = self.pagesDetails.setdefault( tag, TestDetails(tag, self.pageTitle, self.pageSubTitles)) details.addVersionSection(version, categoryHandlers[tag], linkFromDetailsToOverview) selContainer = HTMLgen.Container() selectors = self.makeSelectors(subPageNames) for sel in selectors: target, linkName = sel.getLinkInfo(self.pageVersion) selContainer.append(HTMLgen.Href(target, linkName)) monthContainer = HTMLgen.Container() if len(allMonthSelectors) == 1: # Don't want just one month, no navigation possible prevMonth = list(allMonthSelectors)[0].getPreviousMonthSelector() allMonthSelectors.add(prevMonth) for sel in sorted(allMonthSelectors, key=lambda s: s.sortKey()): target, linkName = sel.getLinkInfo(self.pageVersion) monthContainer.append(HTMLgen.Href(target, linkName)) for page, pageColours in list(self.pagesOverview.values()): if len(monthContainer.contents) > 0: page.prepend(HTMLgen.Heading(2, monthContainer, align='center')) graphs = pageToGraphs.get(page) page.prepend(HTMLgen.Heading(2, selContainer, align='center')) if minorVersionHeader.contents: if not graphs is None and len(graphs) > 1: page.prepend(HTMLgen.Heading(1, *graphs, align='center')) page.prepend( HTMLgen.Heading(1, minorVersionHeader, align='center')) creationDate = TitleWithDateStamp("").__str__().strip() page.prepend(HTMLgen.Paragraph(creationDate, align="center")) page.prepend(HTMLgen.Heading(1, self.getHeading(), align='center')) if len(pageColours) > 0: page.prepend(HTMLgen.BR()) page.prepend(HTMLgen.BR()) page.script = self.getFilterScripts(pageColours) self.writePages()
def getSummaryHeading(self, version, categoryHandler): return HTMLgen.Heading( 2, version + ": " + categoryHandler.generateTextSummary())
def makeTableHeaderCell(self, tableHeader): container = HTMLgen.Container() container.append(HTMLgen.Name(tableHeader)) container.append( HTMLgen.U(HTMLgen.Heading(1, tableHeader, align='center'))) return HTMLgen.TD(container)
def generateTableHead(self, repositoryDirs): head = [HTMLgen.TH("Test")] ciUrl = os.getenv("JENKINS_URL") or os.getenv( "SYSTEM_TEAMFOUNDATIONSERVERURI") runNameDirs = self.getRunNameDirs(repositoryDirs) if ciUrl else [] for tag in self.tags: tagColour = self.findTagColour(tag) linkTarget = getDetailPageName(self.pageVersion, tag) linkText = HTMLgen.Font(getDisplayText(tag), color=tagColour) buildNumber = self.getCiBuildNumber(tag) if ciUrl and buildNumber.isdigit(): runEnv = getEnvironmentFromRunFiles(runNameDirs, tag) container = HTMLgen.Container() tooltip = jenkinschanges.getTimestamp(buildNumber) container.append( HTMLgen.Href(linkTarget, linkText, title=tooltip)) container.append(HTMLgen.BR()) ciTitle, ciTarget = self.getCiLinkData(runEnv, buildNumber) ciText = HTMLgen.Emphasis( HTMLgen.Font("(" + ciTitle + ")", size=1)) container.append(HTMLgen.Href(ciTarget, ciText, title=tooltip)) head.append(HTMLgen.TH(container)) else: head.append(HTMLgen.TH(HTMLgen.Href(linkTarget, linkText))) heading = HTMLgen.TR() heading = heading + head return heading
def generateTableHead(self, repositoryDirs): head = [HTMLgen.TH("Test")] jenkinsUrl = os.getenv("JENKINS_URL") runNameDirs = self.getRunNameDirs(repositoryDirs) if jenkinsUrl else [] for tag in self.tags: tagColour = self.findTagColour(tag) linkTarget = getDetailPageName(self.pageVersion, tag) linkText = HTMLgen.Font(getDisplayText(tag), color=tagColour) buildNumber = self.getJenkinsBuildNumber(tag) if jenkinsUrl and buildNumber.isdigit(): runEnv = getEnvironmentFromRunFiles(runNameDirs, tag) container = HTMLgen.Container() tooltip = jenkinschanges.getTimestamp(buildNumber) container.append( HTMLgen.Href(linkTarget, linkText, title=tooltip)) container.append(HTMLgen.BR()) jobTarget = os.path.join(self.getRunEnv(runEnv, "JENKINS_URL"), "job", self.getRunEnv(runEnv, "JOB_NAME"), buildNumber) jobText = HTMLgen.Emphasis( HTMLgen.Font("(Jenkins " + buildNumber + ")", size=1)) container.append( HTMLgen.Href(jobTarget, jobText, title=tooltip)) head.append(HTMLgen.TH(container)) else: head.append(HTMLgen.TH(HTMLgen.Href(linkTarget, linkText))) heading = HTMLgen.TR() heading = heading + head return heading
def generateExtraVersionLinks(self, extraVersions): cont = HTMLgen.Container() for extra in extraVersions: fullName = self.version + "." + extra cont.append(HTMLgen.Href("#" + fullName, extra)) return HTMLgen.Heading(2, cont, align='center')