from BuildDemos import demos import argparse, requests, json, subprocess, re, pickle parser = argparse.ArgumentParser() parser.add_argument("version", type=str, help="Vaadin version that was just built") parser.add_argument("teamcityUser", type=str, help="Teamcity username to use") parser.add_argument("teamcityPassword", type=str, help="Password for given teamcity username") parser.add_argument("teamcityUrl", type=str, help="Address to the teamcity server") parser.add_argument("buildTypeId", type=str, help="The ID of this build step") parser.add_argument("buildId", type=str, help="ID of the build to generate this report for") parser.add_argument("stagingRepoUrl", type=str, help="URL to the staging repository") args = parser.parse_args() buildResultUrl = "http://{}/viewLog.html?buildId={}&tab=buildResultsDiv&buildTypeId={}".format(args.teamcityUrl, args.buildId, args.buildTypeId) def createTableRow(*columns): html = "" for column in columns: html += "" + column + "" return html + "" def getHtmlList(array): html = "" def getBuildStatusHtml(): build_steps_request_string = "http://{}/app/rest/problemOccurrences?locator=build:{}".format(args.teamcityUrl, args.buildId) build_steps_request = requests.get(build_steps_request_string, auth=(args.teamcityUser, args.teamcityPassword), headers={'Accept':'application/json'}) if build_steps_request.status_code != 200: return createTableRow(traffic_light.format(color="black"), "Build status: unable to retrieve status of build") else: build_steps_json = build_steps_request.json() if build_steps_json["count"] == 0: return createTableRow(traffic_light.format(color="green"), "Build status: all build steps successful") else: return createTableRow(traffic_light.format(color="red"), "Build status: there are failing build steps, check the build report".format(buildResultUrl)) def getTestStatusHtml(): test_failures_request_string = "http://{}/app/rest/testOccurrences?locator=build:{},status:FAILURE".format(args.teamcityUrl, args.buildId) test_failures_request = requests.get(test_failures_request_string, auth=(args.teamcityUser, args.teamcityPassword), headers={'Accept':'application/json'}) if test_failures_request.status_code != 200: return createTableRow(traffic_light.format(color="black"), "Test status: unable to retrieve status of tests") else: test_failures_json = test_failures_request.json() # nowadays the responds doesn't contain count keyword when the build is successful # while count word can be found when build fails if "count" not in test_failures_json: return createTableRow(traffic_light.format(color="green"), "Test status: all tests passing") else: return createTableRow(traffic_light.format(color="red"), "Test status: there are " + str(test_failures_json["count"]) + " failing tests, check the build report".format(buildResultUrl)) def getApiDiffHtml(): apidiff_html = "Check API diff" modules = [ "client", "client-compiler", "compatibility-client", "compatibility-server", "compatibility-server-gae", "compatibility-shared", "liferay-integration", "osgi-integration", "server", "shared" ] link_list = list(map(lambda module: "{}".format(args.teamcityUrl, args.buildTypeId, args.buildId, module, module), modules)) return apidiff_html + getHtmlList(link_list) def getDirs(url): page = requests.get(url) files = re.findall('(.*)', page.text) dirs = filter(lambda x: x.endswith('/'), files) return list(map(lambda x: x.replace('/', ''), dirs)) def dirTree(url): dirs = getDirs(url) result = [] for d in dirs: result.append(d) subDirs = list(map(lambda x: d + '/' + x, dirTree(url + '/' + d))) result.extend(subDirs) return result def getAllowedArtifactPaths(allowedArtifacts): result = [] for artifact in allowedArtifacts: parts = artifact.split('/', 1) result.append(parts[0]) if len(parts) > 1: subart = getAllowedArtifactPaths([ parts[1] ]) subArtifacts = list(map(lambda x: parts[0] + '/' + x, subart)) result.extend(subArtifacts) return result def checkStagingContents(url, allowedArtifacts): dirs = dirTree(url) allowedDirs = getAllowedArtifactPaths(allowedArtifacts) return set(dirs) == set(allowedDirs) def getStagingContentsHtml(repoUrl, allowedArtifacts): if checkStagingContents(repoUrl, allowedArtifacts): return createTableRow(traffic_light.format(color="green"), "Expected artifacts found in the staging repository. Link to the repository.".format(repoUrl)) else: return createTableRow(traffic_light.format(color="red"), "Extraneous or missing artifacts in the staging repository. Link to the repository.".format(repoUrl)) def completeArtifactName(artifactId, version): return 'com/vaadin/' + artifactId + '/' + version def completeArtifactNames(artifactIds, version): return list(map(lambda x: completeArtifactName(x, version), artifactIds)) allowedArtifacts = completeArtifactNames([ 'vaadin-maven-plugin', 'vaadin-archetypes', 'vaadin-archetype-application', 'vaadin-archetype-application-multimodule', 'vaadin-archetype-application-example', 'vaadin-archetype-widget', 'vaadin-archetype-liferay-portlet', 'vaadin-root', 'vaadin-shared', 'vaadin-server', 'vaadin-client', 'vaadin-client-compiler', 'vaadin-client-compiled', 'vaadin-push', 'vaadin-themes', 'vaadin-compatibility-shared', 'vaadin-compatibility-server', "vaadin-compatibility-server-gae", 'vaadin-compatibility-client', 'vaadin-compatibility-client-compiled', 'vaadin-compatibility-themes', 'vaadin-liferay-integration', "vaadin-osgi-integration", 'vaadin-testbench-api', 'vaadin-bom' ], args.version) content = "" traffic_light = "" # Build step status content += getBuildStatusHtml() # Test failures content += getTestStatusHtml() # Missing @since tags try: p1 = subprocess.Popen(['find', '.', '-name', '*.java'], stdout=subprocess.PIPE) p2 = subprocess.Popen(['xargs', 'egrep', '-n', '@since ?$'], stdin=p1.stdout, stdout=subprocess.PIPE) missing = subprocess.check_output(['egrep', '-v', '/(testbench|test|tests|target)/'], stdin=p2.stdout) content += createTableRow(traffic_light.format(color="red"), "Empty @since:
%s
" % (missing)) except subprocess.CalledProcessError as e: if e.returncode == 1: content += createTableRow(traffic_light.format(color="green"), "No empty @since") else: raise e # check staging repositories don't contain extra artifacts content += getStagingContentsHtml(args.stagingRepoUrl, allowedArtifacts) content += createTableRow("", "

Manual checks before publishing

") content += createTableRow("", "If changing between branches or phases (stable, maintenance, alpha, beta, rc), check the phase change checklist") # link to release notes content += createTableRow("", "Check release notes".format(args.teamcityUrl, args.buildTypeId, args.buildId)) # link to api diff content += createTableRow("", getApiDiffHtml()) # check that GitHub issues are in the correct status content += createTableRow("", "Check that closed GitHub issues have correct milestone") content += createTableRow("", "Check demos from docker image:
zcat < demo-validation-{version}.tgz |docker load && docker run --rm -p 8080:8080 demo-validation:{version} || docker rmi demo-validation:{version}
".format(version=args.version)) content += createTableRow("", "

Preparations before publishing

") # link to build dependencies tab to initiate publish step content += createTableRow("", "

Start Publish Release from dependencies tab

".format(args.teamcityUrl, args.buildId, args.buildTypeId)) content += "
" f = open("result/report.html", 'w') f.write(content)