|
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)
|