Created
March 20, 2014 21:32
-
-
Save davehunt/9674346 to your computer and use it in GitHub Desktop.
b2gperf regression hunter
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import argparse | |
import logging | |
import re | |
import time | |
import sys | |
from BeautifulSoup import BeautifulSoup | |
import jenkins | |
import requests | |
# TODO Set low priority in Jenkins for regression hunting jobs | |
# TODO Support app names with spaces | |
def url_links(url, regex=None, auth=None): | |
r = requests.get(url, auth=auth) | |
r.raise_for_status() | |
soup = BeautifulSoup(r.text) | |
links = [link.get('href') for link in soup.findAll('a')] | |
if regex: | |
return [link for link in links if re.match(regex, link)] | |
else: | |
return links | |
def get_builds(branch, device, good_rev, bad_rev, eng=False, max_builds=20, | |
auth=None): | |
revisions = [] | |
path = '' if branch == 'mozilla-central' else 'integration/' | |
pushlog_url = 'https://hg.mozilla.org/%s%s/json-pushes?fromchange=%s' \ | |
'&tochange=%s' % (path, branch, good_rev, bad_rev) | |
print 'Getting revisions from: %s' % pushlog_url | |
r = requests.get(pushlog_url) | |
r.raise_for_status() | |
pushlog = r.json() | |
for push_id in sorted(pushlog.keys()): | |
push = pushlog[push_id] | |
revisions.append((push['changesets'][-1], push['date'])) | |
print '--------> %d revisions found' % len(revisions) | |
revisions.sort(key=lambda r: r[1]) # sort revisions by date | |
if not revisions: | |
return [] | |
start_time = revisions[0][1] | |
end_time = revisions[-1][1] | |
raw_revisions = map(lambda l: l[0], revisions) | |
base_url = 'https://pvtbuilds.mozilla.org/pvt/mozilla.org/b2gotoro/' \ | |
'tinderbox-builds/%s-%s%s/' % ( | |
branch, device, '-eng' if eng else '') | |
range = 60 * 60 * 4 # anything within four hours | |
format = '%Y%m%d%H%M%S' | |
print 'Getting builds from: %s' % base_url | |
ts = map(lambda l: int(time.mktime(time.strptime(l.strip('/'), format))), | |
url_links(base_url, '^\d{14}/$', auth)) | |
print '--------> %d builds found' % len(ts) | |
ts_in_range = filter(lambda t: t > (start_time - range) and | |
t < (end_time + range), ts) | |
print '--------> %d builds within range' % len(ts_in_range) | |
builds = [] | |
for t in [time.strftime(format, time.localtime(t)) for t in ts_in_range]: | |
for link in url_links('%s%s/' % (base_url, t), '^sources\.xml$', auth): | |
url = '%s%s/%s' % (base_url, t, link) | |
r = requests.get(url, auth=auth) | |
search = re.search('<project .* path="gecko" remote="hgmozillaorg"' | |
' revision="(\w{12})"/>', r.text) | |
if search: | |
for revision in raw_revisions: | |
if search.group(1) == revision[:12]: | |
builds.append((revision, '%s%s' % (base_url, t))) | |
print '--------> %d builds matching revisions' % len(builds) | |
if len(builds) > max_builds: | |
builds = builds[:max_builds] | |
print 'Build count exceeds maximum. Only the first %s builds will ' \ | |
'be selected.' % max_builds | |
raw_input('Press return to continue or ctrl-c to abort.') | |
print 'Selected range: %s:%s' % (builds[0][0][:12], builds[-1][0][:12]) | |
return builds | |
def cli(args=sys.argv[1:]): | |
parser = argparse.ArgumentParser( | |
description='Trigger Jenkins jobs for all tinderbox builds ' | |
'between revisions.') | |
parser.add_argument( | |
'-v', '--verbose', | |
action='store_true', | |
default=False, | |
help='verbose output') | |
parser.add_argument( | |
'--dry-run', | |
action='store_true', | |
default=False, | |
help='output the jobs to console without triggering them') | |
parser.add_argument( | |
'-m', | |
dest='max_builds', | |
type=int, | |
default=20, | |
help='maximum number of builds to trigger (default: %(default)s)') | |
parser.add_argument( | |
'-b', | |
dest='branch', | |
default='mozilla-central', | |
help='branch to use (default: %(default)s)') | |
parser.add_argument( | |
'--eng', | |
action='store_true', | |
default=False, | |
help='limit to engineering builds') | |
parser.add_argument( | |
'-a', | |
dest='apps', | |
metavar='APP', | |
nargs='*', | |
help='names of applications to test') | |
parser.add_argument( | |
'-u', | |
dest='username', | |
help='username for access to the builds') | |
parser.add_argument( | |
'-p', | |
dest='password', | |
help='password for access to the builds') | |
parser.add_argument( | |
'-j', | |
dest='jenkins_url', | |
default='http://localhost:8080', | |
help='url of jenkins instance (default: %(default)s)') | |
parser.add_argument( | |
'-e', | |
dest='email', | |
help='email address to send result notifications') | |
parser.add_argument( | |
'device_name', | |
help='name of device') | |
parser.add_argument( | |
'job_name', | |
help='name of the jenkins job to execute') | |
parser.add_argument( | |
'good_rev', | |
help='last known good revision') | |
parser.add_argument( | |
'bad_rev', | |
help='first known bad revision') | |
args = parser.parse_args() | |
log_level = logging.DEBUG if args.verbose else logging.WARN | |
logging.basicConfig(level=log_level) | |
auth = any([args.username, args.password]) and \ | |
(args.username, args.password) or None | |
builds = get_builds(args.branch, args.device_name, args.good_rev, | |
args.bad_rev, args.eng, args.max_builds, auth) | |
j = jenkins.Jenkins(args.jenkins_url) | |
if builds: | |
parameters = {'NOTIFICATION_ADDRESS': args.email} | |
if args.apps: | |
print 'Application%s under test: %s' % ( | |
's' if len(args.apps) > 1 else '', ', '.join(args.apps)) | |
parameters.update({'APP_NAMES': ' '.join(args.apps)}) | |
print 'Results will be sent to: %s' % args.email | |
for build in builds: | |
build_url = build[1] | |
parameters.update({'BUILD_URL': build_url}) | |
print 'Triggering %s for: %s' % (args.job_name, build_url) | |
if not args.dry_run: | |
j.build_job(args.job_name, parameters) | |
time.sleep(0.5) | |
else: | |
print 'No builds to trigger.' | |
if __name__ == '__main__': | |
cli() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment