def renderPinReference(self, reference_name, repoRef, includeName=False): if includeName: preamble = reference_name + "->" else: preamble = "" repoName = "/".join(repoRef.reference.split("/")[:-1]) commitHash = repoRef.reference.split("/")[-1] repo = self.testManager.database.Repo.lookupAny(name=repoName) if not repo: return preamble + HtmlGeneration.lightGreyWithHover( repoRef.reference, "Can't find repo %s" % repoName) commit = self.testManager.database.Commit.lookupAny( repo_and_hash=(repo, commitHash)) if not commit: return preamble + HtmlGeneration.lightGreyWithHover( repoRef.reference[:--30], "Can't find commit %s" % commitHash[:10]) branches = { k.branchname: v for k, v in self.testManager.commitFindAllBranches( commit).iteritems() } if repoRef.branch not in branches: return preamble + self.contextFor(commit).renderLink() return preamble + self.contextFor(commit).renderLink()
def renderPageBody(self): test = self.test if self.currentView() == "test_results": return self.renderIndividualTestResults() if self.currentView() == "test_runs": testRuns = self.testManager.database.TestRun.lookupAll(test=test) if not testRuns: return card("No runs of this test") return HtmlGeneration.grid(self.gridForTestList_(testRuns)) if self.currentView() == "test_definition": return card( '<pre class="language-yaml"><code class="line-numbers">%s</code></pre>' % cgi.escape( algebraic_to_json.encode_and_dump_as_yaml(self.testManager.definitionForTest(test)) ) ) if self.currentView() == "test_dependencies": grid = self.allTestDependencyGrid() if not grid: return card("No dependencies") return HtmlGeneration.grid(grid)
def artifactsForTestRunGrid(self): testRun = self.testRun grid = [["Artifact", "Size"]] if testRun.test.testDefinitionSummary.type == "Build": for artifact in testRun.test.testDefinitionSummary.artifacts: full_name = testRun.test.testDefinitionSummary.name + ("/" + artifact if artifact else "") build_key = self.renderer.artifactStorage.sanitizeName(full_name) + ".tar.gz" if self.renderer.artifactStorage.build_exists(testRun.test.hash, build_key): grid.append([ HtmlGeneration.link(full_name + ".tar.gz", self.renderer.buildDownloadUrl(testRun.test.hash, build_key)), HtmlGeneration.bytesToHumanSize(self.renderer.artifactStorage.build_size(testRun.test.hash, build_key)) ]) for artifactName, sizeInBytes in self.renderer.artifactStorage.testResultKeysForWithSizes(testRun.test.hash, testRun._identity): name = self.renderer.artifactStorage.unsanitizeName(artifactName) if not name.startswith(ArtifactStorage.TEST_LOG_NAME_PREFIX): grid.append([ HtmlGeneration.link( name, self.renderer.testResultDownloadUrl(testRun._identity, artifactName) ), HtmlGeneration.bytesToHumanSize(sizeInBytes) ]) if not grid: return card("No Test Artifacts produced") return HtmlGeneration.grid(grid)
def renderPinUpdateLink(self, branch, reference_name, repoRef): if repoRef.auto and repoRef.auto != "false": return HtmlGeneration.lightGrey("marked auto") else: commit = branch.head targetRepoName = "/".join(repoRef.reference.split("/")[:-1]) target_branch = self.testManager.database.Branch.lookupAny( reponame_and_branchname=(targetRepoName, repoRef.branch)) if not target_branch: return HtmlGeneration.lightGrey("unknown branch %s" % repoRef.branch) if target_branch.head.hash == repoRef.reference.split("/")[-1]: return HtmlGeneration.lightGrey("up to date") message = "push commit updating pin of %s from %s to %s" % ( reference_name, target_branch.head.hash, repoRef.reference.split("/")[-1]) params = { "redirect": self.redirect(), "repoName": commit.repo.name, "branchName": branch.branchname, "ref": reference_name } return ('<a href="/updateBranchPin?' + urllib.urlencode(params) + '" title="' + message + '">' '<span class="octicon octicon-sync " aria-hidden="true" />' '</a>')
def renderPageBody(self): mm = self.testManager.machine_management if self.options.get("amiLogs"): ami,hash = self.options.get("amiLogs").split("_") url = mm.amiConfigLogUrl(ami,hash) if url: raise cherrypy.HTTPRedirect(url) else: return HtmlGeneration.card("No logs available") if self.options.get("amiSetupScript"): ami,hash = self.options.get("amiSetupScript").split("_") url = mm.amiConfigLogUrl(ami,hash, "InstallScript") if url: raise cherrypy.HTTPRedirect(url) else: return HtmlGeneration.card("No script available") osConfigs = set( list(mm.windowsOsConfigsAvailable) + list(mm.windowsOsConfigsBeingCreated) + list(mm.invalidWindowsOsConfigs) ) grid = [["BaseAmi", "Hash", "Status", "", ""]] for osConfig in sorted(osConfigs, key=lambda c: (c.ami, c.setupHash)): ami,contentHash = osConfig.ami, osConfig.setupHash status = ( "OK" if osConfig in mm.windowsOsConfigsAvailable else "In progress" if osConfig in mm.windowsOsConfigsBeingCreated else "Invalid" ) if status in ("OK", "Invalid"): logsButton = HtmlGeneration.Link( self.withOptions(amiLogs=ami+"_"+contentHash).urlString(), "Logs", is_button=True, button_style='btn-primary btn-xs' ).render() else: logsButton = "" scriptButton = HtmlGeneration.Link( self.withOptions(amiSetupScript=ami+"_"+contentHash).urlString(), "Setup Script", is_button=True, button_style='btn-primary btn-xs' ).render() grid.append([ami,contentHash,status, logsButton, scriptButton]) return HtmlGeneration.grid(grid)
def renderIndividualTestResults(self): #show broken out tests over the last N commits rows = [self.testRun] def rowLinkFun(row): return self.contextFor(row).renderLink(includeCommit=False, includeTest=False) def testFun(row): return [row] def cellUrlFun(testGroup, row): return None def rowContextFun(row): return row renderer = IndividualTestGridRenderer.IndividualTestGridRenderer( rows, self, testFun, cellUrlFun, rowContextFun ) grid = [["Test Run", "Logs", "Elapsed (Min)", "Status", ""] + renderer.headers()] for testRun in rows: row = [rowLinkFun(testRun),self.renderer.testLogsButton(testRun._identity)] if testRun.endTimestamp > 0.0: elapsed = (testRun.endTimestamp - testRun.startedTimestamp) / 60.0 else: elapsed = (time.time() - testRun.startedTimestamp) / 60.0 row.append("%.2f" % elapsed) if testRun.endTimestamp > 0.0: row.append("passed" if testRun.success else "failed") else: row.append("running") row.append(" ") grid.append(row + renderer.gridRow(testRun)) grid = HtmlGeneration.transposeGrid(grid) return HtmlGeneration.grid(grid, dataTables=True, header_rows=5)
def renderPageBody(self): deployments = sorted( self.testManager.database.Deployment.lookupAll(isAlive=True), key=lambda d: d.createdTimestamp) grid = [["COMMIT", "TEST", "BOOTED AT", "UP FOR", "CLIENTS", "", ""]] for d in deployments: row = [] commit = self.testManager.oldestCommitForTest(d.test) repo = commit.repo row.append(self.contextFor(commit).renderLink()) row.append(d.test.testDefinitionSummary.name) row.append(time.asctime(time.gmtime(d.createdTimestamp))) row.append(secondsUpToString(time.time() - d.createdTimestamp)) row.append( str( self.testManager.streamForDeployment( d._identity).clientCount())) row.append(self.connectDeploymentLink(d)) row.append(self.shutdownDeploymentLink(d)) grid.append(row) return HtmlGeneration.grid(grid)
def cancelTestRunButton(self, testRunId): return HtmlGeneration.Link( self.address + "/cancelTestRun?" + urllib.urlencode({"testRunId":testRunId, "redirect": self.redirect()}), "cancel", is_button=True, button_style=self.disable_if_cant_write('btn-primary btn-xs') )
def renderLink(self, includeCommit=True, includeTest=True): res = "" if includeCommit: res = self.contextFor(self.commit).renderLink() if includeTest: if res: res = res + "/" res = res + HtmlGeneration.link(self.test.testDefinitionSummary.name, self.contextFor(self.test).urlString()) if res: res = res + "/" return res + HtmlGeneration.link(self.testRun._identity[:8], self.urlString())
def renderProjectAndFilterCrossGrid(self): projects = set() configurations = set() for t in self.allTests(): if t.testDefinitionSummary.type == "Test" and self.shouldIncludeTest( t): projects.add(t.testDefinitionSummary.project) configurations.add(t.testDefinitionSummary.configuration) renderer = TestGridRenderer.TestGridRenderer( sorted(projects), lambda p: [ t for t in self.allTests() if t.testDefinitionSummary.project == p and self.shouldIncludeTest(t) ], lambda group: self.contextFor( ComboContexts.CommitAndFilter(self.commit, group, "") ).renderNavbarLink(textOverride=group), lambda group, row: self.contextFor( ComboContexts.CommitAndFilter(self.commit, group, row)). urlString(), lambda test: test.testDefinitionSummary.configuration) grid = [["PROJECT"] + renderer.headers()] for p in sorted(projects): gridrow = renderer.gridRow(p) grid.append([ self.contextFor( ComboContexts.CommitAndFilter( self.commit, "", p)).renderLink(textOverride=p) ] + gridrow) return HtmlGeneration.grid(grid)
def shutdownDeploymentLink(self, d): return HtmlGeneration.Link("/shutdownDeployment?deploymentId=" + d._identity, "shutdown", is_button=True, new_tab=True, button_style='btn-primary btn-xs')
def connectDeploymentLink(self, d): return HtmlGeneration.Link("/terminalForDeployment?deploymentId=" + d._identity, "connect", is_button=True, new_tab=True, button_style='btn-primary btn-xs')
def renderPageBody(self): if self.options.get("action", ""): self.handleAction() return HtmlGeneration.Redirect( self.withOptionsReset( view=self.options.get("view")).urlString()) view = self.currentView() if view == "commit_data": return self.renderCommitDataView() if view == "test_definitions": return self.renderCommitTestDefinitionsInfo() if view == "test_suites": return self.renderTestSuitesSummary() if view == "test_builds": return self.renderTestSuitesSummary(builds=True) if view == "test_results": return self.renderTestResultsGrid() if view == "repo_refs": return self.renderRepoReferencesGrid() return card( 'Unknown view "<span class="font-weight-bold">%s</span>"' % view)
def deleteTestRunButton(self, testId): return HtmlGeneration.Link( self.deleteTestRunUrl(testId), "CLEAR", is_button=True, button_style=self.disable_if_cant_write('btn-primary btn-xs') )
def renderLink(self, includeCommit=True, nameOverride=None): if includeCommit: res = self.contextFor(self.commit).renderLink() else: res = '' return res + HtmlGeneration.link(nameOverride or self.testName, self.urlString())
def renderLink(self, includeRepo=True, includeBranch=True, textOverride=None): res = "" if includeRepo: assert includeBranch res += self.contextFor(self.repo).renderLink() if includeBranch and not self.branch: name = self.commit.hash[:10] else: if includeBranch: if res: res += "/" res += self.contextFor( self.branch).renderLink(includeRepo=False) name = self.nameInBranch if not includeRepo and not includeBranch: name = "HEAD" + name elif not name: name = "/HEAD" else: if len(name) < 5: name += " " * max(0, 5 - len(name)) hover_text = cgi.escape( self.commit.data.commitMessage) if self.commit.data else None return (res if not textOverride else "") + HtmlGeneration.link( textOverride or name, self.urlString(), hover_text=hover_text)
def testLogsButton(self, testId): return HtmlGeneration.Link( self.testLogsUrl(testId), "LOGS", is_button=True, button_style=self.disable_if_cant_write('btn-primary btn-xs') )
def reload_link(self): return HtmlGeneration.Link( "/reloadSource?" + urllib.urlencode({'redirect': self.redirect()}), '<span class="octicon octicon-sync" aria-hidden="true" style="horizontal-align:center"></span>', is_button=True, button_style='btn-outline-primary btn-xs' )
def renderPageBody(self): headers, grid = self.grid() if not headers: res = card("No repos found") else: res = HtmlGeneration.grid(headers + grid, header_rows=len(headers)) return res
def renderContentCallout(self): detail_header = "Commit Info" detail = self.commitMessageDetail() return HtmlGeneration.popover(contents=octicon("comment"), detail_title=detail_header, detail_view=detail, width=600, data_placement="right")
def renderPageBody(self): view = self.currentView() if view == "branches": headers, grid = self.grid() return HtmlGeneration.grid(headers+grid, header_rows=len(headers)) if view == "configuration": return self.configurationView() if view == "logs": return self.logsView()
def renderLinkWithShaHash(self, noIcon=False): if not self.commit.data: return '' return (octicon("git-commit") if not noIcon else "") + HtmlGeneration.link( "<code>" + self.commit.hash[:8] + "</code>", self.urlString(), hover_text=("commit " + self.commit.hash[:10] + " : " + ("" if not self.commit.data else self.commit.data.commitMessage)))
def logsView(self): grid = [["Timestamp", "Message"]] log = self.repo.branchCreateLogs if not log: return card("No logs so far") while log and len(grid) < 100: grid.append([time.asctime(time.gmtime(log.timestamp)), "<pre>" + cgi.escape(log.msg) + "</pre>"]) log = log.prior return HtmlGeneration.grid(grid)
def configurationView(self): if self.repo.branchCreateTemplates is None: self.repo.branchCreateTemplates = [] if self.options.get('action', None) == "new_template": self.repo.branchCreateTemplates = list(self.repo.branchCreateTemplates) + [ self.database.BranchCreateTemplate.New() ] return HtmlGeneration.Redirect(self.withOptions(action=None).urlString()) if self.options.get('action', None) == "update_template": template = self.database.BranchCreateTemplate(str(self.options.get("identity"))) assert template.exists() and template in self.repo.branchCreateTemplates template.globsToInclude = [str(x) for x in self.options.get("include_pats").split("\n")] template.globsToExclude = [str(x) for x in self.options.get("exclude_pats").split("\n")] template.suffix = str(self.options.get("suffix")) template.branchToCopyFrom = str(self.options.get("branch")) template.def_to_replace = str(self.options.get("def_to_replace")) template.disableOtherAutos = bool(self.options.get("disableOtherAutos")) template.autoprioritizeBranch = bool(self.options.get("autoprioritizeBranch")) template.deleteOnUnderlyingRemoval = bool(self.options.get("deleteOnUnderlyingRemoval")) return HtmlGeneration.Redirect(self.withOptions(action=None).urlString()) result = "" for template in self.repo.branchCreateTemplates: result += card(self.renderTemplateUpdateForm(template)) result += card( HtmlGeneration.Link( self.withOptions(action='new_template').urlString(), "Create new Branch Template", is_button=True, button_style=self.renderer.disable_if_cant_write('btn-primary btn-xs'), hover_text="Create a new branch-creation template." ).render() ) return result
def toggleBranchUnderTestLink(self, branch): icon = "octicon-triangle-right" hover_text = "%s testing this branch" % ("Pause" if branch.isUnderTest else "Start") button_style = "btn-xs " + ("btn-primary active" if branch.isUnderTest else "btn-outline-dark") return HtmlGeneration.Link( "/toggleBranchUnderTest?" + urllib.urlencode({'repo': branch.repo.name, 'branchname':branch.branchname, 'redirect': self.redirect()}), '<span class="octicon %s" aria-hidden="true" style="horizontal-align:center"></span>' % icon, is_button=True, button_style=self.disable_if_cant_write(button_style), hover_text=hover_text )
def getBranchCommitRow(self, commit, renderer): row = [self.getContextForCommit(commit).renderLinkWithShaHash()] all_tests = self.testManager.allTestsForCommit(commit) if all_tests: row[-1] += " " + self.contextFor( commit).toggleCommitUnderTestLink() row.extend(renderer.gridRow(commit)) if False: row.append( HtmlGeneration.lightGrey("waiting to load commit") if not commit.data else HtmlGeneration.lightGrey("no test file") if commit.data.noTestsFound else HtmlGeneration. lightGrey("invalid test file" ) if commit.data.testDefinitionsError else "") row.append(self.contextFor(commit).renderSubjectAndAuthor()) return row
def renderProjectAndFilterCrossGridOverCommits(self, configFilter): projects = set() for t in self.allTests(): if t.testDefinitionSummary.type == "Test" and self.shouldIncludeTest( t): projects.add(t.testDefinitionSummary.project) commits = [self.commit] while len(commits) < self.commitsToRender( ) and commits[-1].data and commits[-1].data.parents: commits.append(commits[-1].data.parents[-1]) grid = [] renderers = [] for c in commits: def makeRenderer(commit): return TestGridRenderer.TestGridRenderer( sorted(projects), lambda p: [ t for t in self.allTests() if self.shouldIncludeTest( t) and t.testDefinitionSummary.project == p and t. testDefinitionSummary.configuration == configFilter ], lambda group: self.contextFor( ComboContexts.CommitAndFilter(commit, configFilter, group)).renderLink( textOverride=group, includeRepo=False, includeBranch=False), lambda group, row: self.contextFor( ComboContexts.CommitAndFilter(commit, group, row) ).urlString(), lambda test: "") renderers.append(makeRenderer(c)) grid = [[""] + [renderer.headers()[0] for renderer in renderers]] for project in sorted(projects): gridrow = [renderer.gridRow(project)[0] for renderer in renderers] grid.append([ self.contextFor( ComboContexts.CommitAndFilter(self.commit, configFilter, project)).renderLink( textOverride=project) ] + gridrow) return HtmlGeneration.grid(grid)
def renderPageBody(self): view = self.options.get("view", "commits") if view == "commits": return self.testDisplayForCommits( self.testManager.commitsToDisplayForBranch( self.branch, self.maxCommitCount())) elif view == "pins": pinGrid = self.pinGridWithUpdateButtons(self.branch) if len(pinGrid) > 1: pinContents = (HtmlGeneration.grid(pinGrid)) else: pinContents = card("Branch has no pins.") return pinContents
def renderCommitTestDefinitionsInfo(self): raw_text, extension = self.testManager.getRawTestFileForCommit( self.commit) post_text = HtmlGeneration.Link( self.withOptions(action="force_reparse").urlString(), "Force Test Reparse", is_button=True, button_style=self.renderer.disable_if_cant_write( 'btn-primary btn-xs mt-4')).render() if raw_text: return card( '<pre class="language-yaml"><code class="line-numbers">%s</code></pre>' % cgi.escape(raw_text)) + post_text else: return card("No test definitions found") + post_text
def renderRepoReferencesGrid(self): lines = [["refname", "Commit", "Target Branch"]] if not self.commit.data: return card("Commit data not loaded yet.") if not self.commit.data.repos: return card("Commit has no references to external repos.") for refname, repoRef in sorted(self.commit.data.repos.iteritems()): if repoRef.matches.Pin: lines.append([ refname, self.renderPinReference(refname, repoRef), repoRef.branchname() if repoRef.branchname() else "" ]) return HtmlGeneration.grid(lines)