Refactor bitbucket/github/gitlab hooks

remotes/origin/issue/4795/notification_even_they_are_disabled
Jesús Espino 2016-07-05 12:27:24 +02:00 committed by David Barragán Merino
parent 2a4cac4647
commit 5856ad6410
11 changed files with 1022 additions and 679 deletions

View File

@ -72,13 +72,5 @@ class BitBucketViewSet(BaseWebhookApiViewSet):
return project_secret == secret_key return project_secret == secret_key
def _get_project(self, request):
project_id = request.GET.get("project", None)
try:
project = Project.objects.get(id=project_id)
return project
except Project.DoesNotExist:
return None
def _get_event_name(self, request): def _get_event_name(self, request):
return request.META.get('HTTP_X_EVENT_KEY', None) return request.META.get('HTTP_X_EVENT_KEY', None)

View File

@ -18,181 +18,67 @@
import re import re
from django.utils.translation import ugettext as _ from taiga.hooks.event_hooks import BaseNewIssueEventHook, BaseIssueCommentEventHook, BasePushEventHook
from taiga.base import exceptions as exc
from taiga.projects.models import IssueStatus, TaskStatus, UserStoryStatus
from taiga.projects.issues.models import Issue
from taiga.projects.tasks.models import Task
from taiga.projects.userstories.models import UserStory
from taiga.projects.history.services import take_snapshot
from taiga.projects.notifications.services import send_notifications
from taiga.hooks.event_hooks import BaseEventHook
from taiga.hooks.exceptions import ActionSyntaxException
from taiga.base.utils import json
from .services import get_bitbucket_user
class PushEventHook(BaseEventHook): class BaseBitBucketEventHook():
def process_event(self): platform = "BitBucket"
if self.payload is None: platform_slug = "bitbucket"
return
def replace_bitbucket_references(self, project_url, wiki_text):
if wiki_text is None:
wiki_text = ""
template = "\g<1>[BitBucket#\g<2>]({}/issues/\g<2>)\g<3>".format(project_url)
return re.sub(r"(\s|^)#(\d+)(\s|$)", template, wiki_text, 0, re.M)
class IssuesEventHook(BaseBitBucketEventHook, BaseNewIssueEventHook):
def get_data(self):
description = self.payload.get('issue', {}).get('content', {}).get('raw', '')
project_url = self.payload.get('repository', {}).get('links', {}).get('html', {}).get('href', None)
return {
"number": self.payload.get('issue', {}).get('id', None),
"subject": self.payload.get('issue', {}).get('title', None),
"url": self.payload.get('issue', {}).get('links', {}).get('html', {}).get('href', None),
"user_id": self.payload.get('actor', {}).get('uuid', None),
"user_name": self.payload.get('actor', {}).get('username', None),
"user_url": self.payload.get('actor', {}).get('links', {}).get('html', {}).get('href'),
"description": self.replace_bitbucket_references(project_url, description),
}
class IssueCommentEventHook(BaseBitBucketEventHook, BaseIssueCommentEventHook):
def get_data(self):
comment_message = self.payload.get('comment', {}).get('content', {}).get('raw', '')
project_url = self.payload.get('repository', {}).get('links', {}).get('html', {}).get('href', None)
issue_url = self.payload.get('issue', {}).get('links', {}).get('html', {}).get('href', None)
comment_id = self.payload.get('comment', {}).get('id', None)
comment_url = "{}#comment-{}".format(issue_url, comment_id)
return {
"number": self.payload.get('issue', {}).get('id', None),
'url': issue_url,
'user_id': self.payload.get('actor', {}).get('uuid', None),
'user_name': self.payload.get('actor', {}).get('username', None),
'user_url': self.payload.get('actor', {}).get('links', {}).get('html', {}).get('href'),
'comment_url': comment_url,
'comment_message': self.replace_bitbucket_references(project_url, comment_message)
}
class PushEventHook(BaseBitBucketEventHook, BasePushEventHook):
def get_data(self):
result = []
changes = self.payload.get("push", {}).get('changes', []) changes = self.payload.get("push", {}).get('changes', [])
for change in filter(None, changes): for change in filter(None, changes):
commits = change.get("commits", []) for commit in change.get("commits", []):
if not commits: message = commit.get("message")
continue result.append({
'user_id': commit.get('author', {}).get('user', {}).get('uuid', None),
for commit in commits: "user_name": commit.get('author', {}).get('user', {}).get('username', None),
message = commit.get("message", None) "user_url": commit.get('author', {}).get('user', {}).get('links', {}).get('html', {}).get('href'),
if not message: "commit_id": commit.get("hash", None),
continue "commit_url": commit.get("links", {}).get('html', {}).get('href'),
"commit_message": message.strip(),
self._process_message(message, None) })
return result
def _process_message(self, message, bitbucket_user):
"""
The message we will be looking for seems like
TG-XX #yyyyyy
Where:
XX: is the ref for us, issue or task
yyyyyy: is the status slug we are setting
"""
if message is None:
return
p = re.compile("tg-(\d+) +#([-\w]+)")
for m in p.finditer(message.lower()):
ref = m.group(1)
status_slug = m.group(2)
self._change_status(ref, status_slug, bitbucket_user)
def _change_status(self, ref, status_slug, bitbucket_user):
if Issue.objects.filter(project=self.project, ref=ref).exists():
modelClass = Issue
statusClass = IssueStatus
elif Task.objects.filter(project=self.project, ref=ref).exists():
modelClass = Task
statusClass = TaskStatus
elif UserStory.objects.filter(project=self.project, ref=ref).exists():
modelClass = UserStory
statusClass = UserStoryStatus
else:
raise ActionSyntaxException(_("The referenced element doesn't exist"))
element = modelClass.objects.get(project=self.project, ref=ref)
try:
status = statusClass.objects.get(project=self.project, slug=status_slug)
except statusClass.DoesNotExist:
raise ActionSyntaxException(_("The status doesn't exist"))
element.status = status
element.save()
snapshot = take_snapshot(element,
comment=_("Status changed from BitBucket commit"),
user=get_bitbucket_user(bitbucket_user))
send_notifications(element, history=snapshot)
def replace_bitbucket_references(project_url, wiki_text):
template = "\g<1>[BitBucket#\g<2>]({}/issues/\g<2>)\g<3>".format(project_url)
return re.sub(r"(\s|^)#(\d+)(\s|$)", template, wiki_text, 0, re.M)
class IssuesEventHook(BaseEventHook):
def process_event(self):
number = self.payload.get('issue', {}).get('id', None)
subject = self.payload.get('issue', {}).get('title', None)
bitbucket_url = self.payload.get('issue', {}).get('links', {}).get('html', {}).get('href', None)
bitbucket_user_id = self.payload.get('actor', {}).get('user', {}).get('uuid', None)
bitbucket_user_name = self.payload.get('actor', {}).get('user', {}).get('username', None)
bitbucket_user_url = self.payload.get('actor', {}).get('user', {}).get('links', {}).get('html', {}).get('href')
project_url = self.payload.get('repository', {}).get('links', {}).get('html', {}).get('href', None)
description = self.payload.get('issue', {}).get('content', {}).get('raw', '')
description = replace_bitbucket_references(project_url, description)
user = get_bitbucket_user(bitbucket_user_id)
if not all([subject, bitbucket_url, project_url]):
raise ActionSyntaxException(_("Invalid issue information"))
issue = Issue.objects.create(
project=self.project,
subject=subject,
description=description,
status=self.project.default_issue_status,
type=self.project.default_issue_type,
severity=self.project.default_severity,
priority=self.project.default_priority,
external_reference=['bitbucket', bitbucket_url],
owner=user
)
take_snapshot(issue, user=user)
if number and subject and bitbucket_user_name and bitbucket_user_url:
comment = _("Issue created by [@{bitbucket_user_name}]({bitbucket_user_url} "
"\"See @{bitbucket_user_name}'s BitBucket profile\") "
"from BitBucket.\nOrigin BitBucket issue: [bb#{number} - {subject}]({bitbucket_url} "
"\"Go to 'bb#{number} - {subject}'\"):\n\n"
"{description}").format(bitbucket_user_name=bitbucket_user_name,
bitbucket_user_url=bitbucket_user_url,
number=number,
subject=subject,
bitbucket_url=bitbucket_url,
description=description)
else:
comment = _("Issue created from BitBucket.")
snapshot = take_snapshot(issue, comment=comment, user=user)
send_notifications(issue, history=snapshot)
class IssueCommentEventHook(BaseEventHook):
def process_event(self):
number = self.payload.get('issue', {}).get('id', None)
subject = self.payload.get('issue', {}).get('title', None)
bitbucket_url = self.payload.get('issue', {}).get('links', {}).get('html', {}).get('href', None)
bitbucket_user_id = self.payload.get('actor', {}).get('user', {}).get('uuid', None)
bitbucket_user_name = self.payload.get('actor', {}).get('user', {}).get('username', None)
bitbucket_user_url = self.payload.get('actor', {}).get('user', {}).get('links', {}).get('html', {}).get('href')
project_url = self.payload.get('repository', {}).get('links', {}).get('html', {}).get('href', None)
comment_message = self.payload.get('comment', {}).get('content', {}).get('raw', '')
comment_message = replace_bitbucket_references(project_url, comment_message)
user = get_bitbucket_user(bitbucket_user_id)
if not all([comment_message, bitbucket_url, project_url]):
raise ActionSyntaxException(_("Invalid issue comment information"))
issues = Issue.objects.filter(external_reference=["bitbucket", bitbucket_url])
tasks = Task.objects.filter(external_reference=["bitbucket", bitbucket_url])
uss = UserStory.objects.filter(external_reference=["bitbucket", bitbucket_url])
for item in list(issues) + list(tasks) + list(uss):
if number and subject and bitbucket_user_name and bitbucket_user_url:
comment = _("Comment by [@{bitbucket_user_name}]({bitbucket_user_url} "
"\"See @{bitbucket_user_name}'s BitBucket profile\") "
"from BitBucket.\nOrigin BitBucket issue: [bb#{number} - {subject}]({bitbucket_url} "
"\"Go to 'bb#{number} - {subject}'\")\n\n"
"{message}").format(bitbucket_user_name=bitbucket_user_name,
bitbucket_user_url=bitbucket_user_url,
number=number,
subject=subject,
bitbucket_url=bitbucket_url,
message=comment_message)
else:
comment = _("Comment From BitBucket:\n\n{message}").format(message=comment_message)
snapshot = take_snapshot(item, comment=comment, user=user)
send_notifications(item, history=snapshot)

View File

@ -16,11 +16,247 @@
# You should have received a copy of the GNU Affero General Public License # You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>. # along with this program. If not, see <http://www.gnu.org/licenses/>.
import re
from django.utils.translation import ugettext as _
from django.contrib.auth import get_user_model
from taiga.projects.models import IssueStatus, TaskStatus, UserStoryStatus
from taiga.projects.issues.models import Issue
from taiga.projects.tasks.models import Task
from taiga.projects.userstories.models import UserStory
from taiga.projects.history.services import take_snapshot
from taiga.projects.notifications.services import send_notifications
from taiga.hooks.exceptions import ActionSyntaxException
from taiga.users.models import AuthData
class BaseEventHook: class BaseEventHook:
platform = "Unknown"
platform_slug = "unknown"
def __init__(self, project, payload): def __init__(self, project, payload):
self.project = project self.project = project
self.payload = payload self.payload = payload
def ignore(self):
return False
def get_user(self, user_id, platform):
user = None
if user_id:
try:
user = AuthData.objects.get(key=platform, value=user_id).user
except AuthData.DoesNotExist:
pass
if user is None:
user = get_user_model().objects.get(is_system=True, username__startswith=platform)
return user
class BaseIssueCommentEventHook(BaseEventHook):
def get_data(self):
raise NotImplementedError
def generate_issue_comment_message(self, **kwargs):
_issue_comment_message = _(
"[@{user_name}]({user_url} "
"\"See @{user_name}'s {platform} profile\") "
"says in [{platform}#{number}]({comment_url} \"Go to comment\"):\n\n"
"\"{comment_message}\""
)
_simple_issue_comment_message = _("Comment From {platform}:\n\n> {comment_message}")
try:
return _issue_comment_message.format(platform=self.platform, **kwargs)
except Exception:
return _simple_issue_comment_message.format(platform=self.platform, message=kwargs.get('comment_message'))
def process_event(self): def process_event(self):
raise NotImplementedError("process_event must be overwritten") if self.ignore():
return
data = self.get_data()
if not all([data['comment_message'], data['url']]):
raise ActionSyntaxException(_("Invalid issue comment information"))
comment = self.generate_issue_comment_message(**data)
issues = Issue.objects.filter(external_reference=[self.platform_slug, data['url']])
tasks = Task.objects.filter(external_reference=[self.platform_slug, data['url']])
uss = UserStory.objects.filter(external_reference=[self.platform_slug, data['url']])
for item in list(issues) + list(tasks) + list(uss):
snapshot = take_snapshot(item, comment=comment, user=self.get_user(data['user_id'], self.platform_slug))
send_notifications(item, history=snapshot)
class BaseNewIssueEventHook(BaseEventHook):
def get_data(self):
raise NotImplementedError
def generate_new_issue_comment(self, **kwargs):
_new_issue_message = _(
"Issue created by [@{user_name}]({user_url} "
"\"See @{user_name}'s {platform} profile\") "
"from [{platform}#{number}]({url} \"Go to issue\")."
)
_simple_new_issue_message = _("Issue created from {platform}.")
try:
return _new_issue_message.format(platform=self.platform, **kwargs)
except Exception:
return _simple_new_issue_message.format(platform=self.platform)
def process_event(self):
if self.ignore():
return
data = self.get_data()
if not all([data['subject'], data['url']]):
raise ActionSyntaxException(_("Invalid issue information"))
user = self.get_user(data['user_id'], self.platform_slug)
issue = Issue.objects.create(
project=self.project,
subject=data['subject'],
description=data['description'],
status=self.project.default_issue_status,
type=self.project.default_issue_type,
severity=self.project.default_severity,
priority=self.project.default_priority,
external_reference=[self.platform_slug, data['url']],
owner=user
)
take_snapshot(issue, user=user)
comment = self.generate_new_issue_comment(**data)
snapshot = take_snapshot(issue, comment=comment, user=user)
send_notifications(issue, history=snapshot)
class BasePushEventHook(BaseEventHook):
def get_data(self):
raise NotImplementedError
def generate_status_change_comment(self, **kwargs):
if kwargs.get('user_url', None) is None:
user_text = kwargs.get('user_name', _('unknown user'))
else:
user_text = "[@{user_name}]({user_url} \"See @{user_name}'s {platform} profile\")".format(
platform=self.platform,
**kwargs
)
_status_change_message = _(
"{user_text} changed the status from "
"[{platform} commit]({commit_url} \"See commit '{commit_id} - {commit_message}'\")\n\n"
" - Status: **{src_status}** → **{dst_status}**"
)
_simple_status_change_message = _(
"Changed status from {platform} commit.\n\n"
" - Status: **{src_status}** → **{dst_status}**"
)
try:
return _status_change_message.format(platform=self.platform, user_text=user_text, **kwargs)
except Exception:
return _simple_status_change_message.format(platform=self.platform)
def generate_commit_reference_comment(self, **kwargs):
if kwargs.get('user_url', None) is None:
user_text = kwargs.get('user_name', _('unknown user'))
else:
user_text = "[@{user_name}]({user_url} \"See @{user_name}'s {platform} profile\")".format(
platform=self.platform,
**kwargs
)
_status_change_message = _(
"This {type_name} has been mentioned by {user_text} "
"in the [{platform} commit]({commit_url} \"See commit '{commit_id} - {commit_message}'\") "
"\"{commit_message}\""
)
_simple_status_change_message = _(
"This issue has been mentioned in the {platform} commit "
"\"{commit_message}\""
)
try:
return _status_change_message.format(platform=self.platform, user_text=user_text, **kwargs)
except Exception:
return _simple_status_change_message.format(platform=self.platform)
def get_item_classes(self, ref):
if Issue.objects.filter(project=self.project, ref=ref).exists():
modelClass = Issue
statusClass = IssueStatus
elif Task.objects.filter(project=self.project, ref=ref).exists():
modelClass = Task
statusClass = TaskStatus
elif UserStory.objects.filter(project=self.project, ref=ref).exists():
modelClass = UserStory
statusClass = UserStoryStatus
else:
raise ActionSyntaxException(_("The referenced element doesn't exist"))
return (modelClass, statusClass)
def get_item_by_ref(self, ref):
(modelClass, statusClass) = self.get_item_classes(ref)
return modelClass.objects.get(project=self.project, ref=ref)
def set_item_status(self, ref, status_slug):
(modelClass, statusClass) = self.get_item_classes(ref)
element = modelClass.objects.get(project=self.project, ref=ref)
try:
status = statusClass.objects.get(project=self.project, slug=status_slug)
except statusClass.DoesNotExist:
raise ActionSyntaxException(_("The status doesn't exist"))
src_status = element.status.name
dst_status = status.name
element.status = status
element.save()
return (element, src_status, dst_status)
def process_event(self):
if self.ignore():
return
data = self.get_data()
for commit in data:
consumed_refs = []
# Status changes
p = re.compile("tg-(\d+) +#([-\w]+)")
for m in p.finditer(commit['commit_message'].lower()):
ref = m.group(1)
status_slug = m.group(2)
(element, src_status, dst_status) = self.set_item_status(ref, status_slug)
comment = self.generate_status_change_comment(src_status=src_status, dst_status=dst_status, **commit)
snapshot = take_snapshot(element,
comment=comment,
user=self.get_user(commit['user_id'], self.platform_slug))
send_notifications(element, history=snapshot)
consumed_refs.append(ref)
# Reference on commit
p = re.compile("tg-(\d+)")
for m in p.finditer(commit['commit_message'].lower()):
ref = m.group(1)
if ref in consumed_refs:
continue
element = self.get_item_by_ref(ref)
type_name = element.__class__._meta.verbose_name
comment = self.generate_commit_reference_comment(type_name=type_name, **commit)
snapshot = take_snapshot(element,
comment=comment,
user=self.get_user(commit['user_id'], self.platform_slug))
send_notifications(element, history=snapshot)
consumed_refs.append(ref)

View File

@ -16,201 +16,72 @@
# You should have received a copy of the GNU Affero General Public License # You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>. # along with this program. If not, see <http://www.gnu.org/licenses/>.
from django.utils.translation import ugettext as _
from taiga.projects.models import IssueStatus, TaskStatus, UserStoryStatus
from taiga.projects.issues.models import Issue
from taiga.projects.tasks.models import Task
from taiga.projects.userstories.models import UserStory
from taiga.projects.history.services import take_snapshot
from taiga.projects.notifications.services import send_notifications
from taiga.hooks.event_hooks import BaseEventHook
from taiga.hooks.exceptions import ActionSyntaxException
from .services import get_github_user
import re import re
from taiga.hooks.event_hooks import BaseNewIssueEventHook, BaseIssueCommentEventHook, BasePushEventHook
class PushEventHook(BaseEventHook):
def process_event(self):
if self.payload is None:
return
github_user = self.payload.get('sender', {})
commits = self.payload.get("commits", [])
for commit in commits:
self._process_commit(commit, github_user)
def _process_commit(self, commit, github_user):
"""
The message we will be looking for seems like
TG-XX #yyyyyy
Where:
XX: is the ref for us, issue or task
yyyyyy: is the status slug we are setting
"""
message = commit.get("message", None)
if message is None:
return
p = re.compile("tg-(\d+) +#([-\w]+)")
for m in p.finditer(message.lower()):
ref = m.group(1)
status_slug = m.group(2)
self._change_status(ref, status_slug, github_user, commit)
def _change_status(self, ref, status_slug, github_user, commit):
if Issue.objects.filter(project=self.project, ref=ref).exists():
modelClass = Issue
statusClass = IssueStatus
elif Task.objects.filter(project=self.project, ref=ref).exists():
modelClass = Task
statusClass = TaskStatus
elif UserStory.objects.filter(project=self.project, ref=ref).exists():
modelClass = UserStory
statusClass = UserStoryStatus
else:
raise ActionSyntaxException(_("The referenced element doesn't exist"))
element = modelClass.objects.get(project=self.project, ref=ref)
try:
status = statusClass.objects.get(project=self.project, slug=status_slug)
except statusClass.DoesNotExist:
raise ActionSyntaxException(_("The status doesn't exist"))
element.status = status
element.save()
github_user_id = github_user.get('id', None)
github_user_name = github_user.get('login', None)
github_user_url = github_user.get('html_url', None)
commit_id = commit.get("id", None)
commit_url = commit.get("url", None)
commit_message = commit.get("message", None)
if (github_user_id and github_user_name and github_user_url and
commit_id and commit_url and commit_message):
comment = _("Status changed by [@{github_user_name}]({github_user_url} "
"\"See @{github_user_name}'s GitHub profile\") "
"from GitHub commit [{commit_id}]({commit_url} "
"\"See commit '{commit_id} - {commit_message}'\").").format(
github_user_name=github_user_name,
github_user_url=github_user_url,
commit_id=commit_id[:7],
commit_url=commit_url,
commit_message=commit_message)
else:
comment = _("Status changed from GitHub commit.")
snapshot = take_snapshot(element,
comment=comment,
user=get_github_user(github_user_id))
send_notifications(element, history=snapshot)
def replace_github_references(project_url, wiki_text): class BaseGitHubEventHook():
if wiki_text == None: platform = "GitHub"
wiki_text = "" platform_slug = "github"
template = "\g<1>[GitHub#\g<2>]({}/issues/\g<2>)\g<3>".format(project_url) def replace_github_references(self, project_url, wiki_text):
return re.sub(r"(\s|^)#(\d+)(\s|$)", template, wiki_text, 0, re.M) if wiki_text is None:
wiki_text = ""
template = "\g<1>[GitHub#\g<2>]({}/issues/\g<2>)\g<3>".format(project_url)
return re.sub(r"(\s|^)#(\d+)(\s|$)", template, wiki_text, 0, re.M)
class IssuesEventHook(BaseEventHook): class IssuesEventHook(BaseGitHubEventHook, BaseNewIssueEventHook):
def process_event(self): def ignore(self):
if self.payload.get('action', None) != "opened": return self.payload.get('action', None) != "opened"
return
number = self.payload.get('issue', {}).get('number', None) def get_data(self):
subject = self.payload.get('issue', {}).get('title', None)
github_url = self.payload.get('issue', {}).get('html_url', None)
github_user_id = self.payload.get('issue', {}).get('user', {}).get('id', None)
github_user_name = self.payload.get('issue', {}).get('user', {}).get('login', None)
github_user_url = self.payload.get('issue', {}).get('user', {}).get('html_url', None)
project_url = self.payload.get('repository', {}).get('html_url', None)
description = self.payload.get('issue', {}).get('body', None) description = self.payload.get('issue', {}).get('body', None)
description = replace_github_references(project_url, description)
user = get_github_user(github_user_id)
if not all([subject, github_url, project_url]):
raise ActionSyntaxException(_("Invalid issue information"))
issue = Issue.objects.create(
project=self.project,
subject=subject,
description=description,
status=self.project.default_issue_status,
type=self.project.default_issue_type,
severity=self.project.default_severity,
priority=self.project.default_priority,
external_reference=['github', github_url],
owner=user
)
take_snapshot(issue, user=user)
if number and subject and github_user_name and github_user_url:
comment = _("Issue created by [@{github_user_name}]({github_user_url} "
"\"See @{github_user_name}'s GitHub profile\") "
"from GitHub.\nOrigin GitHub issue: [gh#{number} - {subject}]({github_url} "
"\"Go to 'gh#{number} - {subject}'\"):\n\n"
"{description}").format(github_user_name=github_user_name,
github_user_url=github_user_url,
number=number,
subject=subject,
github_url=github_url,
description=description)
else:
comment = _("Issue created from GitHub.")
snapshot = take_snapshot(issue, comment=comment, user=user)
send_notifications(issue, history=snapshot)
class IssueCommentEventHook(BaseEventHook):
def process_event(self):
if self.payload.get('action', None) != "created":
raise ActionSyntaxException(_("Invalid issue comment information"))
number = self.payload.get('issue', {}).get('number', None)
subject = self.payload.get('issue', {}).get('title', None)
github_url = self.payload.get('issue', {}).get('html_url', None)
github_user_id = self.payload.get('sender', {}).get('id', None)
github_user_name = self.payload.get('sender', {}).get('login', None)
github_user_url = self.payload.get('sender', {}).get('html_url', None)
project_url = self.payload.get('repository', {}).get('html_url', None) project_url = self.payload.get('repository', {}).get('html_url', None)
return {
"number": self.payload.get('issue', {}).get('number', None),
"subject": self.payload.get('issue', {}).get('title', None),
"url": self.payload.get('issue', {}).get('html_url', None),
"user_id": self.payload.get('issue', {}).get('user', {}).get('id', None),
"user_name": self.payload.get('issue', {}).get('user', {}).get('login', None),
"user_url": self.payload.get('issue', {}).get('user', {}).get('html_url', None),
"description": self.replace_github_references(project_url, description),
}
class IssueCommentEventHook(BaseGitHubEventHook, BaseIssueCommentEventHook):
def ignore(self):
return self.payload.get('action', None) != "created"
def get_data(self):
comment_message = self.payload.get('comment', {}).get('body', None) comment_message = self.payload.get('comment', {}).get('body', None)
comment_message = replace_github_references(project_url, comment_message) project_url = self.payload.get('repository', {}).get('html_url', None)
return {
"number": self.payload.get('issue', {}).get('number', None),
"url": self.payload.get('issue', {}).get('html_url', None),
"user_id": self.payload.get('sender', {}).get('id', None),
"user_name": self.payload.get('sender', {}).get('login', None),
"user_url": self.payload.get('sender', {}).get('html_url', None),
"comment_url": self.payload.get('comment', {}).get('html_url', None),
"comment_message": self.replace_github_references(project_url, comment_message),
}
user = get_github_user(github_user_id)
if not all([comment_message, github_url, project_url]): class PushEventHook(BaseGitHubEventHook, BasePushEventHook):
raise ActionSyntaxException(_("Invalid issue comment information")) def get_data(self):
result = []
github_user = self.payload.get('sender', {})
commits = self.payload.get("commits", [])
for commit in filter(None, commits):
result.append({
"user_id": github_user.get('id', None),
"user_name": github_user.get('login', None),
"user_url": github_user.get('html_url', None),
"commit_id": commit.get("id", None),
"commit_url": commit.get("url", None),
"commit_message": commit.get("message", None),
})
issues = Issue.objects.filter(external_reference=["github", github_url]) return result
tasks = Task.objects.filter(external_reference=["github", github_url])
uss = UserStory.objects.filter(external_reference=["github", github_url])
for item in list(issues) + list(tasks) + list(uss):
if number and subject and github_user_name and github_user_url:
comment = _("Comment by [@{github_user_name}]({github_user_url} "
"\"See @{github_user_name}'s GitHub profile\") "
"from GitHub.\nOrigin GitHub issue: [gh#{number} - {subject}]({github_url} "
"\"Go to 'gh#{number} - {subject}'\")\n\n"
"{message}").format(github_user_name=github_user_name,
github_user_url=github_user_url,
number=number,
subject=subject,
github_url=github_url,
message=comment_message)
else:
comment = _("Comment From GitHub:\n\n{message}").format(message=comment_message)
snapshot = take_snapshot(item, comment=comment, user=user)
send_notifications(item, history=snapshot)

View File

@ -18,10 +18,8 @@
import uuid import uuid
from django.contrib.auth import get_user_model
from django.core.urlresolvers import reverse from django.core.urlresolvers import reverse
from taiga.users.models import AuthData
from taiga.base.utils.urls import get_absolute_url from taiga.base.utils.urls import get_absolute_url
@ -38,18 +36,3 @@ def get_or_generate_config(project):
url = "%s?project=%s" % (url, project.id) url = "%s?project=%s" % (url, project.id)
g_config["webhooks_url"] = url g_config["webhooks_url"] = url
return g_config return g_config
def get_github_user(github_id):
user = None
if github_id:
try:
user = AuthData.objects.get(key="github", value=github_id).user
except AuthData.DoesNotExist:
pass
if user is None:
user = get_user_model().objects.get(is_system=True, username__startswith="github")
return user

View File

@ -70,14 +70,6 @@ class GitLabViewSet(BaseWebhookApiViewSet):
return project_secret == secret_key return project_secret == secret_key
def _get_project(self, request):
project_id = request.GET.get("project", None)
try:
project = Project.objects.get(id=project_id)
return project
except Project.DoesNotExist:
return None
def _get_event_name(self, request): def _get_event_name(self, request):
payload = json.loads(request.body.decode("utf-8")) payload = json.loads(request.body.decode("utf-8"))
return payload.get('object_kind', 'push') if payload is not None else 'empty' return payload.get('object_kind', 'push') if payload is not None else 'empty'

View File

@ -19,158 +19,71 @@
import re import re
import os import os
from django.utils.translation import ugettext as _ from taiga.hooks.event_hooks import BaseNewIssueEventHook, BaseIssueCommentEventHook, BasePushEventHook
from taiga.projects.models import IssueStatus, TaskStatus, UserStoryStatus
from taiga.projects.issues.models import Issue
from taiga.projects.tasks.models import Task
from taiga.projects.userstories.models import UserStory
from taiga.projects.history.services import take_snapshot
from taiga.projects.notifications.services import send_notifications
from taiga.hooks.event_hooks import BaseEventHook
from taiga.hooks.exceptions import ActionSyntaxException
from .services import get_gitlab_user
class PushEventHook(BaseEventHook): class BaseGitLabEventHook():
def process_event(self): platform = "GitLab"
if self.payload is None: platform_slug = "gitlab"
return
commits = self.payload.get("commits", []) def replace_gitlab_references(self, project_url, wiki_text):
for commit in commits: if wiki_text is None:
message = commit.get("message", None) wiki_text = ""
self._process_message(message, None)
def _process_message(self, message, gitlab_user): template = "\g<1>[GitLab#\g<2>]({}/issues/\g<2>)\g<3>".format(project_url)
""" return re.sub(r"(\s|^)#(\d+)(\s|$)", template, wiki_text, 0, re.M)
The message we will be looking for seems like
TG-XX #yyyyyy
Where:
XX: is the ref for us, issue or task
yyyyyy: is the status slug we are setting
"""
if message is None:
return
p = re.compile("tg-(\d+) +#([-\w]+)")
for m in p.finditer(message.lower()):
ref = m.group(1)
status_slug = m.group(2)
self._change_status(ref, status_slug, gitlab_user)
def _change_status(self, ref, status_slug, gitlab_user):
if Issue.objects.filter(project=self.project, ref=ref).exists():
modelClass = Issue
statusClass = IssueStatus
elif Task.objects.filter(project=self.project, ref=ref).exists():
modelClass = Task
statusClass = TaskStatus
elif UserStory.objects.filter(project=self.project, ref=ref).exists():
modelClass = UserStory
statusClass = UserStoryStatus
else:
raise ActionSyntaxException(_("The referenced element doesn't exist"))
element = modelClass.objects.get(project=self.project, ref=ref)
try:
status = statusClass.objects.get(project=self.project, slug=status_slug)
except statusClass.DoesNotExist:
raise ActionSyntaxException(_("The status doesn't exist"))
element.status = status
element.save()
snapshot = take_snapshot(element,
comment=_("Status changed from GitLab commit"),
user=get_gitlab_user(gitlab_user))
send_notifications(element, history=snapshot)
def replace_gitlab_references(project_url, wiki_text): class IssuesEventHook(BaseGitLabEventHook, BaseNewIssueEventHook):
if wiki_text is None: def ignore(self):
wiki_text = "" return self.payload.get('object_attributes', {}).get("action", "") != "open"
template = "\g<1>[GitLab#\g<2>]({}/issues/\g<2>)\g<3>".format(project_url) def get_data(self):
return re.sub(r"(\s|^)#(\d+)(\s|$)", template, wiki_text, 0, re.M)
class IssuesEventHook(BaseEventHook):
def process_event(self):
if self.payload.get('object_attributes', {}).get("action", "") != "open":
return
subject = self.payload.get('object_attributes', {}).get('title', None)
description = self.payload.get('object_attributes', {}).get('description', None) description = self.payload.get('object_attributes', {}).get('description', None)
gitlab_reference = self.payload.get('object_attributes', {}).get('url', None)
project_url = None
if gitlab_reference:
project_url = os.path.basename(os.path.basename(gitlab_reference))
if not all([subject, gitlab_reference, project_url]):
raise ActionSyntaxException(_("Invalid issue information"))
issue = Issue.objects.create(
project=self.project,
subject=subject,
description=replace_gitlab_references(project_url, description),
status=self.project.default_issue_status,
type=self.project.default_issue_type,
severity=self.project.default_severity,
priority=self.project.default_priority,
external_reference=['gitlab', gitlab_reference],
owner=get_gitlab_user(None)
)
take_snapshot(issue, user=get_gitlab_user(None))
snapshot = take_snapshot(issue, comment=_("Created from GitLab"), user=get_gitlab_user(None))
send_notifications(issue, history=snapshot)
class IssueCommentEventHook(BaseEventHook):
def process_event(self):
if self.payload.get('object_attributes', {}).get("noteable_type", None) != "Issue":
return
number = self.payload.get('issue', {}).get('iid', None)
subject = self.payload.get('issue', {}).get('title', None)
project_url = self.payload.get('repository', {}).get('homepage', None) project_url = self.payload.get('repository', {}).get('homepage', None)
user_name = self.payload.get('user', {}).get('username', None)
return {
"number": self.payload.get('object_attributes', {}).get('iid', None),
"subject": self.payload.get('object_attributes', {}).get('title', None),
"url": self.payload.get('object_attributes', {}).get('url', None),
"user_id": None,
"user_name": user_name,
"user_url": os.path.join(os.path.dirname(os.path.dirname(project_url)), "u", user_name),
"description": self.replace_gitlab_references(project_url, description),
}
gitlab_url = os.path.join(project_url, "issues", str(number))
gitlab_user_name = self.payload.get('user', {}).get('username', None)
gitlab_user_url = os.path.join(os.path.dirname(os.path.dirname(project_url)), "u", gitlab_user_name)
class IssueCommentEventHook(BaseGitLabEventHook, BaseIssueCommentEventHook):
def ignore(self):
return self.payload.get('object_attributes', {}).get("noteable_type", None) != "Issue"
def get_data(self):
comment_message = self.payload.get('object_attributes', {}).get('note', None) comment_message = self.payload.get('object_attributes', {}).get('note', None)
comment_message = replace_gitlab_references(project_url, comment_message) project_url = self.payload.get('repository', {}).get('homepage', None)
number = self.payload.get('issue', {}).get('iid', None)
user_name = self.payload.get('user', {}).get('username', None)
return {
"number": number,
"url": os.path.join(project_url, "issues", str(number)),
"user_id": None,
"user_name": user_name,
"user_url": os.path.join(os.path.dirname(os.path.dirname(project_url)), "u", user_name),
"comment_url": self.payload.get('object_attributes', {}).get('url', None),
"comment_message": self.replace_gitlab_references(project_url, comment_message),
}
user = get_gitlab_user(None)
if not all([comment_message, gitlab_url, project_url]): class PushEventHook(BaseGitLabEventHook, BasePushEventHook):
raise ActionSyntaxException(_("Invalid issue comment information")) def get_data(self):
result = []
issues = Issue.objects.filter(external_reference=["gitlab", gitlab_url]) for commit in self.payload.get("commits", []):
tasks = Task.objects.filter(external_reference=["gitlab", gitlab_url]) user_name = commit.get('author', {}).get('name', None)
uss = UserStory.objects.filter(external_reference=["gitlab", gitlab_url]) result.append({
"user_id": None,
for item in list(issues) + list(tasks) + list(uss): "user_name": user_name,
if number and subject and gitlab_user_name and gitlab_user_url: "user_url": None,
comment = _("Comment by [@{gitlab_user_name}]({gitlab_user_url} " "commit_id": commit.get("id", None),
"\"See @{gitlab_user_name}'s GitLab profile\") " "commit_url": commit.get("url", None),
"from GitLab.\nOrigin GitLab issue: [gl#{number} - {subject}]({gitlab_url} " "commit_message": commit.get("message").strip(),
"\"Go to 'gl#{number} - {subject}'\")\n\n" })
"{message}").format(gitlab_user_name=gitlab_user_name, return result
gitlab_user_url=gitlab_user_url,
number=number,
subject=subject,
gitlab_url=gitlab_url,
message=comment_message)
else:
comment = _("Comment From GitLab:\n\n{message}").format(message=comment_message)
snapshot = take_snapshot(item, comment=comment, user=user)
send_notifications(item, history=snapshot)

View File

@ -18,7 +18,6 @@
import uuid import uuid
from django.contrib.auth import get_user_model
from django.core.urlresolvers import reverse from django.core.urlresolvers import reverse
from django.conf import settings from django.conf import settings
@ -41,18 +40,3 @@ def get_or_generate_config(project):
url = "{}?project={}&key={}".format(url, project.id, g_config["secret"]) url = "{}?project={}&key={}".format(url, project.id, g_config["secret"])
g_config["webhooks_url"] = url g_config["webhooks_url"] = url
return g_config return g_config
def get_gitlab_user(user_email):
user = None
if user_email:
try:
user = get_user_model().objects.get(email=user_email)
except get_user_model().DoesNotExist:
pass
if user is None:
user = get_user_model().objects.get(is_system=True, username__startswith="gitlab")
return user

View File

@ -246,6 +246,13 @@ def test_push_event_issue_processing(client):
new_status = f.IssueStatusFactory(project=creation_status.project) new_status = f.IssueStatusFactory(project=creation_status.project)
issue = f.IssueFactory.create(status=creation_status, project=creation_status.project, owner=creation_status.project.owner) issue = f.IssueFactory.create(status=creation_status, project=creation_status.project, owner=creation_status.project.owner)
payload = { payload = {
"actor": {
"user": {
"uuid": "{ce1054cd-3f43-49dc-8aea-d3085ee7ec9b}",
"username": "test-user",
"links": {"html": {"href": "http://bitbucket.com/test-user"}}
}
},
"push": { "push": {
"changes": [ "changes": [
{ {
@ -271,6 +278,13 @@ def test_push_event_task_processing(client):
new_status = f.TaskStatusFactory(project=creation_status.project) new_status = f.TaskStatusFactory(project=creation_status.project)
task = f.TaskFactory.create(status=creation_status, project=creation_status.project, owner=creation_status.project.owner) task = f.TaskFactory.create(status=creation_status, project=creation_status.project, owner=creation_status.project.owner)
payload = { payload = {
"actor": {
"user": {
"uuid": "{ce1054cd-3f43-49dc-8aea-d3085ee7ec9b}",
"username": "test-user",
"links": {"html": {"href": "http://bitbucket.com/test-user"}}
}
},
"push": { "push": {
"changes": [ "changes": [
{ {
@ -296,6 +310,13 @@ def test_push_event_user_story_processing(client):
new_status = f.UserStoryStatusFactory(project=creation_status.project) new_status = f.UserStoryStatusFactory(project=creation_status.project)
user_story = f.UserStoryFactory.create(status=creation_status, project=creation_status.project, owner=creation_status.project.owner) user_story = f.UserStoryFactory.create(status=creation_status, project=creation_status.project, owner=creation_status.project.owner)
payload = { payload = {
"actor": {
"user": {
"uuid": "{ce1054cd-3f43-49dc-8aea-d3085ee7ec9b}",
"username": "test-user",
"links": {"html": {"href": "http://bitbucket.com/test-user"}}
}
},
"push": { "push": {
"changes": [ "changes": [
{ {
@ -314,6 +335,108 @@ def test_push_event_user_story_processing(client):
assert len(mail.outbox) == 1 assert len(mail.outbox) == 1
def test_push_event_issue_mention(client):
creation_status = f.IssueStatusFactory()
role = f.RoleFactory(project=creation_status.project, permissions=["view_issues"])
f.MembershipFactory(project=creation_status.project, role=role, user=creation_status.project.owner)
issue = f.IssueFactory.create(status=creation_status, project=creation_status.project, owner=creation_status.project.owner)
take_snapshot(issue, user=creation_status.project.owner)
payload = {
"actor": {
"user": {
"uuid": "{ce1054cd-3f43-49dc-8aea-d3085ee7ec9b}",
"username": "test-user",
"links": {"html": {"href": "http://bitbucket.com/test-user"}}
}
},
"push": {
"changes": [
{
"commits": [
{ "message": "test message test TG-%s ok bye!" % (issue.ref) }
]
}
]
}
}
mail.outbox = []
ev_hook = event_hooks.PushEventHook(issue.project, payload)
ev_hook.process_event()
issue_history = get_history_queryset_by_model_instance(issue)
assert issue_history.count() == 1
assert issue_history[0].comment.startswith("This issue has been mentioned by")
assert len(mail.outbox) == 1
def test_push_event_task_mention(client):
creation_status = f.TaskStatusFactory()
role = f.RoleFactory(project=creation_status.project, permissions=["view_tasks"])
f.MembershipFactory(project=creation_status.project, role=role, user=creation_status.project.owner)
task = f.TaskFactory.create(status=creation_status, project=creation_status.project, owner=creation_status.project.owner)
take_snapshot(task, user=creation_status.project.owner)
payload = {
"actor": {
"user": {
"uuid": "{ce1054cd-3f43-49dc-8aea-d3085ee7ec9b}",
"username": "test-user",
"links": {"html": {"href": "http://bitbucket.com/test-user"}}
}
},
"push": {
"changes": [
{
"commits": [
{ "message": "test message test TG-%s ok bye!" % (task.ref) }
]
}
]
}
}
mail.outbox = []
ev_hook = event_hooks.PushEventHook(task.project, payload)
ev_hook.process_event()
task_history = get_history_queryset_by_model_instance(task)
assert task_history.count() == 1
assert task_history[0].comment.startswith("This task has been mentioned by")
assert len(mail.outbox) == 1
def test_push_event_user_story_mention(client):
creation_status = f.UserStoryStatusFactory()
role = f.RoleFactory(project=creation_status.project, permissions=["view_us"])
f.MembershipFactory(project=creation_status.project, role=role, user=creation_status.project.owner)
user_story = f.UserStoryFactory.create(status=creation_status, project=creation_status.project, owner=creation_status.project.owner)
take_snapshot(user_story, user=creation_status.project.owner)
payload = {
"actor": {
"user": {
"uuid": "{ce1054cd-3f43-49dc-8aea-d3085ee7ec9b}",
"username": "test-user",
"links": {"html": {"href": "http://bitbucket.com/test-user"}}
}
},
"push": {
"changes": [
{
"commits": [
{ "message": "test message test TG-%s ok bye!" % (user_story.ref) }
]
}
]
}
}
mail.outbox = []
ev_hook = event_hooks.PushEventHook(user_story.project, payload)
ev_hook.process_event()
us_history = get_history_queryset_by_model_instance(user_story)
assert us_history.count() == 1
assert us_history[0].comment.startswith("This user story has been mentioned by")
assert len(mail.outbox) == 1
def test_push_event_multiple_actions(client): def test_push_event_multiple_actions(client):
creation_status = f.IssueStatusFactory() creation_status = f.IssueStatusFactory()
role = f.RoleFactory(project=creation_status.project, permissions=["view_issues"]) role = f.RoleFactory(project=creation_status.project, permissions=["view_issues"])
@ -322,6 +445,13 @@ def test_push_event_multiple_actions(client):
issue1 = f.IssueFactory.create(status=creation_status, project=creation_status.project, owner=creation_status.project.owner) issue1 = f.IssueFactory.create(status=creation_status, project=creation_status.project, owner=creation_status.project.owner)
issue2 = f.IssueFactory.create(status=creation_status, project=creation_status.project, owner=creation_status.project.owner) issue2 = f.IssueFactory.create(status=creation_status, project=creation_status.project, owner=creation_status.project.owner)
payload = { payload = {
"actor": {
"user": {
"uuid": "{ce1054cd-3f43-49dc-8aea-d3085ee7ec9b}",
"username": "test-user",
"links": {"html": {"href": "http://bitbucket.com/test-user"}}
}
},
"push": { "push": {
"changes": [ "changes": [
{ {
@ -349,6 +479,13 @@ def test_push_event_processing_case_insensitive(client):
new_status = f.TaskStatusFactory(project=creation_status.project) new_status = f.TaskStatusFactory(project=creation_status.project)
task = f.TaskFactory.create(status=creation_status, project=creation_status.project, owner=creation_status.project.owner) task = f.TaskFactory.create(status=creation_status, project=creation_status.project, owner=creation_status.project.owner)
payload = { payload = {
"actor": {
"user": {
"uuid": "{ce1054cd-3f43-49dc-8aea-d3085ee7ec9b}",
"username": "test-user",
"links": {"html": {"href": "http://bitbucket.com/test-user"}}
}
},
"push": { "push": {
"changes": [ "changes": [
{ {
@ -370,6 +507,13 @@ def test_push_event_processing_case_insensitive(client):
def test_push_event_task_bad_processing_non_existing_ref(client): def test_push_event_task_bad_processing_non_existing_ref(client):
issue_status = f.IssueStatusFactory() issue_status = f.IssueStatusFactory()
payload = { payload = {
"actor": {
"user": {
"uuid": "{ce1054cd-3f43-49dc-8aea-d3085ee7ec9b}",
"username": "test-user",
"links": {"html": {"href": "http://bitbucket.com/test-user"}}
}
},
"push": { "push": {
"changes": [ "changes": [
{ {
@ -393,6 +537,13 @@ def test_push_event_task_bad_processing_non_existing_ref(client):
def test_push_event_us_bad_processing_non_existing_status(client): def test_push_event_us_bad_processing_non_existing_status(client):
user_story = f.UserStoryFactory.create() user_story = f.UserStoryFactory.create()
payload = { payload = {
"actor": {
"user": {
"uuid": "{ce1054cd-3f43-49dc-8aea-d3085ee7ec9b}",
"username": "test-user",
"links": {"html": {"href": "http://bitbucket.com/test-user"}}
}
},
"push": { "push": {
"changes": [ "changes": [
{ {
@ -417,6 +568,13 @@ def test_push_event_us_bad_processing_non_existing_status(client):
def test_push_event_bad_processing_non_existing_status(client): def test_push_event_bad_processing_non_existing_status(client):
issue = f.IssueFactory.create() issue = f.IssueFactory.create()
payload = { payload = {
"actor": {
"user": {
"uuid": "{ce1054cd-3f43-49dc-8aea-d3085ee7ec9b}",
"username": "test-user",
"links": {"html": {"href": "http://bitbucket.com/test-user"}}
}
},
"push": { "push": {
"changes": [ "changes": [
{ {
@ -686,8 +844,10 @@ def test_api_patch_project_modules(client):
def test_replace_bitbucket_references(): def test_replace_bitbucket_references():
assert event_hooks.replace_bitbucket_references("project-url", "#2") == "[BitBucket#2](project-url/issues/2)" ev_hook = event_hooks.BaseBitBucketEventHook
assert event_hooks.replace_bitbucket_references("project-url", "#2 ") == "[BitBucket#2](project-url/issues/2) " assert ev_hook.replace_bitbucket_references(None, "project-url", "#2") == "[BitBucket#2](project-url/issues/2)"
assert event_hooks.replace_bitbucket_references("project-url", " #2 ") == " [BitBucket#2](project-url/issues/2) " assert ev_hook.replace_bitbucket_references(None, "project-url", "#2 ") == "[BitBucket#2](project-url/issues/2) "
assert event_hooks.replace_bitbucket_references("project-url", " #2") == " [BitBucket#2](project-url/issues/2)" assert ev_hook.replace_bitbucket_references(None, "project-url", " #2 ") == " [BitBucket#2](project-url/issues/2) "
assert event_hooks.replace_bitbucket_references("project-url", "#test") == "#test" assert ev_hook.replace_bitbucket_references(None, "project-url", " #2") == " [BitBucket#2](project-url/issues/2)"
assert ev_hook.replace_bitbucket_references(None, "project-url", "#test") == "#test"
assert ev_hook.replace_bitbucket_references(None, "project-url", None) == ""

View File

@ -172,6 +172,70 @@ def test_push_event_user_story_processing(client):
assert len(mail.outbox) == 1 assert len(mail.outbox) == 1
def test_push_event_issue_mention(client):
creation_status = f.IssueStatusFactory()
role = f.RoleFactory(project=creation_status.project, permissions=["view_issues"])
f.MembershipFactory(project=creation_status.project, role=role, user=creation_status.project.owner)
issue = f.IssueFactory.create(status=creation_status, project=creation_status.project, owner=creation_status.project.owner)
take_snapshot(issue, user=creation_status.project.owner)
payload = {"commits": [
{"message": """test message
test TG-%s ok
bye!
""" % (issue.ref)},
]}
mail.outbox = []
ev_hook = event_hooks.PushEventHook(issue.project, payload)
ev_hook.process_event()
issue_history = get_history_queryset_by_model_instance(issue)
assert issue_history.count() == 1
assert issue_history[0].comment.startswith("This issue has been mentioned by")
assert len(mail.outbox) == 1
def test_push_event_task_mention(client):
creation_status = f.TaskStatusFactory()
role = f.RoleFactory(project=creation_status.project, permissions=["view_tasks"])
f.MembershipFactory(project=creation_status.project, role=role, user=creation_status.project.owner)
task = f.TaskFactory.create(status=creation_status, project=creation_status.project, owner=creation_status.project.owner)
take_snapshot(task, user=creation_status.project.owner)
payload = {"commits": [
{"message": """test message
test TG-%s ok
bye!
""" % (task.ref)},
]}
mail.outbox = []
ev_hook = event_hooks.PushEventHook(task.project, payload)
ev_hook.process_event()
task_history = get_history_queryset_by_model_instance(task)
assert task_history.count() == 1
assert task_history[0].comment.startswith("This task has been mentioned by")
assert len(mail.outbox) == 1
def test_push_event_user_story_mention(client):
creation_status = f.UserStoryStatusFactory()
role = f.RoleFactory(project=creation_status.project, permissions=["view_us"])
f.MembershipFactory(project=creation_status.project, role=role, user=creation_status.project.owner)
user_story = f.UserStoryFactory.create(status=creation_status, project=creation_status.project, owner=creation_status.project.owner)
take_snapshot(user_story, user=creation_status.project.owner)
payload = {"commits": [
{"message": """test message
test TG-%s ok
bye!
""" % (user_story.ref)},
]}
mail.outbox = []
ev_hook = event_hooks.PushEventHook(user_story.project, payload)
ev_hook.process_event()
us_history = get_history_queryset_by_model_instance(user_story)
assert us_history.count() == 1
assert us_history[0].comment.startswith("This user story has been mentioned by")
assert len(mail.outbox) == 1
def test_push_event_multiple_actions(client): def test_push_event_multiple_actions(client):
creation_status = f.IssueStatusFactory() creation_status = f.IssueStatusFactory()
role = f.RoleFactory(project=creation_status.project, permissions=["view_issues"]) role = f.RoleFactory(project=creation_status.project, permissions=["view_issues"])
@ -454,7 +518,7 @@ def test_issues_event_bad_comment(client):
take_snapshot(issue, user=issue.owner) take_snapshot(issue, user=issue.owner)
payload = { payload = {
"action": "other", "action": "created",
"issue": {}, "issue": {},
"comment": {}, "comment": {},
"repository": { "repository": {
@ -512,9 +576,10 @@ def test_api_patch_project_modules(client):
def test_replace_github_references(): def test_replace_github_references():
assert event_hooks.replace_github_references("project-url", "#2") == "[GitHub#2](project-url/issues/2)" ev_hook = event_hooks.BaseGitHubEventHook
assert event_hooks.replace_github_references("project-url", "#2 ") == "[GitHub#2](project-url/issues/2) " assert ev_hook.replace_github_references(None, "project-url", "#2") == "[GitHub#2](project-url/issues/2)"
assert event_hooks.replace_github_references("project-url", " #2 ") == " [GitHub#2](project-url/issues/2) " assert ev_hook.replace_github_references(None, "project-url", "#2 ") == "[GitHub#2](project-url/issues/2) "
assert event_hooks.replace_github_references("project-url", " #2") == " [GitHub#2](project-url/issues/2)" assert ev_hook.replace_github_references(None, "project-url", " #2 ") == " [GitHub#2](project-url/issues/2) "
assert event_hooks.replace_github_references("project-url", "#test") == "#test" assert ev_hook.replace_github_references(None, "project-url", " #2") == " [GitHub#2](project-url/issues/2)"
assert event_hooks.replace_github_references("project-url", None) == "" assert ev_hook.replace_github_references(None, "project-url", "#test") == "#test"
assert ev_hook.replace_github_references(None, "project-url", None) == ""

View File

@ -18,6 +18,7 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>. # along with this program. If not, see <http://www.gnu.org/licenses/>.
import pytest import pytest
from copy import deepcopy
from unittest import mock from unittest import mock
@ -41,6 +42,189 @@ from .. import factories as f
pytestmark = pytest.mark.django_db pytestmark = pytest.mark.django_db
push_base_payload = {
"object_kind": "push",
"before": "95790bf891e76fee5e1747ab589903a6a1f80f22",
"after": "da1560886d4f094c3e6c9ef40349f7d38b5d27d7",
"ref": "refs/heads/master",
"checkout_sha": "da1560886d4f094c3e6c9ef40349f7d38b5d27d7",
"user_id": 4,
"user_name": "John Smith",
"user_email": "john@example.com",
"user_avatar": "https://s.gravatar.com/avatar/d4c74594d841139328695756648b6bd6?s=8://s.gravatar.com/avatar/d4c74594d841139328695756648b6bd6?s=80",
"project_id": 15,
"project": {
"name": "Diaspora",
"description": "",
"web_url": "http://example.com/mike/diaspora",
"avatar_url": None,
"git_ssh_url": "git@example.com:mike/diaspora.git",
"git_http_url": "http://example.com/mike/diaspora.git",
"namespace": "Mike",
"visibility_level": 0,
"path_with_namespace": "mike/diaspora",
"default_branch": "master",
"homepage": "http://example.com/mike/diaspora",
"url": "git@example.com:mike/diaspora.git",
"ssh_url": "git@example.com:mike/diaspora.git",
"http_url": "http://example.com/mike/diaspora.git"
},
"repository": {
"name": "Diaspora",
"url": "git@example.com:mike/diaspora.git",
"description": "",
"homepage": "http://example.com/mike/diaspora",
"git_http_url": "http://example.com/mike/diaspora.git",
"git_ssh_url": "git@example.com:mike/diaspora.git",
"visibility_level": 0
},
"commits": [
{
"id": "b6568db1bc1dcd7f8b4d5a946b0b91f9dacd7327",
"message": "Update Catalan translation to e38cb41.",
"timestamp": "2011-12-12T14:27:31+02:00",
"id": "b6568db1bc1dcd7f8b4d5a946b0b91f9dacd7327",
"url": "http://example.com/mike/diaspora/commit/b6568db1bc1dcd7f8b4d5a946b0b91f9dacd7327",
"author": {
"name": "Jordi Mallach",
"email": "jordi@softcatala.org"
},
"added": ["CHANGELOG"],
"modified": ["app/controller/application.rb"],
"removed": []
},
{
"id": "da1560886d4f094c3e6c9ef40349f7d38b5d27d7",
"message": "fixed readme",
"timestamp": "2012-01-03T23:36:29+02:00",
"url": "http://example.com/mike/diaspora/commit/da1560886d4f094c3e6c9ef40349f7d38b5d27d7",
"author": {
"name": "GitLab dev user",
"email": "gitlabdev@dv6700.(none)"
},
"added": ["CHANGELOG"],
"modified": ["app/controller/application.rb"],
"removed": []
}
],
"total_commits_count": 4
}
new_issue_base_payload = {
"object_kind": "issue",
"user": {
"name": "Administrator",
"username": "root",
"avatar_url": "http://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=40\u0026d=identicon"
},
"project": {
"name": "Gitlab Test",
"description": "Aut reprehenderit ut est.",
"web_url": "http://example.com/gitlabhq/gitlab-test",
"avatar_url": None,
"git_ssh_url": "git@example.com:gitlabhq/gitlab-test.git",
"git_http_url": "http://example.com/gitlabhq/gitlab-test.git",
"namespace": "GitlabHQ",
"visibility_level": 20,
"path_with_namespace": "gitlabhq/gitlab-test",
"default_branch": "master",
"homepage": "http://example.com/gitlabhq/gitlab-test",
"url": "http://example.com/gitlabhq/gitlab-test.git",
"ssh_url": "git@example.com:gitlabhq/gitlab-test.git",
"http_url": "http://example.com/gitlabhq/gitlab-test.git"
},
"repository": {
"name": "Gitlab Test",
"url": "http://example.com/gitlabhq/gitlab-test.git",
"description": "Aut reprehenderit ut est.",
"homepage": "http://example.com/gitlabhq/gitlab-test"
},
"object_attributes": {
"id": 301,
"title": "New API: create/update/delete file",
"assignee_id": 51,
"author_id": 51,
"project_id": 14,
"created_at": "2013-12-03T17:15:43Z",
"updated_at": "2013-12-03T17:15:43Z",
"position": 0,
"branch_name": None,
"description": "Create new API for manipulations with repository",
"milestone_id": None,
"state": "opened",
"iid": 23,
"url": "http://example.com/diaspora/issues/23",
"action": "open"
},
"assignee": {
"name": "User1",
"username": "user1",
"avatar_url": "http://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=40\u0026d=identicon"
}
}
issue_comment_base_payload = {
"object_kind": "note",
"user": {
"name": "Administrator",
"username": "root",
"avatar_url": "http://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=40\u0026d=identicon"
},
"project_id": 5,
"project": {
"name": "Gitlab Test",
"description": "Aut reprehenderit ut est.",
"web_url": "http://example.com/gitlab-org/gitlab-test",
"avatar_url": None,
"git_ssh_url": "git@example.com:gitlab-org/gitlab-test.git",
"git_http_url": "http://example.com/gitlab-org/gitlab-test.git",
"namespace": "Gitlab Org",
"visibility_level": 10,
"path_with_namespace": "gitlab-org/gitlab-test",
"default_branch": "master",
"homepage": "http://example.com/gitlab-org/gitlab-test",
"url": "http://example.com/gitlab-org/gitlab-test.git",
"ssh_url": "git@example.com:gitlab-org/gitlab-test.git",
"http_url": "http://example.com/gitlab-org/gitlab-test.git"
},
"repository": {
"name": "diaspora",
"url": "git@example.com:mike/diaspora.git",
"description": "",
"homepage": "http://example.com/mike/diaspora"
},
"object_attributes": {
"id": 1241,
"note": "Hello world",
"noteable_type": "Issue",
"author_id": 1,
"created_at": "2015-05-17 17:06:40 UTC",
"updated_at": "2015-05-17 17:06:40 UTC",
"project_id": 5,
"attachment": None,
"line_code": None,
"commit_id": "",
"noteable_id": 92,
"system": False,
"st_diff": None,
"url": "http://example.com/gitlab-org/gitlab-test/issues/17#note_1241"
},
"issue": {
"id": 92,
"title": "test",
"assignee_id": None,
"author_id": 1,
"project_id": 5,
"created_at": "2015-04-12 14:53:17 UTC",
"updated_at": "2015-04-26 08:28:42 UTC",
"position": 0,
"branch_name": None,
"description": "test",
"milestone_id": None,
"state": "closed",
"iid": 17
}
}
def test_bad_signature(client): def test_bad_signature(client):
project = f.ProjectFactory() project = f.ProjectFactory()
@ -90,8 +274,8 @@ def test_ok_empty_payload(client):
url = reverse("gitlab-hook-list") url = reverse("gitlab-hook-list")
url = "{}?project={}&key={}".format(url, project.id, "tpnIwJDz4e") url = "{}?project={}&key={}".format(url, project.id, "tpnIwJDz4e")
data = {} response = client.post(url, "null", content_type="application/json",
response = client.post(url,"null", content_type="application/json", REMOTE_ADDR="111.111.111.111") REMOTE_ADDR="111.111.111.111")
assert response.status_code == 204 assert response.status_code == 204
@ -108,8 +292,7 @@ def test_ok_signature_ip_in_network(client):
url = reverse("gitlab-hook-list") url = reverse("gitlab-hook-list")
url = "{}?project={}&key={}".format(url, project.id, "tpnIwJDz4e") url = "{}?project={}&key={}".format(url, project.id, "tpnIwJDz4e")
data = {"test:": "data"} data = {"test:": "data"}
response = client.post(url, response = client.post(url, json.dumps(data),
json.dumps(data),
content_type="application/json", content_type="application/json",
REMOTE_ADDR="111.111.111.112") REMOTE_ADDR="111.111.111.112")
@ -243,9 +426,13 @@ def test_push_event_detected(client):
project = f.ProjectFactory() project = f.ProjectFactory()
url = reverse("gitlab-hook-list") url = reverse("gitlab-hook-list")
url = "%s?project=%s" % (url, project.id) url = "%s?project=%s" % (url, project.id)
data = {"commits": [ data = deepcopy(push_base_payload)
{"message": "test message"}, data["commits"] = [{
]} "message": "test message",
"id": "b6568db1bc1dcd7f8b4d5a946b0b91f9dacd7327",
"url": "http://example.com/mike/diaspora/commit/b6568db1bc1dcd7f8b4d5a946b0b91f9dacd7327",
}]
data["total_commits_count"] = 1
GitLabViewSet._validate_signature = mock.Mock(return_value=True) GitLabViewSet._validate_signature = mock.Mock(return_value=True)
@ -265,12 +452,16 @@ def test_push_event_issue_processing(client):
f.MembershipFactory(project=creation_status.project, role=role, user=creation_status.project.owner) f.MembershipFactory(project=creation_status.project, role=role, user=creation_status.project.owner)
new_status = f.IssueStatusFactory(project=creation_status.project) new_status = f.IssueStatusFactory(project=creation_status.project)
issue = f.IssueFactory.create(status=creation_status, project=creation_status.project, owner=creation_status.project.owner) issue = f.IssueFactory.create(status=creation_status, project=creation_status.project, owner=creation_status.project.owner)
payload = {"commits": [ payload = deepcopy(push_base_payload)
{"message": """test message payload["commits"] = [{
test TG-%s #%s ok "message": """test message
bye! test TG-%s #%s ok
""" % (issue.ref, new_status.slug)}, bye!
]} """ % (issue.ref, new_status.slug),
"id": "b6568db1bc1dcd7f8b4d5a946b0b91f9dacd7327",
"url": "http://example.com/mike/diaspora/commit/b6568db1bc1dcd7f8b4d5a946b0b91f9dacd7327",
}]
payload["total_commits_count"] = 1
mail.outbox = [] mail.outbox = []
ev_hook = event_hooks.PushEventHook(issue.project, payload) ev_hook = event_hooks.PushEventHook(issue.project, payload)
ev_hook.process_event() ev_hook.process_event()
@ -285,12 +476,16 @@ def test_push_event_task_processing(client):
f.MembershipFactory(project=creation_status.project, role=role, user=creation_status.project.owner) f.MembershipFactory(project=creation_status.project, role=role, user=creation_status.project.owner)
new_status = f.TaskStatusFactory(project=creation_status.project) new_status = f.TaskStatusFactory(project=creation_status.project)
task = f.TaskFactory.create(status=creation_status, project=creation_status.project, owner=creation_status.project.owner) task = f.TaskFactory.create(status=creation_status, project=creation_status.project, owner=creation_status.project.owner)
payload = {"commits": [ payload = deepcopy(push_base_payload)
{"message": """test message payload["commits"] = [{
"message": """test message
test TG-%s #%s ok test TG-%s #%s ok
bye! bye!
""" % (task.ref, new_status.slug)}, """ % (task.ref, new_status.slug),
]} "id": "b6568db1bc1dcd7f8b4d5a946b0b91f9dacd7327",
"url": "http://example.com/mike/diaspora/commit/b6568db1bc1dcd7f8b4d5a946b0b91f9dacd7327",
}]
payload["total_commits_count"] = 1
mail.outbox = [] mail.outbox = []
ev_hook = event_hooks.PushEventHook(task.project, payload) ev_hook = event_hooks.PushEventHook(task.project, payload)
ev_hook.process_event() ev_hook.process_event()
@ -305,12 +500,16 @@ def test_push_event_user_story_processing(client):
f.MembershipFactory(project=creation_status.project, role=role, user=creation_status.project.owner) f.MembershipFactory(project=creation_status.project, role=role, user=creation_status.project.owner)
new_status = f.UserStoryStatusFactory(project=creation_status.project) new_status = f.UserStoryStatusFactory(project=creation_status.project)
user_story = f.UserStoryFactory.create(status=creation_status, project=creation_status.project, owner=creation_status.project.owner) user_story = f.UserStoryFactory.create(status=creation_status, project=creation_status.project, owner=creation_status.project.owner)
payload = {"commits": [ payload = deepcopy(push_base_payload)
{"message": """test message payload["commits"] = [{
"message": """test message
test TG-%s #%s ok test TG-%s #%s ok
bye! bye!
""" % (user_story.ref, new_status.slug)}, """ % (user_story.ref, new_status.slug),
]} "id": "b6568db1bc1dcd7f8b4d5a946b0b91f9dacd7327",
"url": "http://example.com/mike/diaspora/commit/b6568db1bc1dcd7f8b4d5a946b0b91f9dacd7327",
}]
payload["total_commits_count"] = 1
mail.outbox = [] mail.outbox = []
ev_hook = event_hooks.PushEventHook(user_story.project, payload) ev_hook = event_hooks.PushEventHook(user_story.project, payload)
@ -320,6 +519,79 @@ def test_push_event_user_story_processing(client):
assert len(mail.outbox) == 1 assert len(mail.outbox) == 1
def test_push_event_issue_mention(client):
creation_status = f.IssueStatusFactory()
role = f.RoleFactory(project=creation_status.project, permissions=["view_issues"])
f.MembershipFactory(project=creation_status.project, role=role, user=creation_status.project.owner)
issue = f.IssueFactory.create(status=creation_status, project=creation_status.project, owner=creation_status.project.owner)
take_snapshot(issue, user=creation_status.project.owner)
payload = deepcopy(push_base_payload)
payload["commits"] = [{
"message": """test message
test TG-%s ok
bye!
""" % (issue.ref),
"id": "b6568db1bc1dcd7f8b4d5a946b0b91f9dacd7327",
"url": "http://example.com/mike/diaspora/commit/b6568db1bc1dcd7f8b4d5a946b0b91f9dacd7327",
}]
mail.outbox = []
ev_hook = event_hooks.PushEventHook(issue.project, payload)
ev_hook.process_event()
issue_history = get_history_queryset_by_model_instance(issue)
assert issue_history.count() == 1
assert issue_history[0].comment.startswith("This issue has been mentioned by")
assert len(mail.outbox) == 1
def test_push_event_task_mention(client):
creation_status = f.TaskStatusFactory()
role = f.RoleFactory(project=creation_status.project, permissions=["view_tasks"])
f.MembershipFactory(project=creation_status.project, role=role, user=creation_status.project.owner)
task = f.TaskFactory.create(status=creation_status, project=creation_status.project, owner=creation_status.project.owner)
take_snapshot(task, user=creation_status.project.owner)
payload = deepcopy(push_base_payload)
payload["commits"] = [{
"message": """test message
test TG-%s ok
bye!
""" % (task.ref),
"id": "b6568db1bc1dcd7f8b4d5a946b0b91f9dacd7327",
"url": "http://example.com/mike/diaspora/commit/b6568db1bc1dcd7f8b4d5a946b0b91f9dacd7327",
}]
mail.outbox = []
ev_hook = event_hooks.PushEventHook(task.project, payload)
ev_hook.process_event()
task_history = get_history_queryset_by_model_instance(task)
assert task_history.count() == 1
assert task_history[0].comment.startswith("This task has been mentioned by")
assert len(mail.outbox) == 1
def test_push_event_user_story_mention(client):
creation_status = f.UserStoryStatusFactory()
role = f.RoleFactory(project=creation_status.project, permissions=["view_us"])
f.MembershipFactory(project=creation_status.project, role=role, user=creation_status.project.owner)
user_story = f.UserStoryFactory.create(status=creation_status, project=creation_status.project, owner=creation_status.project.owner)
take_snapshot(user_story, user=creation_status.project.owner)
payload = deepcopy(push_base_payload)
payload["commits"] = [{
"message": """test message
test TG-%s ok
bye!
""" % (user_story.ref),
"id": "b6568db1bc1dcd7f8b4d5a946b0b91f9dacd7327",
"url": "http://example.com/mike/diaspora/commit/b6568db1bc1dcd7f8b4d5a946b0b91f9dacd7327",
}]
mail.outbox = []
ev_hook = event_hooks.PushEventHook(user_story.project, payload)
ev_hook.process_event()
us_history = get_history_queryset_by_model_instance(user_story)
assert us_history.count() == 1
assert us_history[0].comment.startswith("This user story has been mentioned by")
assert len(mail.outbox) == 1
def test_push_event_multiple_actions(client): def test_push_event_multiple_actions(client):
creation_status = f.IssueStatusFactory() creation_status = f.IssueStatusFactory()
role = f.RoleFactory(project=creation_status.project, permissions=["view_issues"]) role = f.RoleFactory(project=creation_status.project, permissions=["view_issues"])
@ -327,13 +599,17 @@ def test_push_event_multiple_actions(client):
new_status = f.IssueStatusFactory(project=creation_status.project) new_status = f.IssueStatusFactory(project=creation_status.project)
issue1 = f.IssueFactory.create(status=creation_status, project=creation_status.project, owner=creation_status.project.owner) issue1 = f.IssueFactory.create(status=creation_status, project=creation_status.project, owner=creation_status.project.owner)
issue2 = f.IssueFactory.create(status=creation_status, project=creation_status.project, owner=creation_status.project.owner) issue2 = f.IssueFactory.create(status=creation_status, project=creation_status.project, owner=creation_status.project.owner)
payload = {"commits": [ payload = deepcopy(push_base_payload)
{"message": """test message payload["commits"] = [{
"message": """test message
test TG-%s #%s ok test TG-%s #%s ok
test TG-%s #%s ok test TG-%s #%s ok
bye! bye!
""" % (issue1.ref, new_status.slug, issue2.ref, new_status.slug)}, """ % (issue1.ref, new_status.slug, issue2.ref, new_status.slug),
]} "id": "b6568db1bc1dcd7f8b4d5a946b0b91f9dacd7327",
"url": "http://example.com/mike/diaspora/commit/b6568db1bc1dcd7f8b4d5a946b0b91f9dacd7327",
}]
payload["total_commits_count"] = 1
mail.outbox = [] mail.outbox = []
ev_hook1 = event_hooks.PushEventHook(issue1.project, payload) ev_hook1 = event_hooks.PushEventHook(issue1.project, payload)
ev_hook1.process_event() ev_hook1.process_event()
@ -350,12 +626,16 @@ def test_push_event_processing_case_insensitive(client):
f.MembershipFactory(project=creation_status.project, role=role, user=creation_status.project.owner) f.MembershipFactory(project=creation_status.project, role=role, user=creation_status.project.owner)
new_status = f.TaskStatusFactory(project=creation_status.project) new_status = f.TaskStatusFactory(project=creation_status.project)
task = f.TaskFactory.create(status=creation_status, project=creation_status.project, owner=creation_status.project.owner) task = f.TaskFactory.create(status=creation_status, project=creation_status.project, owner=creation_status.project.owner)
payload = {"commits": [ payload = deepcopy(push_base_payload)
{"message": """test message payload["commits"] = [{
"message": """test message
test tg-%s #%s ok test tg-%s #%s ok
bye! bye!
""" % (task.ref, new_status.slug.upper())}, """ % (task.ref, new_status.slug.upper()),
]} "id": "b6568db1bc1dcd7f8b4d5a946b0b91f9dacd7327",
"url": "http://example.com/mike/diaspora/commit/b6568db1bc1dcd7f8b4d5a946b0b91f9dacd7327",
}]
payload["total_commits_count"] = 1
mail.outbox = [] mail.outbox = []
ev_hook = event_hooks.PushEventHook(task.project, payload) ev_hook = event_hooks.PushEventHook(task.project, payload)
ev_hook.process_event() ev_hook.process_event()
@ -366,12 +646,16 @@ def test_push_event_processing_case_insensitive(client):
def test_push_event_task_bad_processing_non_existing_ref(client): def test_push_event_task_bad_processing_non_existing_ref(client):
issue_status = f.IssueStatusFactory() issue_status = f.IssueStatusFactory()
payload = {"commits": [ payload = deepcopy(push_base_payload)
{"message": """test message payload["commits"] = [{
"message": """test message
test TG-6666666 #%s ok test TG-6666666 #%s ok
bye! bye!
""" % (issue_status.slug)}, """ % (issue_status.slug),
]} "id": "b6568db1bc1dcd7f8b4d5a946b0b91f9dacd7327",
"url": "http://example.com/mike/diaspora/commit/b6568db1bc1dcd7f8b4d5a946b0b91f9dacd7327",
}]
payload["total_commits_count"] = 1
mail.outbox = [] mail.outbox = []
ev_hook = event_hooks.PushEventHook(issue_status.project, payload) ev_hook = event_hooks.PushEventHook(issue_status.project, payload)
@ -384,12 +668,16 @@ def test_push_event_task_bad_processing_non_existing_ref(client):
def test_push_event_us_bad_processing_non_existing_status(client): def test_push_event_us_bad_processing_non_existing_status(client):
user_story = f.UserStoryFactory.create() user_story = f.UserStoryFactory.create()
payload = {"commits": [ payload = deepcopy(push_base_payload)
{"message": """test message payload["commits"] = [{
"message": """test message
test TG-%s #non-existing-slug ok test TG-%s #non-existing-slug ok
bye! bye!
""" % (user_story.ref)}, """ % (user_story.ref),
]} "id": "b6568db1bc1dcd7f8b4d5a946b0b91f9dacd7327",
"url": "http://example.com/mike/diaspora/commit/b6568db1bc1dcd7f8b4d5a946b0b91f9dacd7327",
}]
payload["total_commits_count"] = 1
mail.outbox = [] mail.outbox = []
@ -403,12 +691,16 @@ def test_push_event_us_bad_processing_non_existing_status(client):
def test_push_event_bad_processing_non_existing_status(client): def test_push_event_bad_processing_non_existing_status(client):
issue = f.IssueFactory.create() issue = f.IssueFactory.create()
payload = {"commits": [ payload = deepcopy(push_base_payload)
{"message": """test message payload["commits"] = [{
"message": """test message
test TG-%s #non-existing-slug ok test TG-%s #non-existing-slug ok
bye! bye!
""" % (issue.ref)}, """ % (issue.ref),
]} "id": "b6568db1bc1dcd7f8b4d5a946b0b91f9dacd7327",
"url": "http://example.com/mike/diaspora/commit/b6568db1bc1dcd7f8b4d5a946b0b91f9dacd7327",
}]
payload["total_commits_count"] = 1
mail.outbox = [] mail.outbox = []
@ -432,15 +724,12 @@ def test_issues_event_opened_issue(client):
notify_policy.notify_level = NotifyLevel.all notify_policy.notify_level = NotifyLevel.all
notify_policy.save() notify_policy.save()
payload = { payload = deepcopy(new_issue_base_payload)
"object_kind": "issue", payload["object_attributes"]["title"] = "test-title"
"object_attributes": { payload["object_attributes"]["description"] = "test-body"
"title": "test-title", payload["object_attributes"]["url"] = "http://gitlab.com/test/project/issues/11"
"description": "test-body", payload["object_attributes"]["action"] = "open"
"url": "http://gitlab.com/test/project/issues/11", payload["repository"]["homepage"] = "test"
"action": "open",
},
}
mail.outbox = [] mail.outbox = []
@ -459,15 +748,12 @@ def test_issues_event_other_than_opened_issue(client):
issue.project.default_priority = issue.priority issue.project.default_priority = issue.priority
issue.project.save() issue.project.save()
payload = { payload = deepcopy(new_issue_base_payload)
"object_kind": "issue", payload["object_attributes"]["title"] = "test-title"
"object_attributes": { payload["object_attributes"]["description"] = "test-body"
"title": "test-title", payload["object_attributes"]["url"] = "http://gitlab.com/test/project/issues/11"
"description": "test-body", payload["object_attributes"]["action"] = "update"
"url": "http://gitlab.com/test/project/issues/11", payload["repository"]["homepage"] = "test"
"action": "update",
},
}
mail.outbox = [] mail.outbox = []
@ -486,12 +772,12 @@ def test_issues_event_bad_issue(client):
issue.project.default_priority = issue.priority issue.project.default_priority = issue.priority
issue.project.save() issue.project.save()
payload = { payload = deepcopy(new_issue_base_payload)
"object_kind": "issue", del payload["object_attributes"]["title"]
"object_attributes": { del payload["object_attributes"]["description"]
"action": "open", del payload["object_attributes"]["url"]
}, payload["object_attributes"]["action"] = "open"
} payload["repository"]["homepage"] = "test"
mail.outbox = [] mail.outbox = []
ev_hook = event_hooks.IssuesEventHook(issue.project, payload) ev_hook = event_hooks.IssuesEventHook(issue.project, payload)
@ -518,23 +804,13 @@ def test_issue_comment_event_on_existing_issue_task_and_us(client):
us = f.UserStoryFactory.create(external_reference=["gitlab", "http://gitlab.com/test/project/issues/11"], owner=project.owner, project=project) us = f.UserStoryFactory.create(external_reference=["gitlab", "http://gitlab.com/test/project/issues/11"], owner=project.owner, project=project)
take_snapshot(us, user=user) take_snapshot(us, user=user)
payload = { payload = deepcopy(issue_comment_base_payload)
"user": { payload["user"]["username"] = "test"
"username": "test" payload["issue"]["iid"] = "11"
}, payload["issue"]["title"] = "test-title"
"issue": { payload["object_attributes"]["noteable_type"] = "Issue"
"iid": "11", payload["object_attributes"]["note"] = "Test body"
"title": "test-title", payload["repository"]["homepage"] = "http://gitlab.com/test/project"
},
"object_attributes": {
"noteable_type": "Issue",
"note": "Test body",
},
"repository": {
"homepage": "http://gitlab.com/test/project",
},
}
mail.outbox = [] mail.outbox = []
@ -568,22 +844,13 @@ def test_issue_comment_event_on_not_existing_issue_task_and_us(client):
us = f.UserStoryFactory.create(project=issue.project, external_reference=["gitlab", "10"]) us = f.UserStoryFactory.create(project=issue.project, external_reference=["gitlab", "10"])
take_snapshot(us, user=us.owner) take_snapshot(us, user=us.owner)
payload = { payload = deepcopy(issue_comment_base_payload)
"user": { payload["user"]["username"] = "test"
"username": "test" payload["issue"]["iid"] = "99999"
}, payload["issue"]["title"] = "test-title"
"issue": { payload["object_attributes"]["noteable_type"] = "Issue"
"iid": "99999", payload["object_attributes"]["note"] = "test comment"
"title": "test-title", payload["repository"]["homepage"] = "test"
},
"object_attributes": {
"noteable_type": "Issue",
"note": "test comment",
},
"repository": {
"homepage": "test",
},
}
mail.outbox = [] mail.outbox = []
@ -605,21 +872,14 @@ def test_issues_event_bad_comment(client):
issue = f.IssueFactory.create(external_reference=["gitlab", "10"]) issue = f.IssueFactory.create(external_reference=["gitlab", "10"])
take_snapshot(issue, user=issue.owner) take_snapshot(issue, user=issue.owner)
payload = { payload = deepcopy(issue_comment_base_payload)
"user": { payload["user"]["username"] = "test"
"username": "test" payload["issue"]["iid"] = "10"
}, payload["issue"]["title"] = "test-title"
"issue": { payload["object_attributes"]["noteable_type"] = "Issue"
"iid": "10", del payload["object_attributes"]["note"]
"title": "test-title", payload["repository"]["homepage"] = "test"
},
"object_attributes": {
"noteable_type": "Issue",
},
"repository": {
"homepage": "test",
},
}
ev_hook = event_hooks.IssueCommentEventHook(issue.project, payload) ev_hook = event_hooks.IssueCommentEventHook(issue.project, payload)
mail.outbox = [] mail.outbox = []
@ -671,9 +931,10 @@ def test_api_patch_project_modules(client):
def test_replace_gitlab_references(): def test_replace_gitlab_references():
assert event_hooks.replace_gitlab_references("project-url", "#2") == "[GitLab#2](project-url/issues/2)" ev_hook = event_hooks.BaseGitLabEventHook
assert event_hooks.replace_gitlab_references("project-url", "#2 ") == "[GitLab#2](project-url/issues/2) " assert ev_hook.replace_gitlab_references(None, "project-url", "#2") == "[GitLab#2](project-url/issues/2)"
assert event_hooks.replace_gitlab_references("project-url", " #2 ") == " [GitLab#2](project-url/issues/2) " assert ev_hook.replace_gitlab_references(None, "project-url", "#2 ") == "[GitLab#2](project-url/issues/2) "
assert event_hooks.replace_gitlab_references("project-url", " #2") == " [GitLab#2](project-url/issues/2)" assert ev_hook.replace_gitlab_references(None, "project-url", " #2 ") == " [GitLab#2](project-url/issues/2) "
assert event_hooks.replace_gitlab_references("project-url", "#test") == "#test" assert ev_hook.replace_gitlab_references(None, "project-url", " #2") == " [GitLab#2](project-url/issues/2)"
assert event_hooks.replace_gitlab_references("project-url", None) == "" assert ev_hook.replace_gitlab_references(None, "project-url", "#test") == "#test"
assert ev_hook.replace_gitlab_references(None, "project-url", None) == ""