diff --git a/progit/hooks/files/progit_hook_tickets.py b/progit/hooks/files/progit_hook_tickets.py index 8697523..dda3b70 100644 --- a/progit/hooks/files/progit_hook_tickets.py +++ b/progit/hooks/files/progit_hook_tickets.py @@ -5,6 +5,7 @@ the information pushed in the tickets git repository. """ +import json import os import re import sys @@ -19,6 +20,7 @@ if 'PROGIT_CONFIG' not in os.environ \ sys.path.insert(0, os.path.expanduser('~/repos/gitrepo/progit')) +import progit.lib.git def read_git_output(args, input=None, keepends=False, **kw): """Read the output of a Git command.""" @@ -53,14 +55,16 @@ def read_output(cmd, input=None, keepends=False, **kw): def get_files_to_load(new_commits_list): - print 'Files changed by new commits:\n\n' + print 'Files changed by new commits:\n' file_list = [] - for line in read_git_lines( - ['show', '--pretty="format:"', '--name-only', '-r'] - + new_commits_list, - keepends=False,): - if line.strip(): - file_list.append(line.strip()) + new_commits_list.reverse() + for commit in new_commits_list: + filenames = read_git_lines( + ['diff-tree', '--no-commit-id', '--name-only', '-r', commit], + keepends=False) + for line in filenames: + if line.strip(): + file_list.append(line.strip()) return file_list @@ -70,7 +74,10 @@ def get_commits_id(fromrev, torev): of their identifier. ''' cmd = ['rev-list', '%s...%s' % (torev, fromrev)] - return read_git_lines(cmd) + if set(fromrev) == set('0'): + cmd = ['rev-list', '%s' % torev] + output = read_git_lines(cmd) + return output def get_repo_name(): @@ -80,6 +87,16 @@ def get_repo_name(): return repo +def get_username(): + ''' Return the username of the git repo based on its path. + ''' + username = None + repo = os.path.abspath(os.path.join(os.getcwd(), '..')) + if progit.APP.config['TICKETS_FOLDER'] in repo: + username = repo.split(progit.APP.config['TICKETS_FOLDER'])[1] + return username + + def run_as_post_receive_hook(): file_list = set() @@ -94,17 +111,29 @@ def run_as_post_receive_hook(): print ' -- Ref name' print refname - file_list.union( - set(get_files_to_load(get_commits_id(oldrev, newrev)))) + tmp = set(get_files_to_load(get_commits_id(oldrev, newrev))) + file_list = file_list.union(tmp) + + reponame = get_repo_name() + username = get_username() + print 'repo:', reponame, username for filename in file_list: print 'To load: %s' % filename - - print 'repo:', get_repo_name() + data = ''.join(read_git_lines(['show', 'HEAD:%s' % filename])) + if data: + data = json.loads(data) + if data: + progit.lib.git.update_ticket_from_git( + progit.SESSION, + reponame=reponame, + username=username, + issue_uid=filename, + json_data=data) def main(args): - run_as_post_receive_hook() + run_as_post_receive_hook() if __name__ == '__main__': diff --git a/progit/lib/git.py b/progit/lib/git.py index 7f7d17f..e608aa9 100644 --- a/progit/lib/git.py +++ b/progit/lib/git.py @@ -21,6 +21,7 @@ import uuid import pygit2 import progit.exceptions +import progit.lib import progit.lib.notify from progit.lib import model @@ -197,3 +198,102 @@ def update_git_ticket(issue, repo, ticketfolder): # Remove the clone shutil.rmtree(newpath) + + +def get_user_from_json(session, jsondata): + """ From the given json blob, retrieve the user info and search for it + in the db and create the user if it does not already exist. + """ + user = None + + username = jsondata.get('user', {}).get('name') + fullname = jsondata.get('user', {}).get('fullname') + useremails = jsondata.get('user', {}).get('emails') + user = progit.lib.search_user(session, username=username) + if not user: + for email in useremails: + user = progit.lib.search_user(session, email=email) + if user: + break + + if not user: + user = progit.lib.set_up_user( + session=session, + username=username, + fullname=fullname or username, + user_email=useremails[0], + ) + session.commit() + + return user + + + +def update_ticket_from_git( + session, reponame, username, issue_uid, json_data): + """ Update the specified issue (identified by its unique identifier) + with the data present in the json blob provided. + + :arg session: the session to connect to the database with. + :arg repo: the name of the project to update + :arg issue_uid: the unique identifier of the issue to update + :arg json_data: the json representation of the issue taken from the git + and used to update the data in the database. + + """ + print json.dumps(json_data, sort_keys=True, + indent=4, separators=(',', ': ')) + + repo = progit.lib.get_project(session, reponame, user=username) + if not repo: + raise progit.exceptions.ProgitException( + 'Unknown repo %s of username: %s' % (reponame, username)) + + user = get_user_from_json(session, json_data) + + issue = progit.lib.get_issue_by_uid(session, issue_uid=issue_uid) + if not issue: + # Create new issue + progit.lib.new_issue( + session, + repo=repo, + title=json_data.get('title'), + content=json_data.get('content'), + user=user.username, + ticketfolder=None, + issue_id=json_data.get('id'), + issue_uid=issue_uid, + private=json_data.get('private'), + status=json_data.get('status'), + notify=False, + ) + + else: + # Edit existing issue + progit.lib.edit_issue( + session, + issue=issue, + ticketfolder=None, + title=json_data.get('title'), + content=json_data.get('content'), + status=json_data.get('status'), + private=json_data.get('private'), + ) + session.commit() + + issue = progit.lib.get_issue_by_uid(session, issue_uid=issue_uid) + + for comment in json_data['comments']: + user = get_user_from_json(session, comment) + commentobj = progit.lib.get_issue_comment( + session, issue_uid, comment['id']) + if not commentobj: + progit.lib.add_issue_comment( + session, + issue=issue, + comment=comment['comment'], + user=user.username, + ticketfolder=None, + notify=False, + ) + session.commit()