af0d5a9b53
see https://review.gluster.org/#/c/19788/, https://review.gluster.org/#/c/19871/, https://review.gluster.org/#/c/19952/, https://review.gluster.org/#/c/20104/, https://review.gluster.org/#/c/20162/, https://review.gluster.org/#/c/20185/, https://review.gluster.org/#/c/20207/, https://review.gluster.org/#/c/20227/, https://review.gluster.org/#/c/20307/, https://review.gluster.org/#/c/20320/, https://review.gluster.org/#/c/20332/, https://review.gluster.org/#/c/20364/, https://review.gluster.org/#/c/20441/, and https://review.gluster.org/#/c/20484 shebangs changed from /usr/bin/python2 to /usr/bin/python3. (Reminder, various distribution packaging guidelines require use of explicit python version and don't allow '#!/usr/bin/env python', regardless of how handy that idiom may be.) glusterfs.spec(.in) package python{2,3}-gluster and python2 or python3 dependencies as appropriate. configure(.ac): + test for and use python2 or python3 as appropriate. If build machine has python2 and python3, use python3. Override by setting PYTHON=/usr/bin/python2 when running configure. + PYTHONDEV_CPPFLAGS from python[23]-config --includes is a better match to the original python sysconfig.get_python_inc(). All those other extraneous flags breaks the build. + Only change the shebangs once. Changing them over and over again, e.g., during a `make glusterrpms` in extras/LinuxRPM just sends make (is it really make that's looping?) into an infinite loop. If you figure out why, let me know. + Oldest python2 is python2.6 on CentOS 6 and Debian 8 (Jessie). Everything else has 2.7 or 3.x + logic from https://review.gluster.org/c/glusterfs/+/21050, which needs to be removed/merged after that patch is merged. Builds on CentOS 6, CentOS 7, Fedora 28, Fedora rawhide, and the mysterious RHEL > 7. Change-Id: Idae21d3b6f58b32372e1daa0d234e491e563198f updates: #411 Signed-off-by: Kaleb S. KEITHLEY <kkeithle@redhat.com>
181 lines
5.7 KiB
Python
Executable File
181 lines
5.7 KiB
Python
Executable File
#!/usr/bin/python3
|
|
|
|
from __future__ import print_function
|
|
import blessings
|
|
import requests
|
|
from requests.packages.urllib3.exceptions import InsecureRequestWarning
|
|
import re
|
|
import argparse
|
|
from collections import defaultdict
|
|
from datetime import timedelta, datetime
|
|
from pystache import render
|
|
|
|
# This tool goes though the Gluster regression links and checks for failures
|
|
|
|
BASE = 'https://build.gluster.org'
|
|
TERM = blessings.Terminal()
|
|
MAX_BUILDS = 1000
|
|
summary = defaultdict(list)
|
|
VERBOSE = None
|
|
|
|
|
|
def process_failure(url, node):
|
|
text = requests.get(url, verify=False).text
|
|
accum = []
|
|
for t in text.split('\n'):
|
|
if t.find("Result: FAIL") != -1:
|
|
for t2 in accum:
|
|
if VERBOSE:
|
|
print(t2.encode('utf-8'))
|
|
if t2.find("Wstat") != -1:
|
|
test_case = re.search('\./tests/.*\.t', t2)
|
|
if test_case:
|
|
summary[test_case.group()].append((url, node))
|
|
accum = []
|
|
elif t.find("cur_cores=/") != -1:
|
|
summary["core"].append([t.split("/")[1]])
|
|
summary["core"].append(url)
|
|
else:
|
|
accum.append(t)
|
|
|
|
|
|
def print_summary(failed_builds, total_builds, html=False):
|
|
# All the templates
|
|
count = [
|
|
'{{failed}} of {{total}} regressions failed',
|
|
'<p><b>{{failed}}</b> of <b>{{total}}</b> regressions failed</p>'
|
|
]
|
|
regression_link = [
|
|
'\tRegression Link: {{link}}\n'
|
|
'\tNode: {{node}}',
|
|
'<p> Regression Link: {{link}}</p>'
|
|
'<p> Node: {{node}}</p>'
|
|
]
|
|
component = [
|
|
'\tComponent: {{comp}}',
|
|
'<p> Component: {{comp}}</p>'
|
|
]
|
|
failure_count = [
|
|
''.join([
|
|
TERM.red,
|
|
'{{test}} ; Failed {{count}} times',
|
|
TERM.normal
|
|
]),
|
|
(
|
|
'<p><font color="red"><b>{{test}};</b> Failed <b>{{count}}'
|
|
'</b> times</font></p>'
|
|
)
|
|
]
|
|
|
|
template = 0
|
|
if html:
|
|
template = 1
|
|
print(render(
|
|
count[template],
|
|
{'failed': failed_builds, 'total': total_builds}
|
|
))
|
|
for k, v in summary.items():
|
|
if k == 'core':
|
|
print(''.join([TERM.red, "Found cores:", TERM.normal]))
|
|
for comp, link in zip(v[::2], v[1::2]):
|
|
print(render(component[template], {'comp': comp}))
|
|
print(render(
|
|
regression_link[template],
|
|
{'link': link[0], 'node': link[1]}
|
|
))
|
|
else:
|
|
print(render(failure_count[template], {'test': k, 'count': len(v)}))
|
|
for link in v:
|
|
print(render(
|
|
regression_link[template],
|
|
{'link': link[0], 'node': link[1]}
|
|
))
|
|
|
|
|
|
def get_summary(cut_off_date, reg_link):
|
|
'''
|
|
Get links to the failed jobs
|
|
'''
|
|
success_count = 0
|
|
failure_count = 0
|
|
for page in range(0, MAX_BUILDS, 100):
|
|
build_info = requests.get(''.join([
|
|
BASE,
|
|
reg_link,
|
|
'api/json?depth=1&tree=allBuilds'
|
|
'[url,result,timestamp,builtOn]',
|
|
'{{{0},{1}}}'.format(page, page+100)
|
|
]), verify=False).json()
|
|
for build in build_info.get('allBuilds'):
|
|
if datetime.fromtimestamp(build['timestamp']/1000) < cut_off_date:
|
|
# stop when timestamp older than cut off date
|
|
return failure_count, failure_count + success_count
|
|
if build['result'] in [None, 'SUCCESS']:
|
|
# pass when build is a success or ongoing
|
|
success_count += 1
|
|
continue
|
|
if VERBOSE:
|
|
print(''.join([
|
|
TERM.red,
|
|
'FAILURE on {0}'.format(build['url']),
|
|
TERM.normal
|
|
]))
|
|
url = ''.join([build['url'], 'consoleText'])
|
|
failure_count += 1
|
|
process_failure(url, build['builtOn'])
|
|
return failure_count, failure_count + success_count
|
|
|
|
|
|
def main(num_days, regression_link, html_report):
|
|
cut_off_date = datetime.today() - timedelta(days=num_days)
|
|
failure = 0
|
|
total = 0
|
|
for reg in regression_link:
|
|
if reg == 'centos':
|
|
reg_link = '/job/centos6-regression/'
|
|
elif reg == 'netbsd':
|
|
reg_link = '/job/netbsd7-regression/'
|
|
else:
|
|
reg_link = reg
|
|
counts = get_summary(cut_off_date, reg_link)
|
|
failure += counts[0]
|
|
total += counts[1]
|
|
print_summary(failure, total, html_report)
|
|
|
|
|
|
if __name__ == '__main__':
|
|
requests.packages.urllib3.disable_warnings(InsecureRequestWarning)
|
|
parser = argparse.ArgumentParser()
|
|
parser.add_argument("get-summary")
|
|
parser.add_argument(
|
|
"last_no_of_days",
|
|
default=1,
|
|
type=int,
|
|
help="Regression summary of last number of days"
|
|
)
|
|
parser.add_argument(
|
|
"regression_link",
|
|
default="centos",
|
|
nargs='+',
|
|
help="\"centos\" | \"netbsd\" | any other regression link"
|
|
)
|
|
parser.add_argument(
|
|
"--verbose",
|
|
default=False,
|
|
action="store_true",
|
|
help="Print a detailed report of each test case that is failed"
|
|
)
|
|
parser.add_argument(
|
|
"--html-report",
|
|
default=False,
|
|
action="store_true",
|
|
help="Print a brief report of failed regressions in html format"
|
|
)
|
|
args = parser.parse_args()
|
|
VERBOSE = args.verbose
|
|
main(
|
|
num_days=args.last_no_of_days,
|
|
regression_link=args.regression_link,
|
|
html_report=args.html_report
|
|
)
|