Blame progit/lib/git.py

Pierre-Yves Chibon 33b534
# -*- coding: utf-8 -*-
Pierre-Yves Chibon a27356
Pierre-Yves Chibon a27356
"""
Pierre-Yves Chibon a27356
 (c) 2015 - Copyright Red Hat Inc
Pierre-Yves Chibon a27356
Pierre-Yves Chibon a27356
 Authors:
Pierre-Yves Chibon a27356
   Pierre-Yves Chibon <pingou@pingoured.fr></pingou@pingoured.fr>
Pierre-Yves Chibon a27356
Pierre-Yves Chibon a27356
"""
Pierre-Yves Chibon a27356
Pierre-Yves Chibon a27356
Pierre-Yves Chibon a27356
import datetime
Pierre-Yves Chibon 852918
import hashlib
Pierre-Yves Chibon a27356
import json
Pierre-Yves Chibon a27356
import os
Pierre-Yves Chibon a27356
import random
Pierre-Yves Chibon a27356
import shutil
Pierre-Yves Chibon a27356
import string
Pierre-Yves Chibon a27356
import tempfile
Pierre-Yves Chibon 852918
import time
Pierre-Yves Chibon a27356
import uuid
Pierre-Yves Chibon a27356
Pierre-Yves Chibon a27356
import pygit2
Pierre-Yves Chibon 2c34e0
import werkzeug
Pierre-Yves Chibon a27356
Pierre-Yves Chibon 852918
import progit
Pierre-Yves Chibon a27356
import progit.exceptions
Pierre-Yves Chibon c7f9fa
import progit.lib
Pierre-Yves Chibon f2c72b
import progit.lib.notify
Pierre-Yves Chibon a27356
from progit.lib import model
Pierre-Yves Chibon a27356
Pierre-Yves Chibon a27356
Pierre-Yves Chibon a27356
def commit_to_patch(repo_obj, commits):
Pierre-Yves Chibon a27356
    ''' For a given commit (PyGit2 commit object) of a specified git repo,
Pierre-Yves Chibon a27356
    returns a string representation of the changes the commit did in a
Pierre-Yves Chibon a27356
    format that allows it to be used as patch.
Pierre-Yves Chibon a27356
    '''
Pierre-Yves Chibon a27356
    if not isinstance(commits, list):
Pierre-Yves Chibon a27356
        commits = [commits]
Pierre-Yves Chibon a27356
Pierre-Yves Chibon a27356
    patch = ""
Pierre-Yves Chibon a27356
    for cnt, commit in enumerate(commits):
Pierre-Yves Chibon a27356
        if commit.parents:
Pierre-Yves Chibon a27356
            diff = commit.tree.diff_to_tree()
Pierre-Yves Chibon a27356
Pierre-Yves Chibon a27356
            parent = repo_obj.revparse_single('%s^' % commit.oid.hex)
Pierre-Yves Chibon a27356
            diff = repo_obj.diff(parent, commit)
Pierre-Yves Chibon a27356
        else:
Pierre-Yves Chibon a27356
            # First commit in the repo
Pierre-Yves Chibon a27356
            diff = commit.tree.diff_to_tree(swap=True)
Pierre-Yves Chibon a27356
Pierre-Yves Chibon a27356
        subject = message = ''
Pierre-Yves Chibon a27356
        if '\n' in commit.message:
Pierre-Yves Chibon a27356
            subject, message = commit.message.split('\n', 1)
Pierre-Yves Chibon a27356
        else:
Pierre-Yves Chibon a27356
            subject = commit.message
Pierre-Yves Chibon a27356
Pierre-Yves Chibon a27356
        if len(commits) > 1:
Pierre-Yves Chibon a27356
            subject = '[PATCH %s/%s] %s' % (cnt + 1, len(commits), subject)
Pierre-Yves Chibon a27356
Pierre-Yves Chibon a27356
        patch += """From %(commit)s Mon Sep 17 00:00:00 2001
Pierre-Yves Chibon a27356
From: %(author_name)s <%(author_email)s>
Pierre-Yves Chibon a27356
Date: %(date)s
Pierre-Yves Chibon a27356
Subject: %(subject)s
Pierre-Yves Chibon a27356
Pierre-Yves Chibon a27356
%(msg)s
Pierre-Yves Chibon a27356
---
Pierre-Yves Chibon a27356
Pierre-Yves Chibon a27356
%(patch)s
Pierre-Yves Chibon a27356
""" % (
Pierre-Yves Chibon a27356
            {
Pierre-Yves Chibon a27356
                'commit': commit.oid.hex,
Pierre-Yves Chibon a27356
                'author_name': commit.author.name,
Pierre-Yves Chibon a27356
                'author_email': commit.author.email,
Pierre-Yves Chibon a27356
                'date': datetime.datetime.utcfromtimestamp(
Pierre-Yves Chibon a27356
                    commit.commit_time).strftime('%b %d %Y %H:%M:%S +0000'),
Pierre-Yves Chibon a27356
                'subject': subject,
Pierre-Yves Chibon a27356
                'msg': message,
Pierre-Yves Chibon a27356
                'patch': diff.patch,
Pierre-Yves Chibon a27356
            }
Pierre-Yves Chibon a27356
        )
Pierre-Yves Chibon a27356
    return patch
Pierre-Yves Chibon 459834
Pierre-Yves Chibon 459834
Pierre-Yves Chibon 40699d
def write_gitolite_acls(session, configfile):
Pierre-Yves Chibon 459834
    ''' Generate the configuration file for gitolite for all projects
Pierre-Yves Chibon 459834
    on the forge.
Pierre-Yves Chibon 459834
    '''
Pierre-Yves Chibon 459834
    config = []
Pierre-Yves Chibon 459834
    for project in session.query(model.Project).all():
Pierre-Yves Chibon 459834
        if project.parent_id:
Pierre-Yves Chibon 459834
            config.append('repo forks/%s' % project.fullname)
Pierre-Yves Chibon 459834
        else:
Pierre-Yves Chibon 459834
            config.append('repo %s' % project.fullname)
Pierre-Yves Chibon 459834
        config.append('  R   = @all')
Pierre-Yves Chibon 459834
        config.append('  RW+ = %s' % project.user.user)
Pierre-Yves Chibon 459834
        for user in project.users:
Pierre-Yves Chibon 459834
            if user != project.user:
Pierre-Yves Chibon 2286f4
                config.append('  RW+ = %s' % user.user)
Pierre-Yves Chibon 459834
        config.append('')
Pierre-Yves Chibon 459834
Pierre-Yves Chibon 459834
        config.append('repo docs/%s' % project.fullname)
Pierre-Yves Chibon 459834
        config.append('  R   = @all')
Pierre-Yves Chibon 459834
        config.append('  RW+ = %s' % project.user.user)
Pierre-Yves Chibon 459834
        for user in project.users:
Pierre-Yves Chibon 459834
            if user != project.user:
Pierre-Yves Chibon 2286f4
                config.append('  RW+ = %s' % user.user)
Pierre-Yves Chibon 459834
        config.append('')
Pierre-Yves Chibon 459834
Pierre-Yves Chibon 459834
        config.append('repo tickets/%s' % project.fullname)
Pierre-Yves Chibon 459834
        config.append('  R   = @all')
Pierre-Yves Chibon 459834
        config.append('  RW+ = %s' % project.user.user)
Pierre-Yves Chibon 459834
        for user in project.users:
Pierre-Yves Chibon 459834
            if user != project.user:
Pierre-Yves Chibon 2286f4
                config.append('  RW+ = %s' % user.user)
Pierre-Yves Chibon 459834
        config.append('')
Pierre-Yves Chibon 459834
Pierre-Yves Chibon 459834
    with open(configfile, 'w') as stream:
Pierre-Yves Chibon 459834
        for row in config:
Pierre-Yves Chibon 459834
            stream.write(row + '\n')
Pierre-Yves Chibon c8b13b
Pierre-Yves Chibon c8b13b
Pierre-Yves Chibon 2b0341
def update_git(obj, repo, repofolder, objtype='ticket'):
Pierre-Yves Chibon c8b13b
    """ Update the given issue in its git.
Pierre-Yves Chibon c8b13b
Pierre-Yves Chibon c8b13b
    This method forks the provided repo, add/edit the issue whose file name
Pierre-Yves Chibon c8b13b
    is defined by the uid field of the issue and if there are additions/
Pierre-Yves Chibon c8b13b
    changes commit them and push them back to the original repo.
Pierre-Yves Chibon c8b13b
Pierre-Yves Chibon c8b13b
    """
Pierre-Yves Chibon c8b13b
Pierre-Yves Chibon 2b0341
    if not repofolder:
Pierre-Yves Chibon e3b595
        return
Pierre-Yves Chibon e3b595
Pierre-Yves Chibon c8b13b
    # Get the fork
Pierre-Yves Chibon 2b0341
    repopath = os.path.join(repofolder, repo.path)
Pierre-Yves Chibon c8b13b
    ticket_repo = pygit2.Repository(repopath)
Pierre-Yves Chibon c8b13b
Pierre-Yves Chibon c8b13b
    # Clone the repo into a temp folder
Pierre-Yves Chibon c8b13b
    newpath = tempfile.mkdtemp()
Pierre-Yves Chibon c8b13b
    new_repo = pygit2.clone_repository(repopath, newpath)
Pierre-Yves Chibon c8b13b
Pierre-Yves Chibon 2b0341
    file_path = os.path.join(newpath, obj.uid)
Pierre-Yves Chibon c8b13b
Pierre-Yves Chibon c8b13b
    # Get the current index
Pierre-Yves Chibon c8b13b
    index = new_repo.index
Pierre-Yves Chibon c8b13b
Pierre-Yves Chibon c8b13b
    # Are we adding files
Pierre-Yves Chibon c8b13b
    added = False
Pierre-Yves Chibon c8b13b
    if not os.path.exists(file_path):
Pierre-Yves Chibon c8b13b
        added = True
Pierre-Yves Chibon c8b13b
Pierre-Yves Chibon c8b13b
    # Write down what changed
Pierre-Yves Chibon c8b13b
    with open(file_path, 'w') as stream:
Pierre-Yves Chibon 2b0341
        stream.write(obj.to_json())
Pierre-Yves Chibon c8b13b
Pierre-Yves Chibon c8b13b
    # Retrieve the list of files that changed
Pierre-Yves Chibon c8b13b
    diff = new_repo.diff()
Pierre-Yves Chibon c8b13b
    files = [patch.new_file_path for patch in diff]
Pierre-Yves Chibon c8b13b
Pierre-Yves Chibon c8b13b
    # Add the changes to the index
Pierre-Yves Chibon c8b13b
    if added:
Pierre-Yves Chibon 2b0341
        index.add(obj.uid)
Pierre-Yves Chibon c8b13b
    for filename in files:
Pierre-Yves Chibon c8b13b
        index.add(filename)
Pierre-Yves Chibon c8b13b
Pierre-Yves Chibon c8b13b
    # If not change, return
Pierre-Yves Chibon c8b13b
    if not files and not added:
Pierre-Yves Chibon c8b13b
        shutil.rmtree(newpath)
Pierre-Yves Chibon c8b13b
        return
Pierre-Yves Chibon c8b13b
Pierre-Yves Chibon c8b13b
    # See if there is a parent to this commit
Pierre-Yves Chibon c8b13b
    parent = None
Pierre-Yves Chibon c8b13b
    try:
Pierre-Yves Chibon c8b13b
        parent = new_repo.head.get_object().oid
Pierre-Yves Chibon c8b13b
    except pygit2.GitError:
Pierre-Yves Chibon c8b13b
        pass
Pierre-Yves Chibon c8b13b
Pierre-Yves Chibon c8b13b
    parents = []
Pierre-Yves Chibon c8b13b
    if parent:
Pierre-Yves Chibon c8b13b
        parents.append(parent)
Pierre-Yves Chibon c8b13b
Pierre-Yves Chibon c8b13b
    # Author/commiter will always be this one
Pierre-Yves Chibon c8b13b
    author = pygit2.Signature(name='progit', email='progit')
Pierre-Yves Chibon c8b13b
Pierre-Yves Chibon c8b13b
    # Actually commit
Pierre-Yves Chibon c8b13b
    sha = new_repo.create_commit(
Pierre-Yves Chibon c8b13b
        'refs/heads/master',
Pierre-Yves Chibon c8b13b
        author,
Pierre-Yves Chibon c8b13b
        author,
Pierre-Yves Chibon 2b0341
        'Updated %s %s: %s' % (objtype, obj.uid, obj.title),
Pierre-Yves Chibon c8b13b
        new_repo.index.write_tree(),
Pierre-Yves Chibon c8b13b
        parents)
Pierre-Yves Chibon c8b13b
    index.write()
Pierre-Yves Chibon c8b13b
Pierre-Yves Chibon c8b13b
    # Push to origin
Pierre-Yves Chibon c8b13b
    ori_remote = new_repo.remotes[0]
Pierre-Yves Chibon c8b13b
    master_ref = new_repo.lookup_reference('HEAD').resolve()
Pierre-Yves Chibon c8b13b
    refname = '%s:%s' % (master_ref.name, master_ref.name)
Pierre-Yves Chibon c8b13b
Pierre-Yves Chibon c8b13b
    ori_remote.push(refname)
Pierre-Yves Chibon c8b13b
Pierre-Yves Chibon c8b13b
    # Remove the clone
Pierre-Yves Chibon c8b13b
    shutil.rmtree(newpath)
Pierre-Yves Chibon c7f9fa
Pierre-Yves Chibon c7f9fa
Pierre-Yves Chibon c7f9fa
def get_user_from_json(session, jsondata):
Pierre-Yves Chibon c7f9fa
    """ From the given json blob, retrieve the user info and search for it
Pierre-Yves Chibon c7f9fa
    in the db and create the user if it does not already exist.
Pierre-Yves Chibon c7f9fa
    """
Pierre-Yves Chibon c7f9fa
    user = None
Pierre-Yves Chibon c7f9fa
Pierre-Yves Chibon c7f9fa
    username = jsondata.get('user', {}).get('name')
Pierre-Yves Chibon c7f9fa
    fullname = jsondata.get('user', {}).get('fullname')
Pierre-Yves Chibon c7f9fa
    useremails = jsondata.get('user', {}).get('emails')
Pierre-Yves Chibon c7f9fa
    user = progit.lib.search_user(session, username=username)
Pierre-Yves Chibon c7f9fa
    if not user:
Pierre-Yves Chibon c7f9fa
        for email in useremails:
Pierre-Yves Chibon c7f9fa
            user = progit.lib.search_user(session, email=email)
Pierre-Yves Chibon c7f9fa
            if user:
Pierre-Yves Chibon c7f9fa
                break
Pierre-Yves Chibon c7f9fa
Pierre-Yves Chibon c7f9fa
    if not user:
Pierre-Yves Chibon c7f9fa
        user = progit.lib.set_up_user(
Pierre-Yves Chibon c7f9fa
            session=session,
Pierre-Yves Chibon c7f9fa
            username=username,
Pierre-Yves Chibon c7f9fa
            fullname=fullname or username,
Pierre-Yves Chibon c7f9fa
            user_email=useremails[0],
Pierre-Yves Chibon c7f9fa
        )
Pierre-Yves Chibon c7f9fa
        session.commit()
Pierre-Yves Chibon c7f9fa
Pierre-Yves Chibon c7f9fa
    return user
Pierre-Yves Chibon c7f9fa
Pierre-Yves Chibon c7f9fa
Pierre-Yves Chibon a6c9f2
def get_project_from_json(
Pierre-Yves Chibon a6c9f2
        session, jsondata, gitfolder, docfolder, ticketfolder, requestfolder):
Pierre-Yves Chibon a6c9f2
    """ From the given json blob, retrieve the project info and search for
Pierre-Yves Chibon a6c9f2
    it in the db and create the projec if it does not already exist.
Pierre-Yves Chibon a6c9f2
    """
Pierre-Yves Chibon a6c9f2
    project = None
Pierre-Yves Chibon a6c9f2
Pierre-Yves Chibon a6c9f2
Pierre-Yves Chibon a6c9f2
    user = get_user_from_json(session, jsondata)
Pierre-Yves Chibon a6c9f2
    name = jsondata.get('name')
Pierre-Yves Chibon a6c9f2
    project_user = None
Pierre-Yves Chibon a6c9f2
    if jsondata.get('parent'):
Pierre-Yves Chibon a6c9f2
        project_user = user.username
Pierre-Yves Chibon a6c9f2
    project = progit.lib.get_project(session, name, user=project_user)
Pierre-Yves Chibon a6c9f2
Pierre-Yves Chibon a6c9f2
Pierre-Yves Chibon a6c9f2
    if not project:
Pierre-Yves Chibon a6c9f2
        parent = None
Pierre-Yves Chibon a6c9f2
        if jsondata.get('parent'):
Pierre-Yves Chibon a6c9f2
            parent = get_project_from_json(
Pierre-Yves Chibon a6c9f2
                session, jsondata.get('parent'),
Pierre-Yves Chibon a6c9f2
                gitfolder, docfolder, ticketfolder, requestfolder)
Pierre-Yves Chibon a6c9f2
Pierre-Yves Chibon a6c9f2
        progit.lib.new_project(
Pierre-Yves Chibon a6c9f2
            session,
Pierre-Yves Chibon a6c9f2
            user=user.username,
Pierre-Yves Chibon a6c9f2
            name=name,
Pierre-Yves Chibon a6c9f2
            description=jsondata.get('description'),
Pierre-Yves Chibon a6c9f2
            parent_id=parent.id if parent else None,
Pierre-Yves Chibon a6c9f2
            gitfolder=gitfolder,
Pierre-Yves Chibon a6c9f2
            docfolder=docfolder,
Pierre-Yves Chibon a6c9f2
            ticketfolder=ticketfolder,
Pierre-Yves Chibon a6c9f2
            requestfolder=requestfolder,
Pierre-Yves Chibon a6c9f2
        )
Pierre-Yves Chibon a6c9f2
Pierre-Yves Chibon a6c9f2
        session.commit()
Pierre-Yves Chibon a6c9f2
        project = progit.lib.get_project(session, name, user=user.username)
Pierre-Yves Chibon a6c9f2
Pierre-Yves Chibon a6c9f2
    return project
Pierre-Yves Chibon a6c9f2
Pierre-Yves Chibon a6c9f2
Pierre-Yves Chibon c7f9fa
def update_ticket_from_git(
Pierre-Yves Chibon c7f9fa
        session, reponame, username, issue_uid, json_data):
Pierre-Yves Chibon c7f9fa
    """ Update the specified issue (identified by its unique identifier)
Pierre-Yves Chibon c7f9fa
    with the data present in the json blob provided.
Pierre-Yves Chibon c7f9fa
Pierre-Yves Chibon c7f9fa
    :arg session: the session to connect to the database with.
Pierre-Yves Chibon c7f9fa
    :arg repo: the name of the project to update
Pierre-Yves Chibon c7f9fa
    :arg issue_uid: the unique identifier of the issue to update
Pierre-Yves Chibon c7f9fa
    :arg json_data: the json representation of the issue taken from the git
Pierre-Yves Chibon c7f9fa
        and used to update the data in the database.
Pierre-Yves Chibon c7f9fa
Pierre-Yves Chibon c7f9fa
    """
Pierre-Yves Chibon c7f9fa
    print json.dumps(json_data, sort_keys=True,
Pierre-Yves Chibon c7f9fa
                     indent=4, separators=(',', ': '))
Pierre-Yves Chibon c7f9fa
Pierre-Yves Chibon c7f9fa
    repo = progit.lib.get_project(session, reponame, user=username)
Pierre-Yves Chibon c7f9fa
    if not repo:
Pierre-Yves Chibon c7f9fa
        raise progit.exceptions.ProgitException(
Pierre-Yves Chibon c7f9fa
            'Unknown repo %s of username: %s' % (reponame, username))
Pierre-Yves Chibon c7f9fa
Pierre-Yves Chibon c7f9fa
    user = get_user_from_json(session, json_data)
Pierre-Yves Chibon c7f9fa
Pierre-Yves Chibon c7f9fa
    issue = progit.lib.get_issue_by_uid(session, issue_uid=issue_uid)
Pierre-Yves Chibon c7f9fa
    if not issue:
Pierre-Yves Chibon c7f9fa
        # Create new issue
Pierre-Yves Chibon c7f9fa
        progit.lib.new_issue(
Pierre-Yves Chibon c7f9fa
            session,
Pierre-Yves Chibon c7f9fa
            repo=repo,
Pierre-Yves Chibon c7f9fa
            title=json_data.get('title'),
Pierre-Yves Chibon c7f9fa
            content=json_data.get('content'),
Pierre-Yves Chibon c7f9fa
            user=user.username,
Pierre-Yves Chibon c7f9fa
            ticketfolder=None,
Pierre-Yves Chibon c7f9fa
            issue_id=json_data.get('id'),
Pierre-Yves Chibon c7f9fa
            issue_uid=issue_uid,
Pierre-Yves Chibon c7f9fa
            private=json_data.get('private'),
Pierre-Yves Chibon c7f9fa
            status=json_data.get('status'),
Pierre-Yves Chibon c7f9fa
            notify=False,
Pierre-Yves Chibon c7f9fa
        )
Pierre-Yves Chibon c7f9fa
Pierre-Yves Chibon c7f9fa
    else:
Pierre-Yves Chibon c7f9fa
        # Edit existing issue
Pierre-Yves Chibon c7f9fa
        progit.lib.edit_issue(
Pierre-Yves Chibon c7f9fa
            session,
Pierre-Yves Chibon c7f9fa
            issue=issue,
Pierre-Yves Chibon c7f9fa
            ticketfolder=None,
Pierre-Yves Chibon c7f9fa
            title=json_data.get('title'),
Pierre-Yves Chibon c7f9fa
            content=json_data.get('content'),
Pierre-Yves Chibon c7f9fa
            status=json_data.get('status'),
Pierre-Yves Chibon c7f9fa
            private=json_data.get('private'),
Pierre-Yves Chibon c7f9fa
        )
Pierre-Yves Chibon c7f9fa
    session.commit()
Pierre-Yves Chibon c7f9fa
Pierre-Yves Chibon c7f9fa
    issue = progit.lib.get_issue_by_uid(session, issue_uid=issue_uid)
Pierre-Yves Chibon c7f9fa
Pierre-Yves Chibon afa3e7
    # Update tags
Pierre-Yves Chibon afa3e7
    tags = json_data.get('tags', [])
Pierre-Yves Chibon afa3e7
    progit.lib.update_tags_issue(
Pierre-Yves Chibon c99f14
        session, issue, tags, username=user.user, ticketfolder=None)
Pierre-Yves Chibon afa3e7
Pierre-Yves Chibon afa3e7
    # Update depends
Pierre-Yves Chibon afa3e7
    depends = json_data.get('depends', [])
Pierre-Yves Chibon c99f14
    progit.lib.update_dependency_issue(
Pierre-Yves Chibon c99f14
        session, issue.project, issue, depends,
Pierre-Yves Chibon c99f14
        username=user.user, ticketfolder=None)
Pierre-Yves Chibon afa3e7
Pierre-Yves Chibon afa3e7
    # Update blocks
Pierre-Yves Chibon afa3e7
    blocks = json_data.get('blocks', [])
Pierre-Yves Chibon c99f14
    progit.lib.update_blocked_issue(
Pierre-Yves Chibon c99f14
        session, issue.project, issue, blocks,
Pierre-Yves Chibon c99f14
        username=user.user, ticketfolder=None)
Pierre-Yves Chibon afa3e7
Pierre-Yves Chibon c7f9fa
    for comment in json_data['comments']:
Pierre-Yves Chibon c7f9fa
        user = get_user_from_json(session, comment)
Pierre-Yves Chibon c7f9fa
        commentobj = progit.lib.get_issue_comment(
Pierre-Yves Chibon c7f9fa
            session, issue_uid, comment['id'])
Pierre-Yves Chibon c7f9fa
        if not commentobj:
Pierre-Yves Chibon c7f9fa
            progit.lib.add_issue_comment(
Pierre-Yves Chibon c7f9fa
                session,
Pierre-Yves Chibon c7f9fa
                issue=issue,
Pierre-Yves Chibon c7f9fa
                comment=comment['comment'],
Pierre-Yves Chibon c7f9fa
                user=user.username,
Pierre-Yves Chibon c7f9fa
                ticketfolder=None,
Pierre-Yves Chibon c7f9fa
                notify=False,
Pierre-Yves Chibon c7f9fa
            )
Pierre-Yves Chibon c7f9fa
    session.commit()
Pierre-Yves Chibon 852918
Pierre-Yves Chibon a6c9f2
def update_request_from_git(
Pierre-Yves Chibon a6c9f2
        session, reponame, username, request_uid, json_data,
Pierre-Yves Chibon a6c9f2
        gitfolder, docfolder, ticketfolder, requestfolder):
Pierre-Yves Chibon a6c9f2
    """ Update the specified request (identified by its unique identifier)
Pierre-Yves Chibon a6c9f2
    with the data present in the json blob provided.
Pierre-Yves Chibon a6c9f2
Pierre-Yves Chibon a6c9f2
    :arg session: the session to connect to the database with.
Pierre-Yves Chibon a6c9f2
    :arg repo: the name of the project to update
Pierre-Yves Chibon a6c9f2
    :arg username: the username to find the repo, is not None for forked
Pierre-Yves Chibon a6c9f2
        projects
Pierre-Yves Chibon a6c9f2
    :arg request_uid: the unique identifier of the issue to update
Pierre-Yves Chibon a6c9f2
    :arg json_data: the json representation of the issue taken from the git
Pierre-Yves Chibon a6c9f2
        and used to update the data in the database.
Pierre-Yves Chibon a6c9f2
Pierre-Yves Chibon a6c9f2
    """
Pierre-Yves Chibon a6c9f2
    print json.dumps(json_data, sort_keys=True,
Pierre-Yves Chibon a6c9f2
                     indent=4, separators=(',', ': '))
Pierre-Yves Chibon a6c9f2
Pierre-Yves Chibon a6c9f2
    repo = progit.lib.get_project(session, reponame, user=username)
Pierre-Yves Chibon a6c9f2
    if not repo:
Pierre-Yves Chibon a6c9f2
        raise progit.exceptions.ProgitException(
Pierre-Yves Chibon a6c9f2
            'Unknown repo %s of username: %s' % (reponame, username))
Pierre-Yves Chibon a6c9f2
Pierre-Yves Chibon a6c9f2
    user = get_user_from_json(session, json_data)
Pierre-Yves Chibon a6c9f2
Pierre-Yves Chibon a6c9f2
    request = progit.lib.get_request_by_uid(
Pierre-Yves Chibon a6c9f2
        session, request_uid=request_uid)
Pierre-Yves Chibon a6c9f2
Pierre-Yves Chibon a6c9f2
    if not request:
Pierre-Yves Chibon a6c9f2
        repo_from = get_project_from_json(
Pierre-Yves Chibon a6c9f2
            session, json_data.get('repo_from'),
Pierre-Yves Chibon a6c9f2
            gitfolder, docfolder, ticketfolder, requestfolder
Pierre-Yves Chibon a6c9f2
        )
Pierre-Yves Chibon a6c9f2
Pierre-Yves Chibon a6c9f2
        repo_to = get_project_from_json(
Pierre-Yves Chibon a6c9f2
            session, json_data.get('repo'),
Pierre-Yves Chibon a6c9f2
            gitfolder, docfolder, ticketfolder, requestfolder
Pierre-Yves Chibon a6c9f2
        )
Pierre-Yves Chibon a6c9f2
Pierre-Yves Chibon a6c9f2
        # Create new request
Pierre-Yves Chibon a6c9f2
        progit.lib.new_pull_request(
Pierre-Yves Chibon a6c9f2
            session,
Pierre-Yves Chibon a6c9f2
            repo_from=repo_from,
Pierre-Yves Chibon a6c9f2
            branch_from=json_data.get('branch_from'),
Pierre-Yves Chibon a6c9f2
            repo_to=repo_to,
Pierre-Yves Chibon a6c9f2
            branch_to=json_data.get('branch'),
Pierre-Yves Chibon a6c9f2
            title=json_data.get('title'),
Pierre-Yves Chibon a6c9f2
            user=user.username,
Pierre-Yves Chibon a6c9f2
            requestuid=json_data.get('uid'),
Pierre-Yves Chibon a6c9f2
            requestid=json_data.get('id'),
Pierre-Yves Chibon a6c9f2
            status= json_data.get('status'),
Pierre-Yves Chibon a6c9f2
            requestfolder=None,
Pierre-Yves Chibon a6c9f2
            notify=False,
Pierre-Yves Chibon a6c9f2
        )
Pierre-Yves Chibon a6c9f2
        session.commit()
Pierre-Yves Chibon a6c9f2
Pierre-Yves Chibon a6c9f2
    request = progit.lib.get_request_by_uid(
Pierre-Yves Chibon a6c9f2
        session, request_uid=request_uid)
Pierre-Yves Chibon a6c9f2
Pierre-Yves Chibon a6c9f2
    for comment in json_data['comments']:
Pierre-Yves Chibon a6c9f2
        user = get_user_from_json(session, comment)
Pierre-Yves Chibon a6c9f2
        commentobj = progit.lib.get_request_comment(
Pierre-Yves Chibon a6c9f2
            session, request_uid, comment['id'])
Pierre-Yves Chibon a6c9f2
        if not commentobj:
Pierre-Yves Chibon a6c9f2
            progit.lib.add_pull_request_comment(
Pierre-Yves Chibon a6c9f2
                session,
Pierre-Yves Chibon a6c9f2
                request,
Pierre-Yves Chibon a6c9f2
                commit=comment['commit'],
Pierre-Yves Chibon a6c9f2
                filename=comment['filename'],
Pierre-Yves Chibon a6c9f2
                row=comment['line'],
Pierre-Yves Chibon a6c9f2
                comment=comment['comment'],
Pierre-Yves Chibon a6c9f2
                user=user.username,
Pierre-Yves Chibon a6c9f2
                requestfolder=None,
Pierre-Yves Chibon a6c9f2
            )
Pierre-Yves Chibon a6c9f2
    session.commit()
Pierre-Yves Chibon a6c9f2
Pierre-Yves Chibon 852918
Pierre-Yves Chibon 852918
def add_file_to_git(repo, issue, ticketfolder, user, filename, filestream):
Pierre-Yves Chibon 852918
    ''' Add a given file to the specified ticket git repository.
Pierre-Yves Chibon 852918
Pierre-Yves Chibon 852918
    :arg repo: the Project object from the database
Pierre-Yves Chibon 852918
    :arg ticketfolder: the folder on the filesystem where the git repo for
Pierre-Yves Chibon 852918
        tickets are stored
Pierre-Yves Chibon 852918
    :arg user: the user object with its username and email
Pierre-Yves Chibon 852918
    :arg filename: the name of the file to save
Pierre-Yves Chibon 852918
    :arg filestream: the actual content of the file
Pierre-Yves Chibon 852918
Pierre-Yves Chibon 852918
    '''
Pierre-Yves Chibon 852918
Pierre-Yves Chibon 852918
    if not ticketfolder:
Pierre-Yves Chibon 852918
        return
Pierre-Yves Chibon 852918
Pierre-Yves Chibon 852918
    # Prefix the filename with a timestamp:
Pierre-Yves Chibon 852918
    filename = '%s-%s' % (
Pierre-Yves Chibon 852918
        hashlib.sha256(filestream.read()).hexdigest(),
Pierre-Yves Chibon 2c34e0
        werkzeug.secure_filename(filename)
Pierre-Yves Chibon 852918
    )
Pierre-Yves Chibon 852918
Pierre-Yves Chibon 852918
    # Get the fork
Pierre-Yves Chibon 852918
    repopath = os.path.join(ticketfolder, repo.path)
Pierre-Yves Chibon 852918
    ticket_repo = pygit2.Repository(repopath)
Pierre-Yves Chibon 852918
Pierre-Yves Chibon 852918
    # Clone the repo into a temp folder
Pierre-Yves Chibon 852918
    newpath = tempfile.mkdtemp()
Pierre-Yves Chibon 852918
    new_repo = pygit2.clone_repository(repopath, newpath)
Pierre-Yves Chibon 852918
Pierre-Yves Chibon 852918
    folder_path = os.path.join(newpath, 'files')
Pierre-Yves Chibon 852918
    file_path = os.path.join(folder_path, filename)
Pierre-Yves Chibon 852918
Pierre-Yves Chibon 852918
    # Get the current index
Pierre-Yves Chibon 852918
    index = new_repo.index
Pierre-Yves Chibon 852918
Pierre-Yves Chibon 852918
    # Are we adding files
Pierre-Yves Chibon 852918
    added = False
Pierre-Yves Chibon 852918
    if not os.path.exists(file_path):
Pierre-Yves Chibon 852918
        added = True
Pierre-Yves Chibon 852918
    else:
Pierre-Yves Chibon 852918
        # File exists, remove the clone and return
Pierre-Yves Chibon 852918
        shutil.rmtree(newpath)
Pierre-Yves Chibon 852918
        return os.path.join('files', filename)
Pierre-Yves Chibon 852918
Pierre-Yves Chibon 852918
    if not os.path.exists(folder_path):
Pierre-Yves Chibon 852918
        os.mkdir(folder_path)
Pierre-Yves Chibon 852918
Pierre-Yves Chibon 852918
    # Write down what changed
Pierre-Yves Chibon 852918
    filestream.seek(0)
Pierre-Yves Chibon 852918
    with open(file_path, 'w') as stream:
Pierre-Yves Chibon 852918
        stream.write(filestream.read())
Pierre-Yves Chibon 852918
Pierre-Yves Chibon 852918
    # Retrieve the list of files that changed
Pierre-Yves Chibon 852918
    diff = new_repo.diff()
Pierre-Yves Chibon 852918
    files = [patch.new_file_path for patch in diff]
Pierre-Yves Chibon 852918
Pierre-Yves Chibon 852918
    # Add the changes to the index
Pierre-Yves Chibon 852918
    if added:
Pierre-Yves Chibon 852918
        index.add(os.path.join('files', filename))
Pierre-Yves Chibon 852918
    for filename in files:
Pierre-Yves Chibon 852918
        index.add(filename)
Pierre-Yves Chibon 852918
Pierre-Yves Chibon 852918
    # If not change, return
Pierre-Yves Chibon 852918
    if not files and not added:
Pierre-Yves Chibon 852918
        shutil.rmtree(newpath)
Pierre-Yves Chibon 852918
        return
Pierre-Yves Chibon 852918
Pierre-Yves Chibon 852918
    # See if there is a parent to this commit
Pierre-Yves Chibon 852918
    parent = None
Pierre-Yves Chibon 852918
    try:
Pierre-Yves Chibon 852918
        parent = new_repo.head.get_object().oid
Pierre-Yves Chibon 852918
    except pygit2.GitError:
Pierre-Yves Chibon 852918
        pass
Pierre-Yves Chibon 852918
Pierre-Yves Chibon 852918
    parents = []
Pierre-Yves Chibon 852918
    if parent:
Pierre-Yves Chibon 852918
        parents.append(parent)
Pierre-Yves Chibon 852918
Pierre-Yves Chibon 852918
    # Author/commiter will always be this one
Pierre-Yves Chibon 852918
    author = pygit2.Signature(
Pierre-Yves Chibon 852918
        name=user.username,
Pierre-Yves Chibon 852918
        email=user.email
Pierre-Yves Chibon 852918
    )
Pierre-Yves Chibon 852918
Pierre-Yves Chibon 852918
    # Actually commit
Pierre-Yves Chibon 852918
    sha = new_repo.create_commit(
Pierre-Yves Chibon 852918
        'refs/heads/master',
Pierre-Yves Chibon 852918
        author,
Pierre-Yves Chibon 852918
        author,
Pierre-Yves Chibon 852918
        'Add file %s to ticket %s: %s' % (filename, issue.uid, issue.title),
Pierre-Yves Chibon 852918
        new_repo.index.write_tree(),
Pierre-Yves Chibon 852918
        parents)
Pierre-Yves Chibon 852918
    index.write()
Pierre-Yves Chibon 852918
Pierre-Yves Chibon 852918
    # Push to origin
Pierre-Yves Chibon 852918
    ori_remote = new_repo.remotes[0]
Pierre-Yves Chibon 852918
    master_ref = new_repo.lookup_reference('HEAD').resolve()
Pierre-Yves Chibon 852918
    refname = '%s:%s' % (master_ref.name, master_ref.name)
Pierre-Yves Chibon 852918
Pierre-Yves Chibon 852918
    ori_remote.push(refname)
Pierre-Yves Chibon 852918
Pierre-Yves Chibon 852918
    # Remove the clone
Pierre-Yves Chibon 852918
    shutil.rmtree(newpath)
Pierre-Yves Chibon 852918
Pierre-Yves Chibon 852918
    return os.path.join('files', filename)