2016-11-02 13:25:11 +01:00
from BuildDemos import demos
2016-11-03 15:56:54 +01:00
import argparse , requests , json , subprocess , re , pickle
2016-11-02 12:43:52 +01:00
2016-11-02 13:25:11 +01:00
parser = argparse . ArgumentParser ( )
parser . add_argument ( " version " , type = str , help = " Vaadin version that was just built " )
2016-11-02 12:43:52 +01:00
2016-11-02 13:25:11 +01:00
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 " )
2016-11-04 14:00:31 +01:00
parser . add_argument ( " buildTypeId " , type = str , help = " The ID of this build step " )
2016-11-02 13:25:11 +01:00
parser . add_argument ( " buildId " , type = str , help = " ID of the build to generate this report for " )
2017-03-14 09:26:10 +01:00
parser . add_argument ( " stagingRepoUrl " , type = str , help = " URL to the staging repository " )
2016-11-02 13:25:11 +01:00
args = parser . parse_args ( )
2016-11-04 14:00:31 +01:00
buildResultUrl = " http:// {} /viewLog.html?buildId= {} &tab=buildResultsDiv&buildTypeId= {} " . format ( args . teamcityUrl , args . buildId , args . buildTypeId )
2016-11-02 13:25:11 +01:00
def createTableRow ( * columns ) :
html = " <tr> "
for column in columns :
html + = " <td> " + column + " </td> "
return html + " </tr> "
2016-11-02 12:43:52 +01:00
2016-11-03 15:56:54 +01:00
def getHtmlList ( array ) :
html = " <ul> "
for item in array :
html + = " <li> " + item + " </li> "
return html + " </ul> "
2016-11-02 12:43:52 +01:00
def getBuildStatusHtml ( ) :
2016-11-02 13:25:11 +01:00
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 :
2016-11-04 14:00:31 +01:00
return createTableRow ( traffic_light . format ( color = " red " ) , " Build status: there are failing build steps, <a href= {} >check the build report</a> " . format ( buildResultUrl ) )
2016-11-02 12:43:52 +01:00
def getTestStatusHtml ( ) :
2016-11-02 13:25:11 +01:00
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 ( )
if test_failures_json [ " count " ] == 0 :
return createTableRow ( traffic_light . format ( color = " green " ) , " Test status: all tests passing " )
else :
2016-11-04 14:00:31 +01:00
return createTableRow ( traffic_light . format ( color = " red " ) , " Test status: there are " + str ( test_failures_json [ " count " ] ) + " failing tests, <a href= {} >check the build report</a> " . format ( buildResultUrl ) )
2016-11-02 13:25:11 +01:00
2016-11-03 08:26:11 +01:00
def getApiDiffHtml ( ) :
apidiff_html = " Check API diff "
modules = [
" client " , " client-compiler " ,
" compatibility-client " ,
" compatibility-server " ,
2017-03-28 20:25:21 +02:00
" compatibility-server-gae " ,
2016-11-03 08:26:11 +01:00
" compatibility-shared " ,
2017-03-24 12:45:21 +01:00
" liferay-integration " ,
2017-04-04 16:05:27 +02:00
" osgi-integration " ,
2016-11-03 08:26:11 +01:00
" server " , " shared "
]
2016-11-04 14:00:31 +01:00
link_list = list ( map ( lambda module : " <a href= ' http:// {} /repository/download/ {} / {} :id/apidiff/ {} /japicmp.html ' > {} </a> " . format ( args . teamcityUrl , args . buildTypeId , args . buildId , module , module ) , modules ) )
2016-11-03 15:56:54 +01:00
return apidiff_html + getHtmlList ( link_list )
2016-11-03 08:26:11 +01:00
2016-11-02 12:43:52 +01:00
def getDirs ( url ) :
page = requests . get ( url )
files = re . findall ( ' <a href=.*>(.*)</a> ' , 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 )
2017-03-14 09:26:10 +01:00
def getStagingContentsHtml ( repoUrl , allowedArtifacts ) :
2016-11-02 13:25:11 +01:00
if checkStagingContents ( repoUrl , allowedArtifacts ) :
2017-03-14 09:26:10 +01:00
return createTableRow ( traffic_light . format ( color = " green " ) , " Expected artifacts found in the staging repository. <a href= \" {} \" >Link to the repository.</a> " . format ( repoUrl ) )
2016-11-02 13:25:11 +01:00
else :
2017-03-14 09:26:10 +01:00
return createTableRow ( traffic_light . format ( color = " red " ) , " Extraneous or missing artifacts in the staging repository. <a href= \" {} \" >Link to the repository.</a> " . format ( repoUrl ) )
2016-11-02 12:43:52 +01:00
def completeArtifactName ( artifactId , version ) :
return ' com/vaadin/ ' + artifactId + ' / ' + version
def completeArtifactNames ( artifactIds , version ) :
return list ( map ( lambda x : completeArtifactName ( x , version ) , artifactIds ) )
2017-04-04 16:05:27 +02:00
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 )
2016-11-02 12:43:52 +01:00
content = " <html><head></head><body><table> "
traffic_light = " <svg width= \" 20px \" height= \" 20px \" style= \" padding-right:5px \" ><circle cx= \" 10 \" cy= \" 10 \" r= \" 10 \" fill= \" {color} \" /></svg> "
# Build step status
content + = getBuildStatusHtml ( )
# Test failures
content + = getTestStatusHtml ( )
# Missing @since tags
try :
2016-11-02 13:25:11 +01:00
p1 = subprocess . Popen ( [ ' find ' , ' . ' , ' -name ' , ' *.java ' ] , stdout = subprocess . PIPE )
p2 = subprocess . Popen ( [ ' xargs ' , ' egrep ' , ' -n ' , ' @since ?$ ' ] , stdin = p1 . stdout , stdout = subprocess . PIPE )
2016-11-03 08:26:11 +01:00
missing = subprocess . check_output ( [ ' egrep ' , ' -v ' , ' /(testbench|test|tests|target)/ ' ] , stdin = p2 . stdout )
2016-11-02 13:25:11 +01:00
content + = createTableRow ( traffic_light . format ( color = " red " ) , " Empty @since:<br><pre> %s </pre> " % ( missing ) )
2016-11-02 12:43:52 +01:00
except subprocess . CalledProcessError as e :
if e . returncode == 1 :
content + = createTableRow ( traffic_light . format ( color = " green " ) , " No empty @since " )
else :
raise e
2016-11-02 13:25:11 +01:00
# check staging repositories don't contain extra artifacts
2017-03-14 09:26:10 +01:00
content + = getStagingContentsHtml ( args . stagingRepoUrl , allowedArtifacts )
2016-11-02 12:43:52 +01:00
2016-11-02 13:25:11 +01:00
content + = createTableRow ( " " , " <h2>Manual checks before publishing</h2> " )
2017-09-07 10:01:37 +02:00
content + = createTableRow ( " " , " If changing between branches or phases (stable, maintenance, alpha, beta, rc), check the phase change checklist " )
2016-11-02 13:25:11 +01:00
# link to release notes
2016-11-04 14:00:31 +01:00
content + = createTableRow ( " " , " <a href= \" http:// {} /repository/download/ {} / {} :id/release-notes/release-notes.html \" >Check release notes</a> " . format ( args . teamcityUrl , args . buildTypeId , args . buildId ) )
2017-09-07 10:01:37 +02:00
2016-11-02 13:25:11 +01:00
# link to api diff
2016-11-03 08:26:11 +01:00
content + = createTableRow ( " " , getApiDiffHtml ( ) )
2016-11-02 12:43:52 +01:00
2016-12-20 09:40:31 +01:00
# check that GitHub issues are in the correct status
content + = createTableRow ( " " , " <a href= \" https://github.com/vaadin/framework/issues?q=is % 3Aclosed+sort % 3Aupdated-desc \" >Check that closed GitHub issues have correct milestone</a> " )
2016-11-02 12:43:52 +01:00
2017-09-07 10:01:37 +02:00
content + = createTableRow ( " " , " Check demos from docker image:<br><pre>zcat < demo-validation- {version} .tgz |docker load && docker run --rm -p 8080:8080 demo-validation: {version} || docker rmi demo-validation: {version} </pre> " . format ( version = args . version ) )
2016-11-02 12:43:52 +01:00
content + = createTableRow ( " " , " <h2>Preparations before publishing</h2> " )
2016-11-04 14:00:31 +01:00
# link to build dependencies tab to initiate publish step
content + = createTableRow ( " " , " <a href= \" http:// {} /viewLog.html?buildId= {} &buildTypeId= {} &tab=dependencies \" ><h2>Start Publish Release from dependencies tab</h2></a> " . format ( args . teamcityUrl , args . buildId , args . buildTypeId ) )
2016-11-02 12:43:52 +01:00
content + = " </table></body></html> "
2016-11-02 13:25:11 +01:00
f = open ( " result/report.html " , ' w ' )
2016-11-02 12:43:52 +01:00
f . write ( content )