|
Pierre-Yves Chibon |
3935a2 |
#! /usr/bin/env python2
|
|
Pierre-Yves Chibon |
3935a2 |
|
|
Pierre-Yves Chibon |
3935a2 |
|
|
Pierre-Yves Chibon |
3935a2 |
"""Progit specific hook to add comment on issues if the commits fixes or
|
|
Pierre-Yves Chibon |
3935a2 |
relates to an issue.
|
|
Pierre-Yves Chibon |
3935a2 |
"""
|
|
Pierre-Yves Chibon |
3935a2 |
|
|
Pierre-Yves Chibon |
b9137f |
import os
|
|
Pierre-Yves Chibon |
3935a2 |
import re
|
|
Pierre-Yves Chibon |
3935a2 |
import sys
|
|
Pierre-Yves Chibon |
3935a2 |
import subprocess
|
|
Pierre-Yves Chibon |
3935a2 |
|
|
Pierre-Yves Chibon |
3935a2 |
|
|
Pierre-Yves Chibon |
4cc3ef |
if 'PROGIT_CONFIG' not in os.environ \
|
|
Pierre-Yves Chibon |
4cc3ef |
and os.path.exists('/etc/progit/progit.cfg'):
|
|
Pierre-Yves Chibon |
4cc3ef |
print 'Using configuration file `/etc/progit/progit.cfg`'
|
|
Pierre-Yves Chibon |
4cc3ef |
os.environ['PROGIT_CONFIG'] = '/etc/progit/progit.cfg'
|
|
Pierre-Yves Chibon |
4cc3ef |
|
|
Pierre-Yves Chibon |
4cc3ef |
|
|
Pierre-Yves Chibon |
2d550c |
import progit
|
|
Pierre-Yves Chibon |
2d550c |
import progit.exceptions
|
|
Pierre-Yves Chibon |
2d550c |
|
|
Pierre-Yves Chibon |
2d550c |
|
|
Pierre-Yves Chibon |
3935a2 |
FIXES = [
|
|
Pierre-Yves Chibon |
9822e3 |
re.compile('fixe?[sd]?:?\s?#(\d+)', re.I),
|
|
Pierre-Yves Chibon |
9822e3 |
re.compile('.*\s+fixe?[sd]?:?\s?#(\d+)', re.I),
|
|
Pierre-Yves Chibon |
9822e3 |
re.compile('fixe?[sd]?:?\s?https?://.*/(\w+)/issue/(\d+)', re.I),
|
|
Pierre-Yves Chibon |
9822e3 |
re.compile('.*\s+fixe?[sd]?:?\s?https?://.*/(\w+)/issue/(\d+)', re.I),
|
|
Pierre-Yves Chibon |
3935a2 |
]
|
|
Pierre-Yves Chibon |
3935a2 |
|
|
Pierre-Yves Chibon |
3935a2 |
RELATES = [
|
|
Pierre-Yves Chibon |
2ac0f8 |
re.compile('relate[sd]?:?\s?(?:to)?\s?#(\d+)', re.I),
|
|
Pierre-Yves Chibon |
430b75 |
re.compile('.*\s+relate[sd]?:?\s?#(\d+)', re.I),
|
|
Pierre-Yves Chibon |
129a3d |
re.compile(
|
|
Pierre-Yves Chibon |
129a3d |
'relate[sd]?:?\s?(?:to)?\s?https?://.*/(\w+)/issue/(\d+)', re.I),
|
|
Pierre-Yves Chibon |
430b75 |
re.compile('.*\s+relate[sd]?:?\s?https?://.*/(\w+)/issue/(\d+)', re.I),
|
|
Pierre-Yves Chibon |
3935a2 |
]
|
|
Pierre-Yves Chibon |
3935a2 |
|
|
Pierre-Yves Chibon |
1ea98c |
|
|
Pierre-Yves Chibon |
3935a2 |
def read_git_output(args, input=None, keepends=False, **kw):
|
|
Pierre-Yves Chibon |
3935a2 |
"""Read the output of a Git command."""
|
|
Pierre-Yves Chibon |
3935a2 |
|
|
Pierre-Yves Chibon |
3935a2 |
return read_output(['git'] + args, input=input, keepends=keepends, **kw)
|
|
Pierre-Yves Chibon |
3935a2 |
|
|
Pierre-Yves Chibon |
3935a2 |
|
|
Pierre-Yves Chibon |
3935a2 |
def read_git_lines(args, keepends=False, **kw):
|
|
Pierre-Yves Chibon |
3935a2 |
"""Return the lines output by Git command.
|
|
Pierre-Yves Chibon |
3935a2 |
|
|
Pierre-Yves Chibon |
3935a2 |
Return as single lines, with newlines stripped off."""
|
|
Pierre-Yves Chibon |
3935a2 |
|
|
Pierre-Yves Chibon |
3935a2 |
return read_git_output(args, keepends=True, **kw).splitlines(keepends)
|
|
Pierre-Yves Chibon |
3935a2 |
|
|
Pierre-Yves Chibon |
3935a2 |
|
|
Pierre-Yves Chibon |
3935a2 |
def read_output(cmd, input=None, keepends=False, **kw):
|
|
Pierre-Yves Chibon |
3935a2 |
if input:
|
|
Pierre-Yves Chibon |
3935a2 |
stdin = subprocess.PIPE
|
|
Pierre-Yves Chibon |
3935a2 |
else:
|
|
Pierre-Yves Chibon |
3935a2 |
stdin = None
|
|
Pierre-Yves Chibon |
3935a2 |
p = subprocess.Popen(
|
|
Pierre-Yves Chibon |
3935a2 |
cmd, stdin=stdin, stdout=subprocess.PIPE, stderr=subprocess.PIPE, **kw
|
|
Pierre-Yves Chibon |
3935a2 |
)
|
|
Pierre-Yves Chibon |
3935a2 |
(out, err) = p.communicate(input)
|
|
Pierre-Yves Chibon |
3935a2 |
retcode = p.wait()
|
|
Pierre-Yves Chibon |
3935a2 |
if retcode:
|
|
Pierre-Yves Chibon |
3935a2 |
print 'ERROR: %s =-- %s' % (cmd, retcode)
|
|
Pierre-Yves Chibon |
3935a2 |
if not keepends:
|
|
Pierre-Yves Chibon |
3935a2 |
out = out.rstrip('\n\r')
|
|
Pierre-Yves Chibon |
3935a2 |
return out
|
|
Pierre-Yves Chibon |
3935a2 |
|
|
Pierre-Yves Chibon |
3935a2 |
|
|
Pierre-Yves Chibon |
3935a2 |
def generate_revision_change_log(new_commits_list):
|
|
Pierre-Yves Chibon |
3935a2 |
|
|
Pierre-Yves Chibon |
3935a2 |
print 'Detailed log of new commits:\n\n'
|
|
Pierre-Yves Chibon |
e103a7 |
commitid = None
|
|
Pierre-Yves Chibon |
3935a2 |
for line in read_git_lines(
|
|
Pierre-Yves Chibon |
3935a2 |
['log', '--no-walk']
|
|
Pierre-Yves Chibon |
3935a2 |
+ new_commits_list
|
|
Pierre-Yves Chibon |
3935a2 |
+ ['--'],
|
|
Pierre-Yves Chibon |
129a3d |
keepends=False,):
|
|
Pierre-Yves Chibon |
e103a7 |
if line.startswith('commit'):
|
|
Pierre-Yves Chibon |
e103a7 |
commitid = line.split('commit ')[-1]
|
|
Pierre-Yves Chibon |
e103a7 |
|
|
Pierre-Yves Chibon |
907577 |
line = line.strip()
|
|
Pierre-Yves Chibon |
907577 |
|
|
Pierre-Yves Chibon |
3935a2 |
print '*', line
|
|
Pierre-Yves Chibon |
3935a2 |
for motif in FIXES:
|
|
Pierre-Yves Chibon |
3935a2 |
if motif.match(line):
|
|
Pierre-Yves Chibon |
089151 |
print 'fixes', motif.match(line).groups()
|
|
Pierre-Yves Chibon |
b37a8e |
project = None
|
|
Pierre-Yves Chibon |
c79d5a |
if len(motif.match(line).groups()) >= 2:
|
|
Pierre-Yves Chibon |
151505 |
issueid = motif.match(line).group(2)
|
|
Pierre-Yves Chibon |
151505 |
project = motif.match(line).group(1)
|
|
Pierre-Yves Chibon |
151505 |
else:
|
|
Pierre-Yves Chibon |
151505 |
issueid = motif.match(line).group(1)
|
|
Pierre-Yves Chibon |
b37a8e |
fixes_commit(
|
|
Pierre-Yves Chibon |
151505 |
commitid, issueid, project
|
|
Pierre-Yves Chibon |
b37a8e |
)
|
|
Pierre-Yves Chibon |
3935a2 |
for motif in RELATES:
|
|
Pierre-Yves Chibon |
3935a2 |
if motif.match(line):
|
|
Pierre-Yves Chibon |
089151 |
print 'relates to', motif.match(line).groups()
|
|
Pierre-Yves Chibon |
bb1c6f |
project = None
|
|
Pierre-Yves Chibon |
c79d5a |
if len(motif.match(line).groups()) >= 2:
|
|
Pierre-Yves Chibon |
bb1c6f |
project = motif.match(line).group(2)
|
|
Pierre-Yves Chibon |
bb1c6f |
relates_commit(
|
|
Pierre-Yves Chibon |
bb1c6f |
commitid, motif.match(line).group(1), project
|
|
Pierre-Yves Chibon |
bb1c6f |
)
|
|
Pierre-Yves Chibon |
bb1c6f |
|
|
Pierre-Yves Chibon |
bb1c6f |
|
|
Pierre-Yves Chibon |
bb1c6f |
def relates_commit(commitid, issueid, project=None):
|
|
Pierre-Yves Chibon |
bb1c6f |
''' Add a comment to an issue that this commit relates to it. '''
|
|
Pierre-Yves Chibon |
36573f |
repo = project or get_repo_name()
|
|
Pierre-Yves Chibon |
0392d2 |
username = get_username()
|
|
Pierre-Yves Chibon |
bb1c6f |
|
|
Pierre-Yves Chibon |
ac5603 |
repo = progit.lib.get_project(progit.SESSION, repo, user=username)
|
|
Pierre-Yves Chibon |
c04b2e |
if not repo:
|
|
Pierre-Yves Chibon |
c04b2e |
repo = progit.lib.get_project(
|
|
Pierre-Yves Chibon |
c04b2e |
progit.SESSION, get_repo_name(), user=username)
|
|
Pierre-Yves Chibon |
3b7b2b |
issue = progit.lib.search_issues(
|
|
Pierre-Yves Chibon |
d054da |
progit.SESSION, repo, issueid=issueid)
|
|
Pierre-Yves Chibon |
42703d |
|
|
Pierre-Yves Chibon |
3b9fc1 |
if issue is None or issue.project != repo:
|
|
Pierre-Yves Chibon |
bb1c6f |
return
|
|
Pierre-Yves Chibon |
bb1c6f |
|
|
Pierre-Yves Chibon |
58544c |
comment = ''' Commit [%s](../%s) relates to this ticket''' % (
|
|
Pierre-Yves Chibon |
275f52 |
commitid[:8], commitid[:8])
|
|
Pierre-Yves Chibon |
36573f |
|
|
Pierre-Yves Chibon |
36573f |
try:
|
|
Pierre-Yves Chibon |
36573f |
message = progit.lib.add_issue_comment(
|
|
Pierre-Yves Chibon |
36573f |
progit.SESSION,
|
|
Pierre-Yves Chibon |
36573f |
issue=issue,
|
|
Pierre-Yves Chibon |
36573f |
comment=comment,
|
|
Pierre-Yves Chibon |
275f52 |
user=get_pusher(commitid),
|
|
Pierre-Yves Chibon |
0a3375 |
ticketfolder=progit.APP.config['TICKETS_FOLDER'],
|
|
Pierre-Yves Chibon |
36573f |
)
|
|
Pierre-Yves Chibon |
36573f |
progit.SESSION.commit()
|
|
Pierre-Yves Chibon |
36573f |
except progit.exceptions.ProgitException as err:
|
|
Pierre-Yves Chibon |
36573f |
print err
|
|
Pierre-Yves Chibon |
b1e3c1 |
except SQLAlchemyError, err: # pragma: no cover
|
|
Pierre-Yves Chibon |
b1e3c1 |
progit.SESSION.rollback()
|
|
Pierre-Yves Chibon |
b1e3c1 |
progit.APP.logger.exception(err)
|
|
Pierre-Yves Chibon |
3935a2 |
|
|
Pierre-Yves Chibon |
3935a2 |
|
|
Pierre-Yves Chibon |
b37a8e |
def fixes_commit(commitid, issueid, project=None):
|
|
Pierre-Yves Chibon |
b37a8e |
''' Add a comment to an issue that this commit fixes it and update
|
|
Pierre-Yves Chibon |
b37a8e |
the status if the commit is in the master branch. '''
|
|
Pierre-Yves Chibon |
b37a8e |
repo = project or get_repo_name()
|
|
Pierre-Yves Chibon |
1ab53d |
username = get_username()
|
|
Pierre-Yves Chibon |
1ab53d |
|
|
Pierre-Yves Chibon |
1ab53d |
repo = progit.lib.get_project(progit.SESSION, repo, user=username)
|
|
Pierre-Yves Chibon |
c04b2e |
if not repo:
|
|
Pierre-Yves Chibon |
c04b2e |
repo = progit.lib.get_project(
|
|
Pierre-Yves Chibon |
c04b2e |
progit.SESSION, get_repo_name(), user=username)
|
|
Pierre-Yves Chibon |
3b7b2b |
issue = progit.lib.search_issues(
|
|
Pierre-Yves Chibon |
d054da |
progit.SESSION, repo, issueid=issueid)
|
|
Pierre-Yves Chibon |
b37a8e |
|
|
Pierre-Yves Chibon |
3b9fc1 |
if issue is None or issue.project != repo:
|
|
Pierre-Yves Chibon |
b37a8e |
return
|
|
Pierre-Yves Chibon |
b37a8e |
|
|
Pierre-Yves Chibon |
58544c |
comment = ''' Commit [%s](../%s) fixes this ticket''' % (
|
|
Pierre-Yves Chibon |
b37a8e |
commitid[:8], commitid[:8])
|
|
Pierre-Yves Chibon |
b37a8e |
|
|
Pierre-Yves Chibon |
b37a8e |
try:
|
|
Pierre-Yves Chibon |
b37a8e |
message = progit.lib.add_issue_comment(
|
|
Pierre-Yves Chibon |
b37a8e |
progit.SESSION,
|
|
Pierre-Yves Chibon |
b37a8e |
issue=issue,
|
|
Pierre-Yves Chibon |
b37a8e |
comment=comment,
|
|
Pierre-Yves Chibon |
b37a8e |
user=get_pusher(commitid),
|
|
Pierre-Yves Chibon |
0a3375 |
ticketfolder=progit.APP.config['TICKETS_FOLDER'],
|
|
Pierre-Yves Chibon |
b37a8e |
)
|
|
Pierre-Yves Chibon |
b37a8e |
progit.SESSION.commit()
|
|
Pierre-Yves Chibon |
b37a8e |
except progit.exceptions.ProgitException as err:
|
|
Pierre-Yves Chibon |
b37a8e |
print err
|
|
Pierre-Yves Chibon |
b1e3c1 |
except SQLAlchemyError, err: # pragma: no cover
|
|
Pierre-Yves Chibon |
b1e3c1 |
progit.SESSION.rollback()
|
|
Pierre-Yves Chibon |
b1e3c1 |
progit.APP.logger.exception(err)
|
|
Pierre-Yves Chibon |
b37a8e |
|
|
Pierre-Yves Chibon |
e2db6b |
branches = [
|
|
Pierre-Yves Chibon |
e2db6b |
item.replace('* ', '') for item in read_git_lines(
|
|
Pierre-Yves Chibon |
e2db6b |
['branch', '--contains', commitid],
|
|
Pierre-Yves Chibon |
e2db6b |
keepends=False)
|
|
Pierre-Yves Chibon |
e2db6b |
]
|
|
Pierre-Yves Chibon |
b37a8e |
|
|
Pierre-Yves Chibon |
b37a8e |
if 'master' in branches:
|
|
Pierre-Yves Chibon |
b37a8e |
try:
|
|
Pierre-Yves Chibon |
885f0b |
progit.lib.edit_issue(
|
|
Pierre-Yves Chibon |
885f0b |
progit.SESSION,
|
|
Pierre-Yves Chibon |
885f0b |
issue,
|
|
Pierre-Yves Chibon |
885f0b |
ticketfolder=progit.APP.config['TICKETS_FOLDER'],
|
|
Pierre-Yves Chibon |
885f0b |
status='Fixed')
|
|
Pierre-Yves Chibon |
b37a8e |
progit.SESSION.commit()
|
|
Pierre-Yves Chibon |
b37a8e |
except progit.exceptions.ProgitException as err:
|
|
Pierre-Yves Chibon |
b37a8e |
print err
|
|
Pierre-Yves Chibon |
b1e3c1 |
except SQLAlchemyError, err: # pragma: no cover
|
|
Pierre-Yves Chibon |
b1e3c1 |
progit.SESSION.rollback()
|
|
Pierre-Yves Chibon |
b1e3c1 |
progit.APP.logger.exception(err)
|
|
Pierre-Yves Chibon |
b37a8e |
|
|
Pierre-Yves Chibon |
b37a8e |
|
|
Pierre-Yves Chibon |
3935a2 |
def get_commits_id(fromrev, torev):
|
|
Pierre-Yves Chibon |
3935a2 |
''' Retrieve the list commit between two revisions and return the list
|
|
Pierre-Yves Chibon |
3935a2 |
of their identifier.
|
|
Pierre-Yves Chibon |
3935a2 |
'''
|
|
Pierre-Yves Chibon |
129a3d |
cmd = ['rev-list', '%s...%s' % (torev, fromrev)]
|
|
Pierre-Yves Chibon |
3935a2 |
return read_git_lines(cmd)
|
|
Pierre-Yves Chibon |
3935a2 |
|
|
Pierre-Yves Chibon |
3935a2 |
|
|
Pierre-Yves Chibon |
b9137f |
def get_repo_name():
|
|
Pierre-Yves Chibon |
b9137f |
''' Return the name of the git repo based on its path.
|
|
Pierre-Yves Chibon |
b9137f |
'''
|
|
Pierre-Yves Chibon |
b9137f |
repo = os.path.basename(os.getcwd()).split('.git')[0]
|
|
Pierre-Yves Chibon |
b9137f |
return repo
|
|
Pierre-Yves Chibon |
b9137f |
|
|
Pierre-Yves Chibon |
b9137f |
|
|
Pierre-Yves Chibon |
0392d2 |
def get_username():
|
|
Pierre-Yves Chibon |
0392d2 |
''' Return the username of the git repo based on its path.
|
|
Pierre-Yves Chibon |
0392d2 |
'''
|
|
Pierre-Yves Chibon |
0392d2 |
username = None
|
|
Pierre-Yves Chibon |
0392d2 |
repo = os.path.abspath(os.path.join(os.getcwd(), '..'))
|
|
Pierre-Yves Chibon |
0392d2 |
if progit.APP.config['FORK_FOLDER'] in repo:
|
|
Pierre-Yves Chibon |
0392d2 |
username = repo.split(progit.APP.config['FORK_FOLDER'])[1]
|
|
Pierre-Yves Chibon |
0392d2 |
return username
|
|
Pierre-Yves Chibon |
0392d2 |
|
|
Pierre-Yves Chibon |
0392d2 |
|
|
Pierre-Yves Chibon |
8736e9 |
def get_pusher(commit):
|
|
Pierre-Yves Chibon |
5ff2ba |
''' Return the name of the person that pushed the commit. '''
|
|
Pierre-Yves Chibon |
8736e9 |
user = None
|
|
Pierre-Yves Chibon |
8736e9 |
output = read_git_lines(
|
|
Pierre-Yves Chibon |
8736e9 |
['show', '--pretty=format:"%ae"', commit], keepends=False)
|
|
Pierre-Yves Chibon |
8736e9 |
if output:
|
|
Pierre-Yves Chibon |
8736e9 |
user = output[0].replace('"', '')
|
|
Pierre-Yves Chibon |
8736e9 |
if not user:
|
|
Pierre-Yves Chibon |
8736e9 |
user = os.environ.get('GL_USER', os.environ.get('USER', None))
|
|
Pierre-Yves Chibon |
8736e9 |
return user
|
|
Pierre-Yves Chibon |
5ff2ba |
|
|
Pierre-Yves Chibon |
5ff2ba |
|
|
Pierre-Yves Chibon |
3935a2 |
def run_as_post_receive_hook():
|
|
Pierre-Yves Chibon |
5ff2ba |
|
|
Pierre-Yves Chibon |
3935a2 |
changes = []
|
|
Pierre-Yves Chibon |
3935a2 |
for line in sys.stdin:
|
|
Pierre-Yves Chibon |
3935a2 |
print line
|
|
Pierre-Yves Chibon |
3935a2 |
(oldrev, newrev, refname) = line.strip().split(' ', 2)
|
|
Pierre-Yves Chibon |
3935a2 |
|
|
Pierre-Yves Chibon |
3935a2 |
print ' -- Old rev'
|
|
Pierre-Yves Chibon |
3935a2 |
print oldrev
|
|
Pierre-Yves Chibon |
3935a2 |
print ' -- New rev'
|
|
Pierre-Yves Chibon |
3935a2 |
print newrev
|
|
Pierre-Yves Chibon |
3935a2 |
print ' -- Ref name'
|
|
Pierre-Yves Chibon |
3935a2 |
print refname
|
|
Pierre-Yves Chibon |
3935a2 |
|
|
Pierre-Yves Chibon |
3935a2 |
generate_revision_change_log(get_commits_id(oldrev, newrev))
|
|
Pierre-Yves Chibon |
3935a2 |
|
|
Pierre-Yves Chibon |
b9137f |
print 'repo:', get_repo_name()
|
|
Pierre-Yves Chibon |
b9137f |
|
|
Pierre-Yves Chibon |
3935a2 |
|
|
Pierre-Yves Chibon |
3935a2 |
def main(args):
|
|
Pierre-Yves Chibon |
3935a2 |
run_as_post_receive_hook()
|
|
Pierre-Yves Chibon |
3935a2 |
|
|
Pierre-Yves Chibon |
3935a2 |
|
|
Pierre-Yves Chibon |
3935a2 |
if __name__ == '__main__':
|
|
Pierre-Yves Chibon |
3935a2 |
main(sys.argv[1:])
|