Blame progit/lib/__init__.py

Pierre-Yves Chibon 33b534
# -*- coding: utf-8 -*-
Pierre-Yves Chibon 1e2e25
Pierre-Yves Chibon 1e2e25
"""
Pierre-Yves Chibon 8a5345
 (c) 2014-2015 - Copyright Red Hat Inc
Pierre-Yves Chibon 1e2e25
Pierre-Yves Chibon 1e2e25
 Authors:
Pierre-Yves Chibon 1e2e25
   Pierre-Yves Chibon <pingou@pingoured.fr></pingou@pingoured.fr>
Pierre-Yves Chibon 1e2e25
Pierre-Yves Chibon 1e2e25
"""
Pierre-Yves Chibon 1e2e25
Pierre-Yves Chibon 1e2e25
Pierre-Yves Chibon 9af5a0
import datetime
Pierre-Yves Chibon d8110b
import os
Pierre-Yves Chibon d133cd
import shutil
Pierre-Yves Chibon d133cd
import tempfile
Pierre-Yves Chibon 9cb884
import uuid
Pierre-Yves Chibon d8110b
Pierre-Yves Chibon 1e2e25
import sqlalchemy
Pierre-Yves Chibon 42693f
import sqlalchemy.schema
Pierre-Yves Chibon 1e2e25
from datetime import timedelta
Pierre-Yves Chibon 42693f
from sqlalchemy import func
Pierre-Yves Chibon 1e2e25
from sqlalchemy.orm import sessionmaker
Pierre-Yves Chibon 1e2e25
from sqlalchemy.orm import scoped_session
Pierre-Yves Chibon 1e2e25
from sqlalchemy.orm.exc import NoResultFound
Pierre-Yves Chibon 1e2e25
from sqlalchemy.exc import SQLAlchemyError
Pierre-Yves Chibon 1e2e25
Pierre-Yves Chibon d8110b
import pygit2
Pierre-Yves Chibon d8110b
Pierre-Yves Chibon d8110b
import progit.exceptions
Pierre-Yves Chibon 9fe916
import progit.lib.git
Pierre-Yves Chibon f2c72b
import progit.lib.notify
Pierre-Yves Chibon 26b4f4
from progit.lib import model
Pierre-Yves Chibon 1e2e25
Pierre-Yves Chibon 1e2e25
Pierre-Yves Chibon 60bea3
def __get_user(session, key):
Pierre-Yves Chibon 60bea3
    """ Searches for a user in the database for a given username or email.
Pierre-Yves Chibon 60bea3
    """
Pierre-Yves Chibon 60bea3
    user_obj = search_user(session, username=key)
Pierre-Yves Chibon 60bea3
    if not user_obj:
Pierre-Yves Chibon 60bea3
        user_obj = search_user(session, email=key)
Pierre-Yves Chibon 60bea3
Pierre-Yves Chibon 60bea3
    if not user_obj:
Pierre-Yves Chibon 60bea3
        raise progit.exceptions.ProgitException(
Pierre-Yves Chibon 60bea3
            'No user "%s" found' % key
Pierre-Yves Chibon 60bea3
        )
Pierre-Yves Chibon 60bea3
Pierre-Yves Chibon 60bea3
    return user_obj
Pierre-Yves Chibon 60bea3
Pierre-Yves Chibon 60bea3
Pierre-Yves Chibon 1e2e25
def create_session(db_url, debug=False, pool_recycle=3600):
Pierre-Yves Chibon 695ef6
    ''' Create the Session object to use to query the database.
Pierre-Yves Chibon 1e2e25
Pierre-Yves Chibon 1e2e25
    :arg db_url: URL used to connect to the database. The URL contains
Pierre-Yves Chibon 1e2e25
    information with regards to the database engine, the host to connect
Pierre-Yves Chibon 1e2e25
    to, the user and password and the database name.
Pierre-Yves Chibon 1e2e25
      ie: <engine>://<user>:<password>@<host>/<dbname></dbname></host></password></user></engine>
Pierre-Yves Chibon 1e2e25
    :kwarg debug: a boolean specifying wether we should have the verbose
Pierre-Yves Chibon 1e2e25
        output of sqlalchemy or not.
Pierre-Yves Chibon 1e2e25
    :return a Session that can be used to query the database.
Pierre-Yves Chibon 1e2e25
Pierre-Yves Chibon 695ef6
    '''
Pierre-Yves Chibon 1e2e25
    engine = sqlalchemy.create_engine(
Pierre-Yves Chibon 1e2e25
        db_url, echo=debug, pool_recycle=pool_recycle)
Pierre-Yves Chibon 1e2e25
    scopedsession = scoped_session(sessionmaker(bind=engine))
Pierre-Yves Chibon 1e2e25
    return scopedsession
Pierre-Yves Chibon 1e2e25
Pierre-Yves Chibon 1e2e25
Pierre-Yves Chibon 42693f
def get_next_id(session, projectid):
Pierre-Yves Chibon 42693f
    """ Returns the next identifier of a project ticket or pull-request
Pierre-Yves Chibon 42693f
    based on the identifier already in the database.
Pierre-Yves Chibon 42693f
    """
Pierre-Yves Chibon 42693f
    q1 = session.query(
Pierre-Yves Chibon 7909ea
        func.max(model.Issue.id)
Pierre-Yves Chibon 42693f
    ).filter(
Pierre-Yves Chibon 42693f
        model.Issue.project_id == projectid
Pierre-Yves Chibon 42693f
    )
Pierre-Yves Chibon 42693f
Pierre-Yves Chibon 42693f
    q2 = session.query(
Pierre-Yves Chibon 7909ea
        func.max(model.PullRequest.id)
Pierre-Yves Chibon 42693f
    ).filter(
Pierre-Yves Chibon 42693f
        model.PullRequest.project_id == projectid
Pierre-Yves Chibon 42693f
    )
Pierre-Yves Chibon 42693f
Pierre-Yves Chibon 7909ea
    nid = max([el[0] for el in q1.union(q2).all()]) or 0
Pierre-Yves Chibon 42693f
Pierre-Yves Chibon 7909ea
    return nid + 1
Pierre-Yves Chibon 42693f
Pierre-Yves Chibon 42693f
Pierre-Yves Chibon de2a45
def search_user(session, username=None, email=None, token=None, pattern=None):
Pierre-Yves Chibon de2a45
    ''' Searches the database for the user or users matching the given
Pierre-Yves Chibon de2a45
    criterias.
Pierre-Yves Chibon de2a45
Pierre-Yves Chibon de2a45
    :arg session: the session to use to connect to the database.
Pierre-Yves Chibon de2a45
    :kwarg username: the username of the user to look for.
Pierre-Yves Chibon de2a45
    :type username: string or None
Pierre-Yves Chibon de2a45
    :kwarg email: the email or one of the email of the user to look for
Pierre-Yves Chibon de2a45
    :type email: string or None
Pierre-Yves Chibon de2a45
    :kwarg token: the token of the user to look for
Pierre-Yves Chibon de2a45
    :type token: string or None
Pierre-Yves Chibon de2a45
    :kwarg pattern: a pattern to search the users with.
Pierre-Yves Chibon de2a45
    :type pattern: string or None
Pierre-Yves Chibon de2a45
    :return: A single User object if any of username, email or token is
Pierre-Yves Chibon de2a45
        specified, a list of User objects otherwise.
Pierre-Yves Chibon de2a45
    :rtype: User or [User]
Pierre-Yves Chibon 34cbca
Pierre-Yves Chibon 34cbca
    '''
Pierre-Yves Chibon 4cbbea
    query = session.query(
Pierre-Yves Chibon 556d85
        model.User
Pierre-Yves Chibon 4cbbea
    )
Pierre-Yves Chibon 4cbbea
Pierre-Yves Chibon de2a45
    if username is not None:
Pierre-Yves Chibon de2a45
        query = query.filter(
Pierre-Yves Chibon de2a45
            model.User.user == username
Pierre-Yves Chibon de2a45
        )
Pierre-Yves Chibon de2a45
Pierre-Yves Chibon de2a45
    if email is not None:
Pierre-Yves Chibon de2a45
        query = query.filter(
Pierre-Yves Chibon de2a45
            model.UserEmail.user_id == model.User.id
Pierre-Yves Chibon de2a45
        ).filter(
Pierre-Yves Chibon de2a45
            model.UserEmail.email == email
Pierre-Yves Chibon de2a45
        )
Pierre-Yves Chibon de2a45
Pierre-Yves Chibon de2a45
    if token is not None:
Pierre-Yves Chibon de2a45
        query = query.filter(
Pierre-Yves Chibon de2a45
            model.User.token == token
Pierre-Yves Chibon de2a45
        )
Pierre-Yves Chibon de2a45
Pierre-Yves Chibon 4cbbea
    if pattern:
Pierre-Yves Chibon 4cbbea
        pattern = pattern.replace('*', '%')
Pierre-Yves Chibon 4cbbea
        query = query.filter(
Pierre-Yves Chibon 4cbbea
            model.User.user.like(pattern)
Pierre-Yves Chibon 4cbbea
        )
Pierre-Yves Chibon 4cbbea
Pierre-Yves Chibon de2a45
    if any([username, email, token]):
Pierre-Yves Chibon de2a45
        output = query.first()
Pierre-Yves Chibon de2a45
    else:
Pierre-Yves Chibon de2a45
        output = query.all()
Pierre-Yves Chibon de2a45
Pierre-Yves Chibon de2a45
    return output
Pierre-Yves Chibon 556d85
Pierre-Yves Chibon 556d85
Pierre-Yves Chibon a34835
def add_issue_comment(session, issue, comment, user, ticketfolder):
Pierre-Yves Chibon 03c11f
    ''' Add a comment to an issue. '''
Pierre-Yves Chibon 60bea3
    user_obj = __get_user(session, user)
Pierre-Yves Chibon e1372f
Pierre-Yves Chibon 00c3f0
    issue_comment = model.IssueComment(
Pierre-Yves Chibon cc99df
        issue_uid=issue.uid,
Pierre-Yves Chibon 359db9
        comment=comment,
Pierre-Yves Chibon e1372f
        user_id=user_obj.id,
Pierre-Yves Chibon 359db9
    )
Pierre-Yves Chibon 00c3f0
    session.add(issue_comment)
Pierre-Yves Chibon 359db9
    # Make sure we won't have SQLAlchemy error before we create the repo
Pierre-Yves Chibon 44a755
    session.commit()
Pierre-Yves Chibon 359db9
Pierre-Yves Chibon 9fe916
    progit.lib.git.update_git_ticket(
Pierre-Yves Chibon 9fe916
        issue, repo=issue.project, ticketfolder=ticketfolder)
Pierre-Yves Chibon a34835
Pierre-Yves Chibon cbb18b
    progit.lib.notify.notify_new_comment(issue_comment)
Pierre-Yves Chibon 4b55b4
Pierre-Yves Chibon 359db9
    return 'Comment added'
Pierre-Yves Chibon 359db9
Pierre-Yves Chibon 359db9
Pierre-Yves Chibon aafc66
def add_issue_tag(session, issue, tag, user, ticketfolder):
Pierre-Yves Chibon aafc66
    ''' Add a tag to an issue. '''
Pierre-Yves Chibon 60bea3
    user_obj = __get_user(session, user)
Pierre-Yves Chibon aafc66
Pierre-Yves Chibon 4feb86
    for tag_issue in issue.tags:
Pierre-Yves Chibon 4feb86
        if tag_issue.tag == tag:
Pierre-Yves Chibon b14570
            raise progit.exceptions.ProgitException(
Pierre-Yves Chibon b14570
                'Tag already present: %s' % tag)
Pierre-Yves Chibon 4feb86
Pierre-Yves Chibon a77b8c
    tagobj = get_tag(session, tag)
Pierre-Yves Chibon a77b8c
    if not tagobj:
Pierre-Yves Chibon a77b8c
        tagobj = model.Tag(tag=tag)
Pierre-Yves Chibon a77b8c
        session.add(tagobj)
Pierre-Yves Chibon 12bd3d
        session.flush()
Pierre-Yves Chibon a77b8c
Pierre-Yves Chibon 3df2cd
    issue_tag = model.TagIssue(
Pierre-Yves Chibon 6b17b3
        issue_uid=issue.uid,
Pierre-Yves Chibon a77b8c
        tag=tagobj.tag,
Pierre-Yves Chibon aafc66
    )
Pierre-Yves Chibon aafc66
    session.add(issue_tag)
Pierre-Yves Chibon aafc66
    # Make sure we won't have SQLAlchemy error before we create the repo
Pierre-Yves Chibon aafc66
    session.flush()
Pierre-Yves Chibon aafc66
Pierre-Yves Chibon c15942
    progit.lib.git.update_git_ticket(
Pierre-Yves Chibon 9fe916
        issue, repo=issue.project, ticketfolder=ticketfolder)
Pierre-Yves Chibon aafc66
Pierre-Yves Chibon aafc66
    return 'Tag added'
Pierre-Yves Chibon aafc66
Pierre-Yves Chibon aafc66
Pierre-Yves Chibon cdaaf3
def add_issue_assignee(session, issue, assignee, user, ticketfolder):
Pierre-Yves Chibon cdaaf3
    ''' Add an assignee to an issue, in other words, assigned an issue. '''
Pierre-Yves Chibon e39d28
    if assignee is None:
Pierre-Yves Chibon e39d28
        issue.assignee_id = None
Pierre-Yves Chibon e39d28
        session.add(issue)
Pierre-Yves Chibon e39d28
        session.commit()
Pierre-Yves Chibon 9fe916
        progit.lib.git.update_git_ticket(
Pierre-Yves Chibon e39d28
            issue, repo=issue.project, ticketfolder=ticketfolder)
Pierre-Yves Chibon e39d28
Pierre-Yves Chibon cbb18b
        progit.lib.notify.notify_assigned_issue(issue, None, user)
Pierre-Yves Chibon e39d28
        return 'Assignee reset'
Pierre-Yves Chibon e39d28
Pierre-Yves Chibon 60bea3
    user_obj = __get_user(session, user)
Pierre-Yves Chibon cdaaf3
    # Validate the assignee
Pierre-Yves Chibon 60bea3
    user_obj = __get_user(session, assignee)
Pierre-Yves Chibon cdaaf3
Pierre-Yves Chibon cdaaf3
    if issue.assignee_id != user_obj.id:
Pierre-Yves Chibon cdaaf3
        issue.assignee_id = user_obj.id
Pierre-Yves Chibon cdaaf3
        session.add(issue)
Pierre-Yves Chibon cdaaf3
        session.flush()
Pierre-Yves Chibon 9fe916
        progit.lib.git.update_git_ticket(
Pierre-Yves Chibon cdaaf3
            issue, repo=issue.project, ticketfolder=ticketfolder)
Pierre-Yves Chibon ff30f1
Pierre-Yves Chibon cbb18b
        progit.lib.notify.notify_assigned_issue(issue, user_obj, user)
Pierre-Yves Chibon ff30f1
Pierre-Yves Chibon cdaaf3
        return 'Issue assigned'
Pierre-Yves Chibon cdaaf3
Pierre-Yves Chibon cdaaf3
Pierre-Yves Chibon e523bf
def add_issue_dependency(session, issue, issue_blocked, user, ticketfolder):
Pierre-Yves Chibon e523bf
    ''' Add a dependency between two issues. '''
Pierre-Yves Chibon 60bea3
    user_obj = __get_user(session, user)
Pierre-Yves Chibon ad1385
Pierre-Yves Chibon ed19c4
    if issue.uid == issue_blocked.uid:
Pierre-Yves Chibon ed19c4
        raise progit.exceptions.ProgitException(
Pierre-Yves Chibon ed19c4
            'An issue cannot depend on itself'
Pierre-Yves Chibon ed19c4
        )
Pierre-Yves Chibon ed19c4
Pierre-Yves Chibon ad1385
    if issue_blocked not in issue.children:
Pierre-Yves Chibon ad1385
        i2i = model.IssueToIssue(
Pierre-Yves Chibon ad1385
            parent_issue_id=issue_blocked.uid,
Pierre-Yves Chibon ad1385
            child_issue_id=issue.uid
Pierre-Yves Chibon ad1385
        )
Pierre-Yves Chibon ad1385
        session.add(i2i)
Pierre-Yves Chibon ad1385
        # Make sure we won't have SQLAlchemy error before we create the repo
Pierre-Yves Chibon ad1385
        session.flush()
Pierre-Yves Chibon 9fe916
        progit.lib.git.update_git_ticket(
Pierre-Yves Chibon ad1385
            issue, repo=issue.project, ticketfolder=ticketfolder)
Pierre-Yves Chibon 9fe916
        progit.lib.git.update_git_ticket(
Pierre-Yves Chibon ad1385
            issue_blocked,
Pierre-Yves Chibon ad1385
            repo=issue_blocked.project,
Pierre-Yves Chibon ad1385
            ticketfolder=ticketfolder)
Pierre-Yves Chibon ad1385
Pierre-Yves Chibon cbb18b
        #progit.lib.notify.notify_assigned_issue(issue, user_obj)
Pierre-Yves Chibon cbb18b
        #progit.lib.notify.notify_assigned_issue(issue_blocked, user_obj)
Pierre-Yves Chibon ad1385
Pierre-Yves Chibon 7e765d
        return 'Dependency added'
Pierre-Yves Chibon ad1385
Pierre-Yves Chibon ad1385
Pierre-Yves Chibon 83cba8
def remove_issue_tags(session, project, tags):
Pierre-Yves Chibon 83cba8
    ''' Removes the specified tag of a project. '''
Pierre-Yves Chibon 83cba8
Pierre-Yves Chibon 83cba8
    if not isinstance(tags, list):
Pierre-Yves Chibon 83cba8
        tags = [tags]
Pierre-Yves Chibon 83cba8
Pierre-Yves Chibon 3b7b2b
    issues = search_issues(session, project, closed=False, tags=tags)
Pierre-Yves Chibon 3b7b2b
    issues.extend(search_issues(session, project, closed=True, tags=tags))
Pierre-Yves Chibon 83cba8
Pierre-Yves Chibon 83cba8
    msgs = []
Pierre-Yves Chibon 83cba8
    if not issues:
Pierre-Yves Chibon 83cba8
        raise progit.exceptions.ProgitException(
Pierre-Yves Chibon 782b9c
            'No issue found with the tags: %s' % ', '.join(tags))
Pierre-Yves Chibon 83cba8
    else:
Pierre-Yves Chibon 83cba8
        for issue in issues:
Pierre-Yves Chibon 782b9c
            for issue_tag in issue.tags:
Pierre-Yves Chibon 83cba8
                if issue_tag.tag in tags:
Pierre-Yves Chibon 83cba8
                    tag = issue_tag.tag
Pierre-Yves Chibon 83cba8
                    session.delete(issue_tag)
Pierre-Yves Chibon 83cba8
                    msgs.append('Removed tag: %s' % tag)
Pierre-Yves Chibon 83cba8
    return msgs
Pierre-Yves Chibon 83cba8
Pierre-Yves Chibon 83cba8
Pierre-Yves Chibon 9d0844
def edit_issue_tags(session, project, old_tag, new_tag):
Pierre-Yves Chibon 9d0844
    ''' Removes the specified tag of a project. '''
Pierre-Yves Chibon 9d0844
Pierre-Yves Chibon 58adfc
    if old_tag == new_tag:
Pierre-Yves Chibon 58adfc
        raise progit.exceptions.ProgitException(
Pierre-Yves Chibon 58adfc
            'Old tag: "%s" is the same as new tag "%s", nothing to change'
Pierre-Yves Chibon 58adfc
            % (old_tag, new_tag))
Pierre-Yves Chibon 9d0844
Pierre-Yves Chibon 58adfc
    issues = search_issues(session, project, closed=False, tags=old_tag)
Pierre-Yves Chibon 58adfc
    issues.extend(search_issues(session, project, closed=True, tags=old_tag))
Pierre-Yves Chibon 9d0844
Pierre-Yves Chibon 9d0844
    msgs = []
Pierre-Yves Chibon 9d0844
    if not issues:
Pierre-Yves Chibon 9d0844
        raise progit.exceptions.ProgitException(
Pierre-Yves Chibon 9d0844
            'No issue found with the tags: %s' % old_tag)
Pierre-Yves Chibon 9d0844
    else:
Pierre-Yves Chibon 9d0844
        tagobj = get_tag(session, new_tag)
Pierre-Yves Chibon 9d0844
        if not tagobj:
Pierre-Yves Chibon 9d0844
            tagobj = model.Tag(tag=new_tag)
Pierre-Yves Chibon 9d0844
            session.add(tagobj)
Pierre-Yves Chibon 9d0844
Pierre-Yves Chibon 9d0844
        for issue in issues:
Pierre-Yves Chibon 333cb7
            add = True
Pierre-Yves Chibon 9d0844
            # Drop the old tag
Pierre-Yves Chibon 58adfc
            for issue_tag in issue.tags:
Pierre-Yves Chibon 58adfc
                if issue_tag.tag == old_tag:
Pierre-Yves Chibon 9d0844
                    session.delete(issue_tag)
Pierre-Yves Chibon 333cb7
Pierre-Yves Chibon 333cb7
            if add:
Pierre-Yves Chibon 333cb7
                # Add the new one
Pierre-Yves Chibon 333cb7
                issue_tag = model.TagIssue(
Pierre-Yves Chibon 58adfc
                    issue_uid=issue.uid,
Pierre-Yves Chibon 333cb7
                    tag=new_tag
Pierre-Yves Chibon 333cb7
                )
Pierre-Yves Chibon 333cb7
                session.add(issue_tag)
Pierre-Yves Chibon 333cb7
                msgs.append('Edited tag: %s to %s' % (old_tag, new_tag))
Pierre-Yves Chibon 9d0844
Pierre-Yves Chibon 9d0844
    return msgs
Pierre-Yves Chibon 9d0844
Pierre-Yves Chibon 08c7a3
Pierre-Yves Chibon b9cb1e
def add_user_to_project(session, project, user):
Pierre-Yves Chibon b9cb1e
    ''' Add a specified user to a specified project. '''
Pierre-Yves Chibon 60bea3
    user_obj = __get_user(session, user)
Pierre-Yves Chibon b9cb1e
Pierre-Yves Chibon b9cb1e
    project_user = model.ProjectUser(
Pierre-Yves Chibon b9cb1e
        project_id=project.id,
Pierre-Yves Chibon b9cb1e
        user_id=user_obj.id,
Pierre-Yves Chibon b9cb1e
    )
Pierre-Yves Chibon b9cb1e
    session.add(project_user)
Pierre-Yves Chibon b9cb1e
    # Make sure we won't have SQLAlchemy error before we create the repo
Pierre-Yves Chibon b9cb1e
    session.flush()
Pierre-Yves Chibon b9cb1e
Pierre-Yves Chibon c4933c
    return 'User added'
Pierre-Yves Chibon b9cb1e
Pierre-Yves Chibon a8a719
Pierre-Yves Chibon 7df65e
def add_pull_request_comment(session, request, commit, filename, row,
Pierre-Yves Chibon 7df65e
                             comment, user):
Pierre-Yves Chibon 2c11b4
    ''' Add a comment to a pull-request. '''
Pierre-Yves Chibon 60bea3
    user_obj = __get_user(session, user)
Pierre-Yves Chibon 2c11b4
Pierre-Yves Chibon 2c11b4
    pr_comment = model.PullRequestComment(
Pierre-Yves Chibon 446c3d
        pull_request_uid=request.uid,
Pierre-Yves Chibon 2c11b4
        commit_id=commit,
Pierre-Yves Chibon 7df65e
        filename=filename,
Pierre-Yves Chibon 2c11b4
        line=row,
Pierre-Yves Chibon 2c11b4
        comment=comment,
Pierre-Yves Chibon 2c11b4
        user_id=user_obj.id,
Pierre-Yves Chibon 2c11b4
    )
Pierre-Yves Chibon 2c11b4
    session.add(pr_comment)
Pierre-Yves Chibon 2c11b4
    # Make sure we won't have SQLAlchemy error before we create the repo
Pierre-Yves Chibon 2c11b4
    session.flush()
Pierre-Yves Chibon 2c11b4
Pierre-Yves Chibon 2c11b4
    return 'Comment added'
Pierre-Yves Chibon 2c11b4
Pierre-Yves Chibon 2c11b4
Pierre-Yves Chibon 49b899
def new_project(session, user, name, gitfolder, docfolder, ticketfolder,
Pierre-Yves Chibon d8110b
                description=None, parent_id=None):
Pierre-Yves Chibon d8110b
    ''' Create a new project based on the information provided.
Pierre-Yves Chibon d8110b
    '''
Pierre-Yves Chibon 6160b6
    gitrepo = os.path.join(gitfolder, '%s.git' % name)
Pierre-Yves Chibon d8110b
    if os.path.exists(gitrepo):
Pierre-Yves Chibon d8110b
        raise progit.exceptions.RepoExistsException(
Pierre-Yves Chibon ca47fa
            'The project repo "%s" already exists' % name
Pierre-Yves Chibon d8110b
        )
Pierre-Yves Chibon d8110b
Pierre-Yves Chibon 60bea3
    user_obj = __get_user(session, user)
Pierre-Yves Chibon e1372f
Pierre-Yves Chibon d8110b
    project = model.Project(
Pierre-Yves Chibon d8110b
        name=name,
Pierre-Yves Chibon d8110b
        description=description,
Pierre-Yves Chibon e1372f
        user_id=user_obj.id,
Pierre-Yves Chibon d8110b
        parent_id=parent_id
Pierre-Yves Chibon d8110b
    )
Pierre-Yves Chibon d8110b
    session.add(project)
Pierre-Yves Chibon d8110b
    # Make sure we won't have SQLAlchemy error before we create the repo
Pierre-Yves Chibon d8110b
    session.flush()
Pierre-Yves Chibon d8110b
Pierre-Yves Chibon d8110b
    pygit2.init_repository(gitrepo, bare=True)
Pierre-Yves Chibon d8110b
Pierre-Yves Chibon 18042a
    docrepo = os.path.join(docfolder, project.path)
Pierre-Yves Chibon 18042a
    if os.path.exists(docrepo):
Pierre-Yves Chibon 18042a
        shutil.rmtree(gitrepo)
Pierre-Yves Chibon 6160b6
        raise progit.exceptions.RepoExistsException(
Pierre-Yves Chibon ca47fa
            'The docs repo "%s" already exists' % project.path
Pierre-Yves Chibon 6160b6
        )
Pierre-Yves Chibon 18042a
    pygit2.init_repository(docrepo, bare=True)
Pierre-Yves Chibon 6160b6
Pierre-Yves Chibon 18042a
    ticketrepo = os.path.join(ticketfolder, project.path)
Pierre-Yves Chibon 18042a
    if os.path.exists(ticketrepo):
Pierre-Yves Chibon 18042a
        shutil.rmtree(gitrepo)
Pierre-Yves Chibon 18042a
        shutil.rmtree(docrepo)
Pierre-Yves Chibon 49b899
        raise progit.exceptions.RepoExistsException(
Pierre-Yves Chibon 49b899
            'The tickets repo "%s" already exists' % project.path
Pierre-Yves Chibon 49b899
        )
Pierre-Yves Chibon 18042a
    pygit2.init_repository(ticketrepo, bare=True)
Pierre-Yves Chibon 49b899
Pierre-Yves Chibon d8110b
    return 'Project "%s" created' % name
Mathieu Bridon eb729c
Pierre-Yves Chibon f74093
Pierre-Yves Chibon a34835
def new_issue(session, repo, title, content, user, ticketfolder):
Pierre-Yves Chibon 33ff2c
    ''' Create a new issue for the specified repo. '''
Pierre-Yves Chibon 60bea3
    user_obj = __get_user(session, user)
Pierre-Yves Chibon e1372f
Pierre-Yves Chibon 33ff2c
    issue = model.Issue(
Pierre-Yves Chibon 42693f
        id=get_next_id(session, repo.id),
Pierre-Yves Chibon 33ff2c
        project_id=repo.id,
Pierre-Yves Chibon 33ff2c
        title=title,
Pierre-Yves Chibon 33ff2c
        content=content,
Pierre-Yves Chibon e1372f
        user_id=user_obj.id,
Pierre-Yves Chibon 9cb884
        uid=uuid.uuid4().hex,
Pierre-Yves Chibon 33ff2c
    )
Pierre-Yves Chibon 33ff2c
    session.add(issue)
Pierre-Yves Chibon 057ee1
    # Make sure we won't have SQLAlchemy error before we create the issue
Pierre-Yves Chibon 33ff2c
    session.flush()
Pierre-Yves Chibon 33ff2c
Pierre-Yves Chibon 9fe916
    progit.lib.git.update_git_ticket(
Pierre-Yves Chibon 9fe916
        issue, repo=repo, ticketfolder=ticketfolder)
Pierre-Yves Chibon a34835
Pierre-Yves Chibon cbb18b
    progit.lib.notify.notify_new_issue(issue)
Pierre-Yves Chibon 142bae
Pierre-Yves Chibon 33ff2c
    return 'Issue created'
Pierre-Yves Chibon 33ff2c
Pierre-Yves Chibon 33ff2c
Pierre-Yves Chibon aa5fb9
def new_pull_request(session, repo_from, branch_from,
Pierre-Yves Chibon aa5fb9
                     repo_to, branch_to, title, user):
Pierre-Yves Chibon 472a61
    ''' Create a new pull request on the specified repo. '''
Pierre-Yves Chibon 60bea3
    user_obj = __get_user(session, user)
Pierre-Yves Chibon 7d23c0
Pierre-Yves Chibon 472a61
    request = model.PullRequest(
Pierre-Yves Chibon 5df7a0
        id=get_next_id(session, repo_to.id),
Pierre-Yves Chibon 5df7a0
        uid=uuid.uuid4().hex,
Pierre-Yves Chibon aa5fb9
        project_id=repo_to.id,
Pierre-Yves Chibon 62ec72
        project_id_from=repo_from.id,
Pierre-Yves Chibon aa5fb9
        branch=branch_to,
Pierre-Yves Chibon aa5fb9
        branch_from=branch_from,
Pierre-Yves Chibon 472a61
        title=title,
Pierre-Yves Chibon 7d23c0
        user_id=user_obj.id,
Pierre-Yves Chibon 472a61
    )
Pierre-Yves Chibon 472a61
    session.add(request)
Pierre-Yves Chibon 472a61
    # Make sure we won't have SQLAlchemy error before we create the request
Pierre-Yves Chibon 472a61
    session.flush()
Pierre-Yves Chibon 472a61
Pierre-Yves Chibon cbb18b
    progit.lib.notify.notify_new_pull_request(request)
Pierre-Yves Chibon e0589f
Pierre-Yves Chibon 472a61
    return 'Request created'
Pierre-Yves Chibon 472a61
Pierre-Yves Chibon 472a61
Pierre-Yves Chibon a34835
def edit_issue(session, issue, ticketfolder,
Pierre-Yves Chibon a34835
               title=None, content=None, status=None):
Pierre-Yves Chibon c71370
    ''' Edit the specified issue.
Pierre-Yves Chibon c71370
    '''
Pierre-Yves Chibon c71370
    edit = []
Pierre-Yves Chibon fb8b6c
    if title and title != issue.title:
Pierre-Yves Chibon c71370
        issue.title = title
Pierre-Yves Chibon c71370
        edit.append('title')
Pierre-Yves Chibon fb8b6c
    if content and content != issue.content:
Pierre-Yves Chibon c71370
        issue.content = content
Pierre-Yves Chibon c71370
        edit.append('content')
Pierre-Yves Chibon fb8b6c
    if status and status != issue.status:
Pierre-Yves Chibon 4d1cbe
        issue.status = status
Pierre-Yves Chibon 4d1cbe
        edit.append('status')
Pierre-Yves Chibon c71370
Pierre-Yves Chibon 9fe916
    progit.lib.git.update_git_ticket(
Pierre-Yves Chibon 9fe916
        issue, repo=issue.project, ticketfolder=ticketfolder)
Pierre-Yves Chibon a34835
Pierre-Yves Chibon c71370
    if not edit:
Pierre-Yves Chibon c71370
        return 'No changes to edit'
Pierre-Yves Chibon c71370
    else:
Pierre-Yves Chibon c71370
        session.add(issue)
Pierre-Yves Chibon c71370
        session.flush()
Pierre-Yves Chibon c71370
        return 'Edited successfully issue #%s' % issue.id
Pierre-Yves Chibon c71370
Pierre-Yves Chibon c71370
Pierre-Yves Chibon b39aa4
def update_project_settings(session, repo, issue_tracker, project_docs):
Pierre-Yves Chibon b39aa4
    ''' Update the settings of a project. '''
Pierre-Yves Chibon b39aa4
    update = []
Pierre-Yves Chibon b39aa4
    if issue_tracker != repo.issue_tracker:
Pierre-Yves Chibon b39aa4
        repo.issue_tracker = issue_tracker
Pierre-Yves Chibon b39aa4
        update.append('issue_tracker')
Pierre-Yves Chibon b39aa4
    if project_docs != repo.project_docs:
Pierre-Yves Chibon b39aa4
        repo.project_docs = project_docs
Pierre-Yves Chibon b39aa4
        update.append('project_docs')
Pierre-Yves Chibon b39aa4
Pierre-Yves Chibon b39aa4
    if not update:
Pierre-Yves Chibon b39aa4
        return 'No settings to change'
Pierre-Yves Chibon b39aa4
    else:
Pierre-Yves Chibon b39aa4
        session.add(repo)
Pierre-Yves Chibon b39aa4
        session.flush()
Pierre-Yves Chibon 511a11
        return 'Edited successfully settings of repo: %s' % repo.fullname
Pierre-Yves Chibon b39aa4
Pierre-Yves Chibon b39aa4
Pierre-Yves Chibon a33978
def fork_project(session, user, repo, gitfolder,
Pierre-Yves Chibon 7407c0
                 forkfolder, docfolder, ticketfolder):
Pierre-Yves Chibon 652c2c
    ''' Fork a given project into the user's forks. '''
Pierre-Yves Chibon df2470
    if repo.is_fork:
Pierre-Yves Chibon df2470
        reponame = os.path.join(forkfolder, repo.path)
Pierre-Yves Chibon df2470
    else:
Pierre-Yves Chibon df2470
        reponame = os.path.join(gitfolder, repo.path)
Pierre-Yves Chibon df2470
    forkreponame = '%s.git' % os.path.join(forkfolder, user, repo.name)
Pierre-Yves Chibon 652c2c
Pierre-Yves Chibon 9e91eb
    if repo.user.user == user:
Pierre-Yves Chibon 9e91eb
        raise progit.exceptions.RepoExistsException(
Pierre-Yves Chibon 9e91eb
            'You may not fork your own repo')
Pierre-Yves Chibon 9e91eb
Pierre-Yves Chibon 652c2c
    if os.path.exists(forkreponame):
Pierre-Yves Chibon 652c2c
        raise progit.exceptions.RepoExistsException(
Pierre-Yves Chibon 652c2c
            'Repo "%s/%s" already exists' % (user, repo.name))
Pierre-Yves Chibon 652c2c
Pierre-Yves Chibon 60bea3
    user_obj = __get_user(session, user)
Pierre-Yves Chibon e1372f
Pierre-Yves Chibon 652c2c
    project = model.Project(
Pierre-Yves Chibon 652c2c
        name=repo.name,
Pierre-Yves Chibon 652c2c
        description=repo.description,
Pierre-Yves Chibon e1372f
        user_id=user_obj.id,
Pierre-Yves Chibon 652c2c
        parent_id=repo.id
Pierre-Yves Chibon 652c2c
    )
Pierre-Yves Chibon 652c2c
    session.add(project)
Pierre-Yves Chibon 652c2c
    # Make sure we won't have SQLAlchemy error before we create the repo
Pierre-Yves Chibon 652c2c
    session.flush()
Pierre-Yves Chibon 652c2c
Pierre-Yves Chibon d01de7
    pygit2.clone_repository(reponame, forkreponame, bare=True)
Pierre-Yves Chibon 652c2c
Pierre-Yves Chibon b09b48
    docrepo = os.path.join(docfolder, project.path)
Pierre-Yves Chibon b09b48
    if os.path.exists(docrepo):
Pierre-Yves Chibon b09b48
        shutil.rmtree(forkreponame)
Pierre-Yves Chibon 6160b6
        raise progit.exceptions.RepoExistsException(
Pierre-Yves Chibon 4b7a7d
            'The docs "%s" already exists' % project.path
Pierre-Yves Chibon 6160b6
        )
Pierre-Yves Chibon b09b48
    pygit2.init_repository(docrepo, bare=True)
Pierre-Yves Chibon a33978
Pierre-Yves Chibon b09b48
    ticketrepo = os.path.join(ticketfolder, project.path)
Pierre-Yves Chibon b09b48
    if os.path.exists(ticketrepo):
Pierre-Yves Chibon b09b48
        shutil.rmtree(forkreponame)
Pierre-Yves Chibon b09b48
        shutil.rmtree(docrepo)
Pierre-Yves Chibon a33978
        raise progit.exceptions.RepoExistsException(
Pierre-Yves Chibon a33978
            'The tickets repo "%s" already exists' % project.path
Pierre-Yves Chibon a33978
        )
Pierre-Yves Chibon b09b48
    pygit2.init_repository(ticketrepo, bare=True)
Pierre-Yves Chibon 6160b6
Pierre-Yves Chibon 652c2c
    return 'Repo "%s" cloned to "%s/%s"' % (repo.name, user, repo.name)
Pierre-Yves Chibon 652c2c
Pierre-Yves Chibon 652c2c
Pierre-Yves Chibon 7ece2d
def search_projects(
Pierre-Yves Chibon 7752a8
        session, username=None, fork=None,
Pierre-Yves Chibon ea0ee1
        start=None, limit=None, count=False):
Pierre-Yves Chibon 695ef6
    '''List existing projects
Pierre-Yves Chibon 695ef6
    '''
Pierre-Yves Chibon 0b9290
    projects = session.query(
Pierre-Yves Chibon 0b9290
        model.Project
Pierre-Yves Chibon 0b9290
    ).order_by(
Pierre-Yves Chibon 0b9290
        model.Project.date_created
Pierre-Yves Chibon 0b9290
    )
Mathieu Bridon eb729c
Pierre-Yves Chibon ea0ee1
    if username is not None:
Pierre-Yves Chibon e1372f
        projects = projects.filter(
Pierre-Yves Chibon e1372f
            model.User.user == username
Pierre-Yves Chibon e1372f
        ).filter(
Pierre-Yves Chibon e1372f
            model.User.id == model.Project.user_id
Pierre-Yves Chibon ea0ee1
        )
Pierre-Yves Chibon ea0ee1
Pierre-Yves Chibon 7752a8
    if fork is not None:
Pierre-Yves Chibon 7752a8
        if fork is True:
Pierre-Yves Chibon 7752a8
            projects = projects.filter(
Pierre-Yves Chibon 7752a8
                model.Project.parent_id != None
Pierre-Yves Chibon 7752a8
            )
Pierre-Yves Chibon 7752a8
        elif fork is False:
Pierre-Yves Chibon 2f8732
            projects = projects.filter(
Pierre-Yves Chibon 2f8732
                model.Project.parent_id == None
Pierre-Yves Chibon 7752a8
            )
Pierre-Yves Chibon 7752a8
Mathieu Bridon eb729c
    if start is not None:
Mathieu Bridon eb729c
        projects = projects.offset(start)
Mathieu Bridon eb729c
Mathieu Bridon eb729c
    if limit is not None:
Mathieu Bridon eb729c
        projects = projects.limit(limit)
Mathieu Bridon eb729c
Pierre-Yves Chibon f74093
    if count:
Pierre-Yves Chibon f74093
        return projects.count()
Pierre-Yves Chibon f74093
    else:
Pierre-Yves Chibon f74093
        return projects.all()
Mathieu Bridon eb729c
Mathieu Bridon 998605
Pierre-Yves Chibon 929595
def get_project(session, name, user=None):
Pierre-Yves Chibon 695ef6
    '''Get a project from the database
Pierre-Yves Chibon 695ef6
    '''
Pierre-Yves Chibon 929595
    query = session.query(
Pierre-Yves Chibon f74093
        model.Project
Pierre-Yves Chibon 178d6f
    ).filter(
Pierre-Yves Chibon 178d6f
        model.Project.name == name
Pierre-Yves Chibon 929595
    )
Pierre-Yves Chibon 1ac00b
Pierre-Yves Chibon 929595
    if user is not None:
Pierre-Yves Chibon 929595
        query = query.filter(
Pierre-Yves Chibon e1372f
            model.User.user == user
Pierre-Yves Chibon e1372f
        ).filter(
Pierre-Yves Chibon e1372f
            model.User.id == model.Project.user_id
Pierre-Yves Chibon 1ac00b
        ).filter(
Pierre-Yves Chibon 1ac00b
            model.Project.parent_id != None
Pierre-Yves Chibon 929595
        )
Pierre-Yves Chibon 1ac00b
    else:
Pierre-Yves Chibon 1ac00b
        query = query.filter(
Pierre-Yves Chibon 1ac00b
            model.Project.parent_id == None
Pierre-Yves Chibon 1ac00b
        )
Pierre-Yves Chibon 1ac00b
Pierre-Yves Chibon 929595
    return query.first()
Pierre-Yves Chibon 562d75
Pierre-Yves Chibon 562d75
Pierre-Yves Chibon 5ffcae
def search_issues(
Pierre-Yves Chibon 5b2947
        session, repo, issueid=None, status=None, closed=False, tags=None,
Pierre-Yves Chibon 02e68a
        assignee=None, author=None):
Pierre-Yves Chibon 5b2947
    ''' Retrieve one or more issues associated to a project with the given
Pierre-Yves Chibon 5b2947
    criterias.
Pierre-Yves Chibon b6df7d
Pierre-Yves Chibon b6df7d
    Watch out that the closed argument is incompatible with the status
Pierre-Yves Chibon b6df7d
    argument. The closed argument will return all the issues whose status
Pierre-Yves Chibon b6df7d
    is not 'Open', otherwise it will return the issues having the specified
Pierre-Yves Chibon b6df7d
    status.
Pierre-Yves Chibon bc60cc
    The `tags` argument can be used to filter the issues returned based on
Pierre-Yves Chibon bc60cc
    a certain tag.
Pierre-Yves Chibon 5b2947
    If the `issueid` argument is specified a single Issue object (or None)
Pierre-Yves Chibon 5b2947
    will be returned instead of a list of Issue objects.
Pierre-Yves Chibon 5b2947
Pierre-Yves Chibon 5b2947
    :arg session: the session to use to connect to the database.
Pierre-Yves Chibon 5b2947
    :arg repo: a Project object to which the issues should be associated
Pierre-Yves Chibon 5b2947
    :type repo: progit.lib.model.Project
Pierre-Yves Chibon 5b2947
    :kwarg issueid: the identifier of the issue to look for
Pierre-Yves Chibon 5b2947
    :type issueid: int or None
Pierre-Yves Chibon 5b2947
    :kwarg status: the status of the issue to look for (incompatible with
Pierre-Yves Chibon 5b2947
        the `closed` argument).
Pierre-Yves Chibon 5b2947
    :type status: str or None
Pierre-Yves Chibon 5b2947
    :kwarg closed: a boolean indicating whether the issue to retrieve are
Pierre-Yves Chibon 5b2947
        closed or open (incompatible with the `status` argument).
Pierre-Yves Chibon 5b2947
    :type closed: bool or None
Pierre-Yves Chibon 5b2947
    :kwarg tags: a tag the issue(s) returned should be associated with
Pierre-Yves Chibon 5b2947
    :type tags: str or list(str) or None
Pierre-Yves Chibon 5b2947
    :return: A single Issue object if issueid is specified, a list of Project
Pierre-Yves Chibon 5b2947
        objects otherwise.
Pierre-Yves Chibon 5b2947
    :rtype: Project or [Project]
Pierre-Yves Chibon bc60cc
Pierre-Yves Chibon 562d75
    '''
Pierre-Yves Chibon 562d75
    query = session.query(
Pierre-Yves Chibon 35a3e4
        model.Issue
Pierre-Yves Chibon 95f042
    ).filter(
Pierre-Yves Chibon 95f042
        model.Issue.project_id == repo.id
Pierre-Yves Chibon 3a2a1c
    ).order_by(
Pierre-Yves Chibon 3a2a1c
        model.Issue.id
Pierre-Yves Chibon 562d75
    )
Pierre-Yves Chibon 562d75
Pierre-Yves Chibon 5b2947
    if issueid is not None:
Pierre-Yves Chibon 5b2947
        query = query.filter(
Pierre-Yves Chibon 5b2947
            model.Issue.id == issueid
Pierre-Yves Chibon 5b2947
        )
Pierre-Yves Chibon 5b2947
Pierre-Yves Chibon b6df7d
    if status is not None and not closed:
Pierre-Yves Chibon 4d1cbe
        query = query.filter(
Pierre-Yves Chibon 4d1cbe
            model.Issue.status == status
Pierre-Yves Chibon 4d1cbe
        )
Pierre-Yves Chibon b6df7d
    if closed:
Pierre-Yves Chibon b6df7d
        query = query.filter(
Pierre-Yves Chibon b6df7d
            model.Issue.status != 'Open'
Pierre-Yves Chibon b6df7d
        )
Pierre-Yves Chibon d01150
    if tags is not None and tags != []:
Pierre-Yves Chibon 5b2947
        if isinstance(tags, basestring):
Pierre-Yves Chibon 5b2947
            tags = [tags]
Pierre-Yves Chibon 5b2947
Pierre-Yves Chibon bc60cc
        query = query.filter(
Pierre-Yves Chibon 9037dd
            model.Issue.uid == model.TagIssue.issue_uid
Pierre-Yves Chibon bc60cc
        ).filter(
Pierre-Yves Chibon bc60cc
            model.TagIssue.tag.in_(tags)
Pierre-Yves Chibon bc60cc
        )
Pierre-Yves Chibon a10ca7
    if assignee is not None:
Pierre-Yves Chibon ba4b04
        if str(assignee).lower() not in ['false', '0', 'true', '1']:
Pierre-Yves Chibon 685db8
            query = query.filter(
Pierre-Yves Chibon 685db8
                model.Issue.assignee_id == model.User.id
Pierre-Yves Chibon 685db8
            ).filter(
Pierre-Yves Chibon 685db8
                model.User.user == assignee
Pierre-Yves Chibon 685db8
            )
Pierre-Yves Chibon ba4b04
        elif str(assignee).lower() in ['true', '1']:
Pierre-Yves Chibon ba4b04
            query = query.filter(
Pierre-Yves Chibon ba4b04
                model.Issue.assignee_id != None
Pierre-Yves Chibon ba4b04
            )
Pierre-Yves Chibon 685db8
        else:
Pierre-Yves Chibon 685db8
            query = query.filter(
Pierre-Yves Chibon 685db8
                model.Issue.assignee_id == None
Pierre-Yves Chibon 685db8
            )
Pierre-Yves Chibon 02e68a
    if author is not None:
Pierre-Yves Chibon 02e68a
        query = query.filter(
Pierre-Yves Chibon 7407c0
            model.Issue.user_id == model.User.id
Pierre-Yves Chibon 7407c0
        ).filter(
Pierre-Yves Chibon 7407c0
            model.User.user == author
Pierre-Yves Chibon 7407c0
        )
Pierre-Yves Chibon 4d1cbe
Pierre-Yves Chibon 5b2947
    if issueid is not None:
Pierre-Yves Chibon 5b2947
        output = query.first()
Pierre-Yves Chibon 5b2947
    else:
Pierre-Yves Chibon 5b2947
        output = query.all()
Pierre-Yves Chibon 562d75
Pierre-Yves Chibon 5b2947
    return output
Pierre-Yves Chibon 562d75
Pierre-Yves Chibon 35112d
Pierre-Yves Chibon 64b484
def get_tags_of_project(session, project, pattern=None):
Pierre-Yves Chibon 8efc30
    ''' Returns the list of tags associated with the issues of a project.
Pierre-Yves Chibon 8efc30
    '''
Pierre-Yves Chibon 8efc30
    query = session.query(
Pierre-Yves Chibon 8efc30
        model.Tag
Pierre-Yves Chibon 8efc30
    ).filter(
Pierre-Yves Chibon 8efc30
        model.Tag.tag == model.TagIssue.tag
Pierre-Yves Chibon 8efc30
    ).filter(
Pierre-Yves Chibon 4aca3b
        model.TagIssue.issue_uid == model.Issue.uid
Pierre-Yves Chibon 8efc30
    ).filter(
Pierre-Yves Chibon 8efc30
        model.Issue.project_id == project.id
Pierre-Yves Chibon 8efc30
    ).order_by(
Pierre-Yves Chibon 8efc30
        model.Tag.tag
Pierre-Yves Chibon 8efc30
    )
Pierre-Yves Chibon 8efc30
Pierre-Yves Chibon 64b484
    if pattern:
Pierre-Yves Chibon 64b484
        query = query.filter(
Pierre-Yves Chibon 64b484
            model.Tag.tag.ilike(pattern.replace('*', '%'))
Pierre-Yves Chibon 64b484
        )
Pierre-Yves Chibon 64b484
Pierre-Yves Chibon 8efc30
    return query.all()
Pierre-Yves Chibon 8efc30
Pierre-Yves Chibon 8efc30
Pierre-Yves Chibon 2e810e
def get_tag(session, tag):
Pierre-Yves Chibon 2e810e
    ''' Returns a Tag object for the given tag text.
Pierre-Yves Chibon 2e810e
    '''
Pierre-Yves Chibon 2e810e
    query = session.query(
Pierre-Yves Chibon 2e810e
        model.Tag
Pierre-Yves Chibon 2e810e
    ).filter(
Pierre-Yves Chibon 2e810e
        model.Tag.tag == tag
Pierre-Yves Chibon 2e810e
    )
Pierre-Yves Chibon 2e810e
Pierre-Yves Chibon 2e810e
    return query.first()
Pierre-Yves Chibon 2e810e
Pierre-Yves Chibon 35112d
Pierre-Yves Chibon 08dd17
def search_pull_requests(
Pierre-Yves Chibon a2002e
        session, requestid=None, project_id=None, project_id_from=None,
Pierre-Yves Chibon a2002e
        status=None):
Pierre-Yves Chibon b0265c
    ''' Retrieve the specified issue
Pierre-Yves Chibon b0265c
    '''
Pierre-Yves Chibon 33e9fc
Pierre-Yves Chibon b0265c
    query = session.query(
Pierre-Yves Chibon 35a3e4
        model.PullRequest
Pierre-Yves Chibon 3a2a1c
    ).order_by(
Pierre-Yves Chibon 3a2a1c
        model.PullRequest.id
Pierre-Yves Chibon b0265c
    )
Pierre-Yves Chibon b0265c
Pierre-Yves Chibon a2002e
    if requestid:
Pierre-Yves Chibon a2002e
        query = query.filter(
Pierre-Yves Chibon a2002e
            model.PullRequest.id == requestid
Pierre-Yves Chibon a2002e
        )
Pierre-Yves Chibon a2002e
Pierre-Yves Chibon b0265c
    if project_id:
Pierre-Yves Chibon b0265c
        query = query.filter(
Pierre-Yves Chibon b0265c
            model.PullRequest.project_id == project_id
Pierre-Yves Chibon b0265c
        )
Pierre-Yves Chibon b0265c
Pierre-Yves Chibon b0265c
    if project_id_from:
Pierre-Yves Chibon b0265c
        query = query.filter(
Pierre-Yves Chibon b0265c
            model.PullRequest.project_id_from == project_id_from
Pierre-Yves Chibon b0265c
        )
Pierre-Yves Chibon b0265c
Pierre-Yves Chibon b0265c
    if status is not None:
Pierre-Yves Chibon b0265c
        query = query.filter(
Pierre-Yves Chibon b0265c
            model.PullRequest.status == status
Pierre-Yves Chibon b0265c
        )
Pierre-Yves Chibon b0265c
Pierre-Yves Chibon a2002e
    if requestid:
Pierre-Yves Chibon a2002e
        output = query.first()
Pierre-Yves Chibon a2002e
    else:
Pierre-Yves Chibon a2002e
        output = query.all()
Pierre-Yves Chibon 35112d
Pierre-Yves Chibon a2002e
    return output
Pierre-Yves Chibon 42a02c
Pierre-Yves Chibon 42a02c
Pierre-Yves Chibon 375fde
def close_pull_request(session, request, user, merged=True):
Pierre-Yves Chibon 42a02c
    ''' Close the provided pull-request.
Pierre-Yves Chibon 42a02c
    '''
Pierre-Yves Chibon 42a02c
    request.status = False
Pierre-Yves Chibon 42a02c
    session.add(request)
Pierre-Yves Chibon 42a02c
    session.flush()
Pierre-Yves Chibon 4d1cbe
Johan Cwiklinski 86d9c4
    if merged == True:
Pierre-Yves Chibon cbb18b
        progit.lib.notify.notify_merge_pull_request(request, user)
Johan Cwiklinski 86d9c4
    else:
Pierre-Yves Chibon cbb18b
        progit.lib.notify.notify_cancelled_pull_request(request, user)
Pierre-Yves Chibon 5fdf85
Pierre-Yves Chibon 4d1cbe
Pierre-Yves Chibon 4d1cbe
def get_issue_statuses(session):
Pierre-Yves Chibon 4d1cbe
    ''' Return the complete list of status an issue can have.
Pierre-Yves Chibon 4d1cbe
    '''
Pierre-Yves Chibon 4d1cbe
    output = []
Pierre-Yves Chibon 4d1cbe
    statuses = session.query(model.StatusIssue).all()
Pierre-Yves Chibon 4d1cbe
    for status in statuses:
Pierre-Yves Chibon 4d1cbe
        output.append(status.status)
Pierre-Yves Chibon 4d1cbe
    return output
Pierre-Yves Chibon 7c47d2
Pierre-Yves Chibon 7c47d2
Pierre-Yves Chibon c2aa0d
def set_up_user(session, username, fullname, user_email):
Pierre-Yves Chibon c2aa0d
    ''' Set up a new user into the database or update its information. '''
Pierre-Yves Chibon f05535
    user = search_user(session, username=username)
Pierre-Yves Chibon c2aa0d
    if not user:
Pierre-Yves Chibon c2aa0d
        user = model.User(
Pierre-Yves Chibon c2aa0d
            user=username,
Pierre-Yves Chibon c2aa0d
            fullname=fullname)
Pierre-Yves Chibon c2aa0d
        session.add(user)
Pierre-Yves Chibon c2aa0d
        session.flush()
Pierre-Yves Chibon c2aa0d
Pierre-Yves Chibon c2aa0d
    if user.fullname != fullname:
Pierre-Yves Chibon c2aa0d
        user.fullname = fullname
Pierre-Yves Chibon c2aa0d
        session.add(user)
Pierre-Yves Chibon c2aa0d
        session.flush()
Pierre-Yves Chibon c2aa0d
Pierre-Yves Chibon 8b2894
    emails = [email.email for email in user.emails]
Pierre-Yves Chibon 8b2894
    if user_email not in emails:
Pierre-Yves Chibon c2aa0d
        useremail = model.UserEmail(
Pierre-Yves Chibon c2aa0d
            user_id=user.id,
Pierre-Yves Chibon c2aa0d
            email=user_email)
Pierre-Yves Chibon c2aa0d
        session.add(useremail)
Pierre-Yves Chibon c2aa0d
        session.flush()
Pierre-Yves Chibon 8f25f2
Pierre-Yves Chibon 8f25f2
Pierre-Yves Chibon 8f25f2
def update_user_ssh(session, user, ssh_key):
Pierre-Yves Chibon 8f25f2
    ''' Set up a new user into the database or update its information. '''
Pierre-Yves Chibon 8f25f2
    if isinstance(user, basestring):
Pierre-Yves Chibon 60bea3
        user = __get_user(session, user)
Pierre-Yves Chibon 8f25f2
Pierre-Yves Chibon 8f25f2
    message = 'Nothing to update'
Pierre-Yves Chibon 8f25f2
Pierre-Yves Chibon 8f25f2
    if ssh_key != user.public_ssh_key:
Pierre-Yves Chibon 8f25f2
        user.public_ssh_key = ssh_key
Pierre-Yves Chibon 8f25f2
        session.add(user)
Pierre-Yves Chibon 8f25f2
        session.flush()
Pierre-Yves Chibon 8f25f2
        message = 'Public ssh key updated'
Pierre-Yves Chibon 8f25f2
Pierre-Yves Chibon 8f25f2
    return message
Pierre-Yves Chibon f7d963
Pierre-Yves Chibon f7d963
Pierre-Yves Chibon 95245b
def avatar_url(username, size=64, default='retro'):
Pierre-Yves Chibon 95245b
    openid = "http://%s.id.fedoraproject.org/" % username
Pierre-Yves Chibon 95245b
    return avatar_url_from_openid(openid, size, default)
Pierre-Yves Chibon 95245b
Pierre-Yves Chibon 95245b
Pierre-Yves Chibon 95245b
def avatar_url_from_openid(openid, size=64, default='retro', dns=False):
Pierre-Yves Chibon 95245b
    """
Pierre-Yves Chibon 95245b
    Our own implementation since fas doesn't support this nicely yet.
Pierre-Yves Chibon 95245b
    """
Pierre-Yves Chibon 95245b
Pierre-Yves Chibon 95245b
    if dns:  # pragma: no cover
Pierre-Yves Chibon 95245b
        # This makes an extra DNS SRV query, which can slow down our webapps.
Pierre-Yves Chibon 95245b
        # It is necessary for libravatar federation, though.
Pierre-Yves Chibon 95245b
        import libravatar
Pierre-Yves Chibon 95245b
        return libravatar.libravatar_url(
Pierre-Yves Chibon 95245b
            openid=openid,
Pierre-Yves Chibon 95245b
            size=size,
Pierre-Yves Chibon 95245b
            default=default,
Pierre-Yves Chibon 95245b
        )
Pierre-Yves Chibon 95245b
    else:
Pierre-Yves Chibon 7407c0
        import urllib
Pierre-Yves Chibon 7407c0
        import hashlib
Pierre-Yves Chibon 95245b
        query = urllib.urlencode({'s': size, 'd': default})
Pierre-Yves Chibon 95245b
        hash = hashlib.sha256(openid).hexdigest()
Pierre-Yves Chibon 95245b
        return "https://seccdn.libravatar.org/avatar/%s?%s" % (hash, query)