diff --git a/.travis.yml b/.travis.yml
new file mode 100644
index 00000000..474e735a
--- /dev/null
+++ b/.travis.yml
@@ -0,0 +1,12 @@
+sudo: false
+language: python
+python:
+ - 3.3
+ - 3.4
+ - 3.5
+install:
+ - pip install flake8
+script:
+ - flake8 --ignore E501 homu
+notifications:
+ webhooks: http://build.servo.org:54856/travis
diff --git a/cfg.sample.toml b/cfg.sample.toml
index 43fc1cd6..47a6f15d 100644
--- a/cfg.sample.toml
+++ b/cfg.sample.toml
@@ -75,7 +75,7 @@ secret = ""
#token = ""
## Use the Status API
-#[repo.NAME.status]
+#[repo.NAME.status.LABEL]
#
## String label set by status updates
#context = ""
diff --git a/homu/git_helper.py b/homu/git_helper.py
index 4bc2f92c..2d44340c 100755
--- a/homu/git_helper.py
+++ b/homu/git_helper.py
@@ -1,11 +1,11 @@
#!/usr/bin/env python3
import sys
-import subprocess
import os
SSH_KEY_FILE = os.path.join(os.path.dirname(__file__), '../cache/key')
+
def main():
args = ['ssh', '-i', SSH_KEY_FILE, '-S', 'none'] + sys.argv[1:]
os.execvp('ssh', args)
diff --git a/homu/main.py b/homu/main.py
index a0f0f703..38d048d6 100644
--- a/homu/main.py
+++ b/homu/main.py
@@ -17,7 +17,6 @@
import subprocess
from .git_helper import SSH_KEY_FILE
import shlex
-import sys
STATUS_TO_PRIORITY = {
'success': 0,
@@ -30,9 +29,9 @@
INTERRUPTED_BY_HOMU_FMT = 'Interrupted by Homu ({})'
INTERRUPTED_BY_HOMU_RE = re.compile(r'Interrupted by Homu \((.+?)\)')
-
TEST_TIMEOUT = 3600 * 10
+
@contextmanager
def buildbot_sess(repo_cfg):
sess = requests.Session()
@@ -47,10 +46,13 @@ def buildbot_sess(repo_cfg):
sess.get(repo_cfg['buildbot']['url'] + '/logout', allow_redirects=False)
db_query_lock = Lock()
+
+
def db_query(db, *args):
with db_query_lock:
db.execute(*args)
+
class PullReqState:
num = 0
priority = 0
@@ -75,7 +77,7 @@ def __init__(self, num, head_sha, status, db, repo_label, mergeable_que, gh, own
self.owner = owner
self.name = name
self.repos = repos
- self.test_started = time.time() # FIXME: Save in the local database
+ self.test_started = time.time() # FIXME: Save in the local database
def head_advanced(self, head_sha, *, use_db=True):
self.head_sha = head_sha
@@ -239,17 +241,20 @@ def fail(err):
utils.retry_until(inner, fail, self)
+
def sha_cmp(short, full):
return len(short) >= 4 and short == full[:len(short)]
+
def sha_or_blank(sha):
return sha if re.match(r'^[0-9a-f]+$', sha) else ''
+
def parse_commands(body, username, repo_cfg, state, my_username, db, states, *, realtime=False, sha=''):
try_only = False
if username not in repo_cfg['reviewers'] and username != my_username:
if username.lower() == state.delegate.lower():
- pass # Allow users who have been delegated review powers
+ pass # Allow users who have been delegated review powers
elif username in repo_cfg.get('try_users', []):
try_only = True
else:
@@ -263,11 +268,12 @@ def parse_commands(body, username, repo_cfg, state, my_username, db, states, *,
if word == 'r+' or word.startswith('r='):
if try_only:
- if realtime: state.add_comment(':key: Insufficient privileges')
+ if realtime:
+ state.add_comment(':key: Insufficient privileges')
continue
- if not sha and i+1 < len(words):
- cur_sha = sha_or_blank(words[i+1])
+ if not sha and i + 1 < len(words):
+ cur_sha = sha_or_blank(words[i + 1])
else:
cur_sha = sha
@@ -282,7 +288,8 @@ def parse_commands(body, username, repo_cfg, state, my_username, db, states, *,
# condition. Last time, it happened when squashing commits in a PR. In this case, we
# just try to retrieve the head SHA manually.
if all(x == '0' for x in state.head_sha):
- if realtime: state.add_comment(':bangbang: Invalid head SHA found, retrying: `{}`'.format(state.head_sha))
+ if realtime:
+ state.add_comment(':bangbang: Invalid head SHA found, retrying: `{}`'.format(state.head_sha))
state.head_sha = state.get_repo().pull_request(state.num).head.sha
state.save()
@@ -307,7 +314,8 @@ def parse_commands(body, username, repo_cfg, state, my_username, db, states, *,
else:
lines.append('- There\'s another pull request that is currently being tested, blocking this pull request: #{}'.format(_state.num))
- if lines: lines.insert(0, '')
+ if lines:
+ lines.insert(0, '')
lines.insert(0, ':bulb: This pull request was already approved, no need to approve it again.')
state.add_comment('\n'.join(lines))
@@ -325,7 +333,8 @@ def parse_commands(body, username, repo_cfg, state, my_username, db, states, *,
elif word == 'r-':
if try_only:
- if realtime: state.add_comment(':key: Insufficient privileges')
+ if realtime:
+ state.add_comment(':key: Insufficient privileges')
continue
state.approved_by = ''
@@ -333,20 +342,24 @@ def parse_commands(body, username, repo_cfg, state, my_username, db, states, *,
state.save()
elif word.startswith('p='):
- try: state.priority = int(word[len('p='):])
- except ValueError: pass
+ try:
+ state.priority = int(word[len('p='):])
+ except ValueError:
+ pass
state.save()
elif word.startswith('delegate='):
if try_only:
- if realtime: state.add_comment(':key: Insufficient privileges')
+ if realtime:
+ state.add_comment(':key: Insufficient privileges')
continue
state.delegate = word[len('delegate='):]
state.save()
- if realtime: state.add_comment(':v: @{} can now approve this pull request'.format(state.delegate))
+ if realtime:
+ state.add_comment(':v: @{} can now approve this pull request'.format(state.delegate))
elif word == 'delegate-':
state.delegate = ''
@@ -354,13 +367,15 @@ def parse_commands(body, username, repo_cfg, state, my_username, db, states, *,
elif word == 'delegate+':
if try_only:
- if realtime: state.add_comment(':key: Insufficient privileges')
+ if realtime:
+ state.add_comment(':key: Insufficient privileges')
continue
state.delegate = state.get_repo().pull_request(state.num).user.login
state.save()
- if realtime: state.add_comment(':v: @{} can now approve this pull request'.format(state.delegate))
+ if realtime:
+ state.add_comment(':v: @{} can now approve this pull request'.format(state.delegate))
elif word == 'retry' and realtime:
state.set_status('')
@@ -391,7 +406,8 @@ def parse_commands(body, username, repo_cfg, state, my_username, db, states, *,
mat = re.search('(?s)
(.*?)
', res.text)
if mat:
err = mat.group(1).strip()
- if not err: err = 'Unknown error'
+ if not err:
+ err = 'Unknown error'
else:
err = ''
@@ -414,6 +430,7 @@ def parse_commands(body, username, repo_cfg, state, my_username, db, states, *,
return state_changed
+
def git_push(fpath, branch, state):
merge_sha = subprocess.check_output(['git', '-C', fpath, 'rev-parse', 'HEAD']).decode('ascii').strip()
@@ -433,6 +450,7 @@ def fail(err):
return merge_sha
+
def create_merge(state, repo_cfg, branch, git_cfg):
base_sha = state.get_repo().ref('heads/' + state.base_ref).object.sha
@@ -449,7 +467,7 @@ def create_merge(state, repo_cfg, branch, git_cfg):
desc = 'Merge conflict'
if git_cfg['local_git']:
- pull = state.get_repo().pull_request(state.num)
+ state.get_repo().pull_request(state.num)
fpath = 'cache/{}/{}'.format(repo_cfg['owner'], repo_cfg['name'])
url = 'git@github.com:{}/{}.git'.format(repo_cfg['owner'], repo_cfg['name'])
@@ -516,9 +534,11 @@ def create_merge(state, repo_cfg, branch, git_cfg):
force=True,
)
- try: merge_commit = state.get_repo().merge(branch, state.head_sha, merge_msg)
+ try:
+ merge_commit = state.get_repo().merge(branch, state.head_sha, merge_msg)
except github3.models.GitHubError as e:
- if e.code != 409: raise
+ if e.code != 409:
+ raise
else:
return merge_commit.sha if merge_commit else ''
@@ -529,6 +549,7 @@ def create_merge(state, repo_cfg, branch, git_cfg):
return ''
+
def start_build(state, repo_cfgs, buildbot_slots, logger, db, git_cfg):
if buildbot_slots[0]:
return True
@@ -537,20 +558,21 @@ def start_build(state, repo_cfgs, buildbot_slots, logger, db, git_cfg):
repo_cfg = repo_cfgs[state.repo_label]
+ builders = []
if 'buildbot' in repo_cfg:
branch = 'try' if state.try_ else 'auto'
branch = repo_cfg.get('branch', {}).get(branch, branch)
- builders = repo_cfg['buildbot']['try_builders' if state.try_ else 'builders']
- elif 'travis' in repo_cfg:
+ builders += repo_cfg['buildbot']['try_builders' if state.try_ else 'builders']
+ if 'travis' in repo_cfg:
branch = repo_cfg.get('branch', {}).get('auto', 'auto')
- builders = ['travis']
- elif 'status' in repo_cfg:
+ builders += ['travis']
+ if 'status' in repo_cfg:
branch = repo_cfg.get('branch', {}).get('auto', 'auto')
- builders = ['status']
- else:
+ builders += ['status-' + key for key, value in repo_cfg['status'].items() if 'context' in value]
+ if len(builders) is 0:
raise RuntimeError('Invalid configuration')
- if state.approved_by and builders == ['status'] and repo_cfg['status']['context'] == 'continuous-integration/travis-ci/push':
+ if state.approved_by and len(builders) == 1 and 'status' in repo_cfg and len(repo_cfg['status']) == 1 and 'context' in repo_cfg['status'][0] and repo_cfg['status'][0]['context'] == 'continuous-integration/travis-ci/push':
for info in utils.github_iter_statuses(state.get_repo(), state.head_sha):
if info.context == 'continuous-integration/travis-ci/pr':
if info.state == 'success':
@@ -563,7 +585,8 @@ def start_build(state, repo_cfgs, buildbot_slots, logger, db, git_cfg):
if travis_commit:
base_sha = state.get_repo().ref('heads/' + state.base_ref).object.sha
if [travis_commit.parents[0]['sha'], travis_commit.parents[1]['sha']] == [base_sha, state.head_sha]:
- try: merge_sha = create_merge(state, repo_cfg, state.base_ref, git_cfg)
+ try:
+ merge_sha = create_merge(state, repo_cfg, state.base_ref, git_cfg)
except subprocess.CalledProcessError:
print('* Unable to create a merge commit for the exempted PR: {}'.format(state))
traceback.print_exc()
@@ -608,6 +631,7 @@ def start_build(state, repo_cfgs, buildbot_slots, logger, db, git_cfg):
return True
+
def start_rebuild(state, repo_cfgs):
repo_cfg = repo_cfgs[state.repo_label]
@@ -673,12 +697,14 @@ def start_rebuild(state, repo_cfgs):
return True
+
def start_build_or_rebuild(state, repo_cfgs, *args):
if start_rebuild(state, repo_cfgs):
return True
return start_build(state, repo_cfgs, *args)
+
def process_queue(states, repos, repo_cfgs, logger, buildbot_slots, db, git_cfg):
for repo_label, repo in repos.items():
repo_states = sorted(states[repo_label].values())
@@ -707,6 +733,7 @@ def process_queue(states, repos, repo_cfgs, logger, buildbot_slots, db, git_cfg)
if start_build(state, repo_cfgs, buildbot_slots, logger, db, git_cfg):
return
+
def fetch_mergeability(mergeable_que):
re_pull_num = re.compile('(?i)merge (?:of|pull request) #([0-9]+)')
@@ -726,8 +753,10 @@ def fetch_mergeability(mergeable_que):
if cause:
mat = re_pull_num.search(cause['title'])
- if mat: issue_or_commit = '#' + mat.group(1)
- else: issue_or_commit = cause['sha'][:7]
+ if mat:
+ issue_or_commit = '#' + mat.group(1)
+ else:
+ issue_or_commit = cause['sha'][:7]
else:
issue_or_commit = ''
@@ -744,6 +773,7 @@ def fetch_mergeability(mergeable_que):
finally:
mergeable_que.task_done()
+
def check_timeout(states, queue_handler):
while True:
try:
@@ -769,6 +799,7 @@ def check_timeout(states, queue_handler):
finally:
time.sleep(3600)
+
def synchronize(repo_label, repo_cfg, logger, gh, states, repos, db, mergeable_que, my_username, repo_labels):
logger.info('Synchronizing {}...'.format(repo_label))
@@ -843,15 +874,17 @@ def synchronize(repo_label, repo_cfg, logger, gh, states, repos, db, mergeable_q
logger.info('Done synchronizing {}!'.format(repo_label))
+
def arguments():
- parser = argparse.ArgumentParser(description =
- 'A bot that integrates with GitHub and '
- 'your favorite continuous integration service')
+ parser = argparse.ArgumentParser(
+ description='A bot that integrates with GitHub and your favorite '
+ 'continuous integration service')
parser.add_argument('-v', '--verbose',
action='store_true', help='Enable more verbose logging')
return parser.parse_args()
+
def main():
args = arguments()
@@ -868,7 +901,8 @@ def main():
gh = github3.login(token=cfg['github']['access_token'])
user = gh.user()
- try: user_email = [x for x in gh.iter_emails() if x['primary']][0]['email']
+ try:
+ user_email = [x for x in gh.iter_emails() if x['primary']][0]['email']
except IndexError:
raise RuntimeError('Primary email not set, or "user" scope not granted')
@@ -946,15 +980,15 @@ def main():
state.try_ = bool(try_)
state.rollup = bool(rollup)
state.delegate = delegate
-
+ builders = []
if merge_sha:
if 'buildbot' in repo_cfg:
- builders = repo_cfg['buildbot']['builders']
- elif 'travis' in repo_cfg:
- builders = ['travis']
- elif 'status' in repo_cfg:
- builders = ['status']
- else:
+ builders += repo_cfg['buildbot']['builders']
+ if 'travis' in repo_cfg:
+ builders += ['travis']
+ if 'status' in repo_cfg:
+ builders += ['status-' + key for key, value in repo_cfg['status'].items() if 'context' in value]
+ if len(builders) is 0:
raise RuntimeError('Invalid configuration')
state.init_build_res(builders, use_db=False)
@@ -974,8 +1008,10 @@ def main():
for repo_label, num, builder, res, url, merge_sha in db.fetchall():
try:
state = states[repo_label][num]
- if builder not in state.build_res: raise KeyError
- if state.merge_sha != merge_sha: raise KeyError
+ if builder not in state.build_res:
+ raise KeyError
+ if state.merge_sha != merge_sha:
+ raise KeyError
except KeyError:
db_query(db, 'DELETE FROM build_res WHERE repo = ? AND num = ? AND builder = ?', [repo_label, num, builder])
continue
@@ -987,7 +1023,8 @@ def main():
db_query(db, 'SELECT repo, num, mergeable FROM mergeable')
for repo_label, num, mergeable in db.fetchall():
- try: state = states[repo_label][num]
+ try:
+ state = states[repo_label][num]
except KeyError:
db_query(db, 'DELETE FROM mergeable WHERE repo = ? AND num = ?', [repo_label, num])
continue
@@ -1000,6 +1037,7 @@ def main():
db_query(db, 'DELETE FROM pull WHERE repo = ?', [repo_label])
queue_handler_lock = Lock()
+
def queue_handler():
with queue_handler_lock:
return process_queue(states, repos, repo_cfgs, logger, buildbot_slots, db, git_cfg)
diff --git a/homu/server.py b/homu/server.py
index 25f06fa3..1cf5665d 100644
--- a/homu/server.py
+++ b/homu/server.py
@@ -11,16 +11,19 @@
from bottle import get, post, run, request, redirect, abort, response
import hashlib
from threading import Thread
-import time
import sys
import os
import traceback
-import bottle; bottle.BaseRequest.MEMFILE_MAX = 1024 * 1024 * 10
+import bottle
+bottle.BaseRequest.MEMFILE_MAX = 1024 * 1024 * 10
-class G: pass
+
+class G:
+ pass
g = G()
+
def find_state(sha):
for repo_label, repo_states in g.states.items():
for state in repo_states.values():
@@ -29,6 +32,7 @@ def find_state(sha):
raise ValueError('Invalid SHA')
+
def get_repo(repo_label, repo_cfg):
repo = g.repos[repo_label]
if not repo:
@@ -38,10 +42,12 @@ def get_repo(repo_label, repo_cfg):
assert repo.name == repo_cfg['name']
return repo
+
@get('/')
def index():
return g.tpls['index'].render(repos=sorted(g.repos))
+
@get('/queue/')
def queue(repo_label):
logger = g.logger.getChild('queue')
@@ -57,7 +63,8 @@ def queue(repo_label):
states = []
for label in labels:
- try: states += g.states[label].values()
+ try:
+ states += g.states[label].values()
except KeyError:
abort(404, 'No such repository: {}'.format(label))
@@ -81,16 +88,17 @@ def queue(repo_label):
})
return g.tpls['queue'].render(
- repo_label = repo_label,
- states = rows,
- oauth_client_id = g.cfg['github']['app_client_id'],
- total = len(pull_states),
- approved = len([x for x in pull_states if x.approved_by]),
- rolled_up = len([x for x in pull_states if x.rollup]),
- failed = len([x for x in pull_states if x.status == 'failure' or x.status == 'error']),
- multiple = multiple,
+ repo_label=repo_label,
+ states=rows,
+ oauth_client_id=g.cfg['github']['app_client_id'],
+ total=len(pull_states),
+ approved=len([x for x in pull_states if x.approved_by]),
+ rolled_up=len([x for x in pull_states if x.rollup]),
+ failed=len([x for x in pull_states if x.status == 'failure' or x.status == 'error']),
+ multiple=multiple,
)
+
@get('/callback')
def callback():
logger = g.logger.getChild('callback')
@@ -123,14 +131,17 @@ def callback():
else:
abort(400, 'Invalid command')
+
def rollup(user_gh, state, repo_label, repo_cfg, repo):
user_repo = user_gh.repository(user_gh.user().login, repo.name)
base_repo = user_gh.repository(repo.owner.login, repo.name)
nums = state.get('nums', [])
if nums:
- try: rollup_states = [g.states[repo_label][num] for num in nums]
- except KeyError as e: return 'Invalid PR number: {}'.format(e.args[0])
+ try:
+ rollup_states = [g.states[repo_label][num] for num in nums]
+ except KeyError as e:
+ return 'Invalid PR number: {}'.format(e.args[0])
else:
rollup_states = [x for x in g.states[repo_label].values() if x.rollup]
rollup_states = [x for x in rollup_states if x.approved_by]
@@ -165,9 +176,11 @@ def rollup(user_gh, state, repo_label, repo_cfg, repo):
state.body,
)
- try: user_repo.merge(repo_cfg.get('branch', {}).get('rollup', 'rollup'), state.head_sha, merge_msg)
+ try:
+ user_repo.merge(repo_cfg.get('branch', {}).get('rollup', 'rollup'), state.head_sha, merge_msg)
except github3.models.GitHubError as e:
- if e.code != 409: raise
+ if e.code != 409:
+ raise
failures.append(state.num)
else:
@@ -191,6 +204,7 @@ def rollup(user_gh, state, repo_label, repo_cfg, repo):
else:
redirect(pull.html_url)
+
@post('/github')
def github():
logger = g.logger.getChild('github')
@@ -371,14 +385,16 @@ def fail(err):
g.queue_handler()
elif event_type == 'status':
- try: state, repo_label = find_state(info['sha'])
+ try:
+ state, repo_label = find_state(info['sha'])
except ValueError:
return 'OK'
- if 'status' not in state.build_res:
- return 'OK'
-
- if info['context'] != repo_cfg['status']['context']:
+ status_name = ""
+ for name, value in repo_cfg['status'].items():
+ if 'context' in value and value['context'] == info['context']:
+ status_name = name
+ if status_name is "":
return 'OK'
if info['state'] == 'pending':
@@ -388,14 +404,15 @@ def fail(err):
if row['name'] == state.base_ref:
return 'OK'
- report_build_res(info['state'] == 'success', info['target_url'], 'status', state, logger, repo_cfg)
+ report_build_res(info['state'] == 'success', info['target_url'], 'status-' + status_name, state, logger, repo_cfg)
return 'OK'
+
def report_build_res(succ, url, builder, state, logger, repo_cfg):
lazy_debug(logger,
lambda: 'build result {}: builder = {}, succ = {}, current build_res = {}'
- .format(state, builder, succ, state.build_res_summary()))
+ .format(state, builder, succ, state.build_res_summary()))
state.set_build_res(builder, succ, url)
@@ -410,7 +427,8 @@ def report_build_res(succ, url, builder, state, logger, repo_cfg):
if state.approved_by and not state.try_:
try:
- try: utils.github_set_ref(state.get_repo(), 'heads/' + state.base_ref, state.merge_sha)
+ try:
+ utils.github_set_ref(state.get_repo(), 'heads/' + state.base_ref, state.merge_sha)
except github3.models.GitHubError:
utils.github_create_status(state.get_repo(), state.merge_sha, 'success', '', 'Branch protection bypassed', context='homu')
utils.github_set_ref(state.get_repo(), 'heads/' + state.base_ref, state.merge_sha)
@@ -434,6 +452,7 @@ def report_build_res(succ, url, builder, state, logger, repo_cfg):
g.queue_handler()
+
@post('/buildbot')
def buildbot():
logger = g.logger.getChild('buildbot')
@@ -446,11 +465,14 @@ def buildbot():
lazy_debug(logger, lambda: 'info: {}'.format(info))
props = dict(x[:2] for x in info['properties'])
- if 'retry' in info['text']: continue
+ if 'retry' in info['text']:
+ continue
- if not props['revision']: continue
+ if not props['revision']:
+ continue
- try: state, repo_label = find_state(props['revision'])
+ try:
+ state, repo_label = find_state(props['revision'])
except ValueError:
lazy_debug(logger,
lambda: 'Invalid commit ID from Buildbot: {}'.format(props['revision']))
@@ -518,10 +540,13 @@ def buildbot():
lazy_debug(logger, lambda: 'info: {}'.format(info))
props = dict(x[:2] for x in info['properties'])
- if not props['revision']: continue
+ if not props['revision']:
+ continue
- try: state, repo_label = find_state(props['revision'])
- except ValueError: pass
+ try:
+ state, repo_label = find_state(props['revision'])
+ except ValueError:
+ pass
else:
if info['builderName'] in state.build_res:
repo_cfg = g.repo_cfgs[repo_label]
@@ -544,6 +569,7 @@ def buildbot():
return 'OK'
+
@post('/travis')
def travis():
logger = g.logger.getChild('travis')
@@ -552,7 +578,8 @@ def travis():
lazy_debug(logger, lambda: 'info: {}'.format(utils.remove_url_keys_from_json(info)))
- try: state, repo_label = find_state(info['commit'])
+ try:
+ state, repo_label = find_state(info['commit'])
except ValueError:
lazy_debug(logger, lambda: 'Invalid commit ID from Travis: {}'.format(info['commit']))
return 'OK'
@@ -572,7 +599,7 @@ def travis():
# fabricating travis notifications to try to trick Homu, but,
# I imagine that this will most often occur because a repo is
# misconfigured.
- logger.warn('authorization failed for {}, maybe the repo has the wrong travis token? ' \
+ logger.warn('authorization failed for {}, maybe the repo has the wrong travis token? '
'header = {}, computed = {}'
.format(state, auth_header, code))
abort(400, 'Authorization failed')
@@ -583,6 +610,7 @@ def travis():
return 'OK'
+
def synch(user_gh, state, repo_label, repo_cfg, repo):
if not repo.is_collaborator(user_gh.user().login):
abort(400, 'You are not a collaborator')
@@ -591,6 +619,7 @@ def synch(user_gh, state, repo_label, repo_cfg, repo):
return 'Synchronizing {}...'.format(repo_label)
+
@post('/admin')
def admin():
if request.json['secret'] != g.cfg['web']['secret']:
@@ -638,7 +667,8 @@ def admin():
elif request.json['cmd'] == 'sync_all':
def inner():
for repo_label in g.repos:
- try: synchronize(repo_label, g.repo_cfgs[repo_label], g.logger, g.gh, g.states, g.repos, g.db, g.mergeable_que, g.my_username, g.repo_labels)
+ try:
+ synchronize(repo_label, g.repo_cfgs[repo_label], g.logger, g.gh, g.states, g.repos, g.db, g.mergeable_que, g.my_username, g.repo_labels)
except:
print('* Error while synchronizing {}'.format(repo_label))
traceback.print_exc()
@@ -651,10 +681,11 @@ def inner():
return 'Unrecognized command'
+
def start(cfg, states, queue_handler, repo_cfgs, repos, logger, buildbot_slots, my_username, db, repo_labels, mergeable_que, gh):
env = jinja2.Environment(
- loader = jinja2.FileSystemLoader(pkg_resources.resource_filename(__name__, 'html')),
- autoescape = True,
+ loader=jinja2.FileSystemLoader(pkg_resources.resource_filename(__name__, 'html')),
+ autoescape=True,
)
tpls = {}
tpls['index'] = env.get_template('index.html')
@@ -674,7 +705,8 @@ def start(cfg, states, queue_handler, repo_cfgs, repos, logger, buildbot_slots,
g.mergeable_que = mergeable_que
g.gh = gh
- try: run(host=cfg['web'].get('host', ''), port=cfg['web']['port'], server='waitress')
+ try:
+ run(host=cfg['web'].get('host', ''), port=cfg['web']['port'], server='waitress')
except OSError as e:
print(e, file=sys.stderr)
os._exit(1)
diff --git a/homu/utils.py b/homu/utils.py
index 4ce574b1..afa3fa1a 100644
--- a/homu/utils.py
+++ b/homu/utils.py
@@ -7,30 +7,37 @@
import requests
import time
+
def github_set_ref(repo, ref, sha, *, force=False, auto_create=True):
url = repo._build_url('git', 'refs', ref, base_url=repo._api)
data = {'sha': sha, 'force': force}
- try: js = repo._json(repo._patch(url, data=json.dumps(data)), 200)
+ try:
+ js = repo._json(repo._patch(url, data=json.dumps(data)), 200)
except github3.models.GitHubError as e:
if e.code == 422 and auto_create:
- try: return repo.create_ref('refs/' + ref, sha)
- except github3.models.GitHubError: raise e
+ try:
+ return repo.create_ref('refs/' + ref, sha)
+ except github3.models.GitHubError:
+ raise e
else:
raise
return github3.git.Reference(js, repo) if js else None
+
class Status(github3.repos.status.Status):
def __init__(self, info):
super(Status, self).__init__(info)
self.context = info.get('context')
+
def github_iter_statuses(repo, sha):
url = repo._build_url('statuses', sha, base_url=repo._api)
return repo._iter(-1, url, Status)
+
def github_create_status(repo, sha, state, target_url='', description='', *,
context=''):
data = {'state': state, 'target_url': target_url,
@@ -39,6 +46,7 @@ def github_create_status(repo, sha, state, target_url='', description='', *,
js = repo._json(repo._post(url, data=data), 201)
return Status(js) if js else None
+
def remove_url_keys_from_json(json):
if isinstance(json, dict):
return {key: remove_url_keys_from_json(value)
@@ -49,19 +57,24 @@ def remove_url_keys_from_json(json):
else:
return json
+
def lazy_debug(logger, f):
if logger.isEnabledFor(logging.DEBUG):
logger.debug(f())
+
def logged_call(args):
- try: subprocess.check_call(args, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
- except subprocess.CalledProcessError as e:
+ try:
+ subprocess.check_call(args, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
+ except subprocess.CalledProcessError:
print('* Failed to execute command: {}'.format(args))
raise
+
def silent_call(args):
return subprocess.call(args, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
+
def retry_until(inner, fail, state):
err = None
exc_info = None
@@ -75,7 +88,8 @@ def retry_until(inner, fail, state):
err = e
exc_info = sys.exc_info()
- if i != 1: time.sleep(1)
+ if i != 1:
+ time.sleep(1)
else:
err = None
break