Merge "Improving Gerrit + commit-log automation."
This commit is contained in:
commit
22a260d7a0
@ -230,29 +230,76 @@ def is_direct_release(full_project_name):
|
|||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
def process_bugtask(launchpad, bugtask, git_log, args):
|
class Task:
|
||||||
"""Apply changes to bugtask, based on hook / branch..."""
|
def __init__(self, lp_task, prefix):
|
||||||
|
'''Prefixes associated with bug references will allow for certain
|
||||||
|
changes to be made to the bug's launchpad (lp) page. The following
|
||||||
|
tokens represent the automation currently taking place.
|
||||||
|
|
||||||
|
::
|
||||||
|
add_comment -> Adds a comment to the bug's lp page.
|
||||||
|
set_in_progress -> Sets the bug's lp status to 'In Progress'.
|
||||||
|
set_fix_released -> Sets the bug's lp status to 'Fix Released'.
|
||||||
|
set_fix_committed -> Sets the bug's lp status to 'Fix Committed'.
|
||||||
|
::
|
||||||
|
|
||||||
|
changes_needed, when populated, simply indicates the actions that are
|
||||||
|
available to be taken based on the value of 'prefix'.
|
||||||
|
'''
|
||||||
|
self.lp_task = lp_task
|
||||||
|
self.changes_needed = []
|
||||||
|
|
||||||
|
# If no prefix was matched, default to 'closes'.
|
||||||
|
prefix = prefix.split('-')[0].lower() if prefix else 'closes'
|
||||||
|
|
||||||
|
if prefix in ('closes', 'fixes', 'resolves'):
|
||||||
|
self.changes_needed.extend(('add_comment',
|
||||||
|
'set_in_progress',
|
||||||
|
'set_fix_committed',
|
||||||
|
'set_fix_released'))
|
||||||
|
elif prefix in ('partial',):
|
||||||
|
self.changes_needed.extend(('add_comment', 'set_in_progress'))
|
||||||
|
elif prefix in ('related', 'impacts', 'affects'):
|
||||||
|
self.changes_needed.extend(('add_comment',))
|
||||||
|
else:
|
||||||
|
# prefix is not recognized.
|
||||||
|
self.changes_needed.extend(('add_comment',))
|
||||||
|
|
||||||
|
def needs_change(self, change):
|
||||||
|
'''Return a boolean indicating if given 'change' needs to be made.'''
|
||||||
|
if change in self.changes_needed:
|
||||||
|
return True
|
||||||
|
else:
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
|
def process_bugtask(launchpad, task, git_log, args):
|
||||||
|
"""Apply changes to lp bug tasks, based on hook / branch."""
|
||||||
|
|
||||||
|
bugtask = task.lp_task
|
||||||
|
|
||||||
if args.hook == "change-merged":
|
if args.hook == "change-merged":
|
||||||
if args.branch == 'master':
|
if args.branch == 'master':
|
||||||
if is_direct_release(args.project):
|
if (is_direct_release(args.project) and
|
||||||
|
task.needs_change('set_fix_released')):
|
||||||
set_fix_released(bugtask)
|
set_fix_released(bugtask)
|
||||||
else:
|
else:
|
||||||
if bugtask.status != u'Fix Released':
|
if (bugtask.status != u'Fix Released' and
|
||||||
|
task.needs_change('set_fix_committed')):
|
||||||
set_fix_committed(bugtask)
|
set_fix_committed(bugtask)
|
||||||
elif args.branch == 'milestone-proposed':
|
elif args.branch == 'milestone-proposed':
|
||||||
release_fixcommitted(bugtask)
|
release_fixcommitted(bugtask)
|
||||||
elif args.branch.startswith('stable/'):
|
elif args.branch.startswith('stable/'):
|
||||||
series = args.branch[7:]
|
series = args.branch[7:]
|
||||||
# Look for a related task matching the series
|
# Look for a related task matching the series.
|
||||||
for reltask in bugtask.related_tasks:
|
for reltask in bugtask.related_tasks:
|
||||||
if (reltask.bug_target_name.endswith("/" + series) and
|
if (reltask.bug_target_name.endswith("/" + series) and
|
||||||
reltask.status != u'Fix Released'):
|
reltask.status != u'Fix Released' and
|
||||||
# Use fixcommitted if there is any
|
task.needs_change('set_fix_committed')):
|
||||||
set_fix_committed(reltask)
|
set_fix_committed(reltask)
|
||||||
break
|
break
|
||||||
else:
|
else:
|
||||||
# Use tagging if there isn't any
|
# Use tag_in_branchname if there isn't any.
|
||||||
tag_in_branchname(bugtask, args.branch)
|
tag_in_branchname(bugtask, args.branch)
|
||||||
|
|
||||||
add_change_merged_message(bugtask, args.change_url, args.project,
|
add_change_merged_message(bugtask, args.change_url, args.project,
|
||||||
@ -261,13 +308,15 @@ def process_bugtask(launchpad, bugtask, git_log, args):
|
|||||||
|
|
||||||
if args.hook == "patchset-created":
|
if args.hook == "patchset-created":
|
||||||
if args.branch == 'master':
|
if args.branch == 'master':
|
||||||
if bugtask.status not in [u'Fix Committed', u'Fix Released']:
|
if (bugtask.status not in [u'Fix Committed', u'Fix Released'] and
|
||||||
set_in_progress(bugtask, launchpad, args.uploader,
|
task.needs_change('set_in_progress')):
|
||||||
args.change_url)
|
set_in_progress(bugtask, launchpad,
|
||||||
|
args.uploader, args.change_url)
|
||||||
elif args.branch.startswith('stable/'):
|
elif args.branch.startswith('stable/'):
|
||||||
series = args.branch[7:]
|
series = args.branch[7:]
|
||||||
for reltask in bugtask.related_tasks:
|
for reltask in bugtask.related_tasks:
|
||||||
if (reltask.bug_target_name.endswith("/" + series) and
|
if (reltask.bug_target_name.endswith("/" + series) and
|
||||||
|
task.needs_change('set_in_progress') and
|
||||||
reltask.status not in [u'Fix Committed',
|
reltask.status not in [u'Fix Committed',
|
||||||
u'Fix Released']):
|
u'Fix Released']):
|
||||||
set_in_progress(reltask, launchpad,
|
set_in_progress(reltask, launchpad,
|
||||||
@ -280,23 +329,44 @@ def process_bugtask(launchpad, bugtask, git_log, args):
|
|||||||
|
|
||||||
|
|
||||||
def find_bugs(launchpad, git_log, args):
|
def find_bugs(launchpad, git_log, args):
|
||||||
"""Find bugs referenced in the git log and return related bugtasks."""
|
'''Find bugs referenced in the git log and return related tasks.
|
||||||
|
|
||||||
bug_regexp = r'([Bb]ug|[Ll][Pp])[\s#:]*(\d+)'
|
Our regular expression is composed of three major parts:
|
||||||
tokens = re.split(bug_regexp, git_log)
|
part1: Matches only at start-of-line (required). Optionally matches any
|
||||||
|
word or hyphen separated words.
|
||||||
|
part2: Matches the words 'bug' or 'lp' on a word boundry (required).
|
||||||
|
part3: Matches a whole number (required).
|
||||||
|
|
||||||
# Extract unique bug tasks
|
The following patterns will be matched properly:
|
||||||
|
bug # 555555
|
||||||
|
Closes-Bug: 555555
|
||||||
|
Fixes: bug # 555555
|
||||||
|
Resolves: bug 555555
|
||||||
|
Partial-Bug: lp bug # 555555
|
||||||
|
|
||||||
|
:returns: an iterable containing Task objects.
|
||||||
|
'''
|
||||||
|
|
||||||
|
part1 = r'^[\t ]*(?P<prefix>[-\w]+)?[\s:]*'
|
||||||
|
part2 = r'(?:\b(?:bug|lp)\b[\s#:]*)+'
|
||||||
|
part3 = r'(?P<bug_number>\d+)\s*?$'
|
||||||
|
regexp = part1 + part2 + part3
|
||||||
|
matches = re.finditer(regexp, git_log, flags=re.I | re.M)
|
||||||
|
|
||||||
|
# Extract unique bug tasks and associated prefixes.
|
||||||
bugtasks = {}
|
bugtasks = {}
|
||||||
for token in tokens:
|
for match in matches:
|
||||||
if re.match('^\d+$', token) and (token not in bugtasks):
|
prefix = match.group('prefix')
|
||||||
|
bug_num = match.group('bug_number')
|
||||||
|
if bug_num not in bugtasks:
|
||||||
try:
|
try:
|
||||||
lp_bug = launchpad.bugs[token]
|
lp_bug = launchpad.bugs[bug_num]
|
||||||
for lp_task in lp_bug.bug_tasks:
|
for lp_task in lp_bug.bug_tasks:
|
||||||
if lp_task.bug_target_name == git2lp(args.project):
|
if lp_task.bug_target_name == git2lp(args.project):
|
||||||
bugtasks[token] = lp_task
|
bugtasks[bug_num] = Task(lp_task, prefix)
|
||||||
break
|
break
|
||||||
except KeyError:
|
except KeyError:
|
||||||
# Unknown bug
|
# Unknown bug.
|
||||||
pass
|
pass
|
||||||
|
|
||||||
return bugtasks.values()
|
return bugtasks.values()
|
||||||
@ -313,31 +383,31 @@ def extract_git_log(args):
|
|||||||
def main():
|
def main():
|
||||||
parser = argparse.ArgumentParser()
|
parser = argparse.ArgumentParser()
|
||||||
parser.add_argument('hook')
|
parser.add_argument('hook')
|
||||||
#common
|
# common
|
||||||
parser.add_argument('--change', default=None)
|
parser.add_argument('--change', default=None)
|
||||||
parser.add_argument('--change-url', default=None)
|
parser.add_argument('--change-url', default=None)
|
||||||
parser.add_argument('--project', default=None)
|
parser.add_argument('--project', default=None)
|
||||||
parser.add_argument('--branch', default=None)
|
parser.add_argument('--branch', default=None)
|
||||||
parser.add_argument('--commit', default=None)
|
parser.add_argument('--commit', default=None)
|
||||||
#change-merged
|
# change-merged
|
||||||
parser.add_argument('--submitter', default=None)
|
parser.add_argument('--submitter', default=None)
|
||||||
#patchset-created
|
# patchset-created
|
||||||
parser.add_argument('--uploader', default=None)
|
parser.add_argument('--uploader', default=None)
|
||||||
parser.add_argument('--patchset', default=None)
|
parser.add_argument('--patchset', default=None)
|
||||||
|
|
||||||
args = parser.parse_args()
|
args = parser.parse_args()
|
||||||
|
|
||||||
# Connect to Launchpad
|
# Connect to Launchpad.
|
||||||
lpconn = launchpad.Launchpad.login_with(
|
lpconn = launchpad.Launchpad.login_with(
|
||||||
'Gerrit User Sync', uris.LPNET_SERVICE_ROOT, GERRIT_CACHE_DIR,
|
'Gerrit User Sync', uris.LPNET_SERVICE_ROOT, GERRIT_CACHE_DIR,
|
||||||
credentials_file=GERRIT_CREDENTIALS, version='devel')
|
credentials_file=GERRIT_CREDENTIALS, version='devel')
|
||||||
|
|
||||||
# Get git log
|
# Get git log.
|
||||||
git_log = extract_git_log(args)
|
git_log = extract_git_log(args)
|
||||||
|
|
||||||
# Process bugtasks found in git log
|
# Process tasks found in git log.
|
||||||
for bugtask in find_bugs(lpconn, git_log, args):
|
for task in find_bugs(lpconn, git_log, args):
|
||||||
process_bugtask(lpconn, bugtask, git_log, args)
|
process_bugtask(lpconn, task, git_log, args)
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
main()
|
main()
|
||||||
|
Loading…
x
Reference in New Issue
Block a user