您最多选择25个主题 主题必须以字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符

GenerateBuildTestAndStagingReport.py 11KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185
  1. from BuildDemos import demos
  2. import argparse, requests, json, subprocess, re, pickle
  3. parser = argparse.ArgumentParser()
  4. parser.add_argument("version", type=str, help="Vaadin version that was just built")
  5. parser.add_argument("deployUrl", type=str, help="Base url of the deployment server")
  6. parser.add_argument("buildResultUrl", type=str, help="URL for the build result page")
  7. parser.add_argument("teamcityUser", type=str, help="Teamcity username to use")
  8. parser.add_argument("teamcityPassword", type=str, help="Password for given teamcity username")
  9. parser.add_argument("teamcityUrl", type=str, help="Address to the teamcity server")
  10. parser.add_argument("buildId", type=str, help="ID of the build to generate this report for")
  11. parser.add_argument("frameworkRepoUrl", type=str, help="URL to the framework staging repository")
  12. parser.add_argument("archetypeRepoUrl", type=str, help="URL to the archetype staging repository")
  13. parser.add_argument("pluginRepoUrl", type=str, help="URL to the plugin staging repository")
  14. args = parser.parse_args()
  15. def createTableRow(*columns):
  16. html = "<tr>"
  17. for column in columns:
  18. html += "<td>" + column + "</td>"
  19. return html + "</tr>"
  20. def getHtmlList(array):
  21. html = "<ul>"
  22. for item in array:
  23. html += "<li>" + item + "</li>"
  24. return html + "</ul>"
  25. def getBuildStatusHtml():
  26. build_steps_request_string = "http://{}/app/rest/problemOccurrences?locator=build:{}".format(args.teamcityUrl, args.buildId)
  27. build_steps_request = requests.get(build_steps_request_string, auth=(args.teamcityUser, args.teamcityPassword), headers={'Accept':'application/json'})
  28. if build_steps_request.status_code != 200:
  29. return createTableRow(traffic_light.format(color="black"), "Build status: unable to retrieve status of build")
  30. else:
  31. build_steps_json = build_steps_request.json()
  32. if build_steps_json["count"] == 0:
  33. return createTableRow(traffic_light.format(color="green"), "Build status: all build steps successful")
  34. else:
  35. return createTableRow(traffic_light.format(color="red"), "Build status: there are failing build steps, <a href={}>check the build report</a>".format(args.buildResultUrl))
  36. def getTestStatusHtml():
  37. test_failures_request_string = "http://{}/app/rest/testOccurrences?locator=build:{},status:FAILURE".format(args.teamcityUrl, args.buildId)
  38. test_failures_request = requests.get(test_failures_request_string, auth=(args.teamcityUser, args.teamcityPassword), headers={'Accept':'application/json'})
  39. if test_failures_request.status_code != 200:
  40. return createTableRow(traffic_light.format(color="black"), "Test status: unable to retrieve status of tests")
  41. else:
  42. test_failures_json = test_failures_request.json()
  43. if test_failures_json["count"] == 0:
  44. return createTableRow(traffic_light.format(color="green"), "Test status: all tests passing")
  45. else:
  46. return createTableRow(traffic_light.format(color="red"), "Test status: there are " + str(test_failures_json["count"]) + " failing tests, <a href=\"http://r2d2.devnet.vaadin.com/viewLog.html?buildId={}&buildTypeId=Vaadin80_Releases_BuildTestAndStageRelease&tab=testsInfo\">see report</a>.".format(args.buildId))
  47. def getDemoValidationStatusHtml():
  48. status = pickle.load(open("result/demo_validation_status.pickle", "rb"))
  49. if status["error"]:
  50. return createTableRow(traffic_light.format(color="red"), getHtmlList(status["messages"]))
  51. else:
  52. return createTableRow(traffic_light.format(color="green"), getHtmlList(status["messages"]))
  53. def getDemoLinksHtml():
  54. demos_html = "Try demos"
  55. link_list = list(map(lambda demo: "<a href='{url}/{demoName}-{version}'>{demoName}</a>".format(url=args.deployUrl, demoName=demo, version=args.version), demos))
  56. return demos_html + getHtmlList(link_list)
  57. def getApiDiffHtml():
  58. apidiff_html = "Check API diff"
  59. modules = [
  60. "client", "client-compiler",
  61. "compatibility-client",
  62. "compatibility-server",
  63. "compatibility-shared",
  64. "server", "shared"
  65. ]
  66. link_list = list(map(lambda module: "<li><a href='http://r2d2.devnet.vaadin.com/repository/download/Vaadin80_Releases_BuildTestAndStageRelease/{}:id/apidiff/{}/japicmp.html'>{}</a></li>".format(args.buildId, module, module), modules))
  67. return apidiff_html + getHtmlList(link_list)
  68. def getDirs(url):
  69. page = requests.get(url)
  70. files = re.findall('<a href=.*>(.*)</a>', page.text)
  71. dirs = filter(lambda x: x.endswith('/'), files)
  72. return list(map(lambda x: x.replace('/', ''), dirs))
  73. def dirTree(url):
  74. dirs = getDirs(url)
  75. result = []
  76. for d in dirs:
  77. result.append(d)
  78. subDirs = list(map(lambda x: d + '/' + x, dirTree(url + '/' + d)))
  79. result.extend(subDirs)
  80. return result
  81. def getAllowedArtifactPaths(allowedArtifacts):
  82. result = []
  83. for artifact in allowedArtifacts:
  84. parts = artifact.split('/', 1)
  85. result.append(parts[0])
  86. if len(parts) > 1:
  87. subart = getAllowedArtifactPaths([ parts[1] ])
  88. subArtifacts = list(map(lambda x: parts[0] + '/' + x, subart))
  89. result.extend(subArtifacts)
  90. return result
  91. def checkStagingContents(url, allowedArtifacts):
  92. dirs = dirTree(url)
  93. allowedDirs = getAllowedArtifactPaths(allowedArtifacts)
  94. return set(dirs) == set(allowedDirs)
  95. def getStagingContentsHtml(repoUrl, allowedArtifacts, name):
  96. if checkStagingContents(repoUrl, allowedArtifacts):
  97. return createTableRow(traffic_light.format(color="green"), "No extra artifacts found in the {} staging repository. <a href=\"{}\">Link to the repository.</a>".format(name, repoUrl))
  98. else:
  99. return createTableRow(traffic_light.format(color="red"), "Extra artifacts found in the {} staging repository. <a href=\"{}\">Link to the repository.</a>".format(name, repoUrl))
  100. def completeArtifactName(artifactId, version):
  101. return 'com/vaadin/' + artifactId + '/' + version
  102. def completeArtifactNames(artifactIds, version):
  103. return list(map(lambda x: completeArtifactName(x, version), artifactIds))
  104. allowedPluginArtifacts = completeArtifactNames([ 'vaadin-maven-plugin' ], args.version)
  105. allowedArchetypeArtifacts = completeArtifactNames([ 'vaadin-archetype-application', 'vaadin-archetype-application-multimodule', 'vaadin-archetype-application-example', 'vaadin-archetype-widget', 'vaadin-archetype-liferay-portlet' ], args.version)
  106. allowedFrameworkArtifacts = completeArtifactNames([ 'vaadin-root', 'vaadin-bom', 'vaadin-shared', 'vaadin-server', 'vaadin-client', 'vaadin-client-compiler', 'vaadin-client-compiled', 'vaadin-push', 'vaadin-themes', 'vaadin-widgets', 'vaadin-compatibility-shared', 'vaadin-compatibility-server', 'vaadin-compatibility-client', 'vaadin-compatibility-client-compiled', 'vaadin-compatibility-themes' ], args.version)
  107. content = "<html><head></head><body><table>"
  108. traffic_light = "<svg width=\"20px\" height=\"20px\" style=\"padding-right:5px\"><circle cx=\"10\" cy=\"10\" r=\"10\" fill=\"{color}\"/></svg>"
  109. # Build step status
  110. content += getBuildStatusHtml()
  111. # Test failures
  112. content += getTestStatusHtml()
  113. # Missing @since tags
  114. try:
  115. p1 = subprocess.Popen(['find', '.', '-name', '*.java'], stdout=subprocess.PIPE)
  116. p2 = subprocess.Popen(['xargs', 'egrep', '-n', '@since ?$'], stdin=p1.stdout, stdout=subprocess.PIPE)
  117. missing = subprocess.check_output(['egrep', '-v', '/(testbench|test|tests|target)/'], stdin=p2.stdout)
  118. content += createTableRow(traffic_light.format(color="red"), "Empty @since:<br><pre>%s</pre>" % (missing))
  119. except subprocess.CalledProcessError as e:
  120. if e.returncode == 1:
  121. content += createTableRow(traffic_light.format(color="green"), "No empty @since")
  122. else:
  123. raise e
  124. # check staging repositories don't contain extra artifacts
  125. content += getStagingContentsHtml(args.frameworkRepoUrl, allowedFrameworkArtifacts, "framework")
  126. content += getStagingContentsHtml(args.archetypeRepoUrl, allowedArchetypeArtifacts, "archetype")
  127. content += getStagingContentsHtml(args.pluginRepoUrl, allowedPluginArtifacts, "plugin")
  128. content += createTableRow("", "<h2>Manual checks before publishing</h2>")
  129. # try demos
  130. content += createTableRow("", getDemoLinksHtml())
  131. # link to release notes
  132. content += createTableRow("", "<a href=\"http://r2d2.devnet.vaadin.com/repository/download/Vaadin80_Releases_BuildTestAndStageRelease/{}:id/release-notes/release-notes.html\">Check release notes</a>".format(args.buildId))
  133. # link to api diff
  134. content += createTableRow("", getApiDiffHtml())
  135. # closed fixed tickets without a milestone
  136. content += createTableRow("", "<a href=\"https://dev.vaadin.com/query?status=closed&component=Core+Framework&resolution=fixed&milestone=!Vaadin {version}&col=id&col=summary&col=component&col=status&col=type&col=priority&col=milestone&order=priority\">Closed fixed tickets without milestone {version}</a>".format(version=args.version))
  137. # closed tickets with milestone
  138. content += createTableRow("", "<a href=\"https://dev.vaadin.com/query?status=closed&component=Core+Framework&resolution=fixed&milestone=Vaadin {version}&col=id&col=summary&col=component&col=milestone&col=status&col=type\">Closed tickets with milestone {version}</a>".format(version=args.version))
  139. # pending release tickets with milestone
  140. content += createTableRow("", "<a href=\"https://dev.vaadin.com/query?status=pending-release&component=Core+Framework&resolution=fixed&milestone=Vaadin {version}&col=id&col=summary&col=component&col=milestone&col=status&col=type\">Pending-release tickets with milestone {version}</a>".format(version=args.version))
  141. # pending release tickets without milestone
  142. content += createTableRow("", "<a href=\"https://dev.vaadin.com/query?status=pending-release&milestone=\">Pending-release tickets without milestone</a>")
  143. content += createTableRow("", "<h2>Preparations before publishing</h2>")
  144. # create milestone for next release
  145. content += createTableRow("", "<a href=\"https://dev.vaadin.com/milestone?action=new\">Create milestone for next release</a>")
  146. # close trac milestone
  147. content += createTableRow("", "<a href=\"https://dev.vaadin.com/milestone/Vaadin {version}\">Close Trac Milestone</a>".format(version=args.version))
  148. # verify pending release tickets still have milestone
  149. content += createTableRow("", "<a href=\"https://dev.vaadin.com/query?status=pending-release&component=Core+Framework&resolution=fixed&col=id&col=summary&col=component&col=milestone&col=status&col=type\">Verify pending release tickets still have milestone {version}</a>".format(version=args.version))
  150. # add version to trac
  151. content += createTableRow("", "<a href=\"https://dev.vaadin.com/admin/ticket/versions\">Add version {version} to Trac".format(version=args.version))
  152. content += "</table></body></html>"
  153. f = open("result/report.html", 'w')
  154. f.write(content)