Refactor bitbucket/github/gitlab hooks
parent
2a4cac4647
commit
5856ad6410
|
@ -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)
|
||||||
|
|
|
@ -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
|
|
||||||
|
|
||||||
changes = self.payload.get("push", {}).get('changes', [])
|
def replace_bitbucket_references(self, project_url, wiki_text):
|
||||||
for change in filter(None, changes):
|
if wiki_text is None:
|
||||||
commits = change.get("commits", [])
|
wiki_text = ""
|
||||||
if not commits:
|
|
||||||
continue
|
|
||||||
|
|
||||||
for commit in commits:
|
|
||||||
message = commit.get("message", None)
|
|
||||||
if not message:
|
|
||||||
continue
|
|
||||||
|
|
||||||
self._process_message(message, None)
|
|
||||||
|
|
||||||
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)
|
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)
|
return re.sub(r"(\s|^)#(\d+)(\s|$)", template, wiki_text, 0, re.M)
|
||||||
|
|
||||||
|
|
||||||
class IssuesEventHook(BaseEventHook):
|
class IssuesEventHook(BaseBitBucketEventHook, BaseNewIssueEventHook):
|
||||||
def process_event(self):
|
def get_data(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 = 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)
|
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', '')
|
comment_message = self.payload.get('comment', {}).get('content', {}).get('raw', '')
|
||||||
comment_message = replace_bitbucket_references(project_url, comment_message)
|
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)
|
||||||
|
}
|
||||||
|
|
||||||
user = get_bitbucket_user(bitbucket_user_id)
|
|
||||||
|
|
||||||
if not all([comment_message, bitbucket_url, project_url]):
|
class PushEventHook(BaseBitBucketEventHook, BasePushEventHook):
|
||||||
raise ActionSyntaxException(_("Invalid issue comment information"))
|
def get_data(self):
|
||||||
|
result = []
|
||||||
issues = Issue.objects.filter(external_reference=["bitbucket", bitbucket_url])
|
changes = self.payload.get("push", {}).get('changes', [])
|
||||||
tasks = Task.objects.filter(external_reference=["bitbucket", bitbucket_url])
|
for change in filter(None, changes):
|
||||||
uss = UserStory.objects.filter(external_reference=["bitbucket", bitbucket_url])
|
for commit in change.get("commits", []):
|
||||||
|
message = commit.get("message")
|
||||||
for item in list(issues) + list(tasks) + list(uss):
|
result.append({
|
||||||
if number and subject and bitbucket_user_name and bitbucket_user_url:
|
'user_id': commit.get('author', {}).get('user', {}).get('uuid', None),
|
||||||
comment = _("Comment by [@{bitbucket_user_name}]({bitbucket_user_url} "
|
"user_name": commit.get('author', {}).get('user', {}).get('username', None),
|
||||||
"\"See @{bitbucket_user_name}'s BitBucket profile\") "
|
"user_url": commit.get('author', {}).get('user', {}).get('links', {}).get('html', {}).get('href'),
|
||||||
"from BitBucket.\nOrigin BitBucket issue: [bb#{number} - {subject}]({bitbucket_url} "
|
"commit_id": commit.get("hash", None),
|
||||||
"\"Go to 'bb#{number} - {subject}'\")\n\n"
|
"commit_url": commit.get("links", {}).get('html', {}).get('href'),
|
||||||
"{message}").format(bitbucket_user_name=bitbucket_user_name,
|
"commit_message": message.strip(),
|
||||||
bitbucket_user_url=bitbucket_user_url,
|
})
|
||||||
number=number,
|
return result
|
||||||
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)
|
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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"
|
||||||
|
platform_slug = "github"
|
||||||
|
|
||||||
|
def replace_github_references(self, project_url, wiki_text):
|
||||||
|
if wiki_text is None:
|
||||||
wiki_text = ""
|
wiki_text = ""
|
||||||
|
|
||||||
template = "\g<1>[GitHub#\g<2>]({}/issues/\g<2>)\g<3>".format(project_url)
|
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)
|
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)
|
|
||||||
|
|
|
@ -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
|
|
||||||
|
|
|
@ -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'
|
||||||
|
|
|
@ -19,78 +19,14 @@
|
||||||
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:
|
|
||||||
message = commit.get("message", None)
|
|
||||||
self._process_message(message, None)
|
|
||||||
|
|
||||||
def _process_message(self, message, gitlab_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, 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):
|
|
||||||
if wiki_text is None:
|
if wiki_text is None:
|
||||||
wiki_text = ""
|
wiki_text = ""
|
||||||
|
|
||||||
|
@ -98,79 +34,56 @@ def replace_gitlab_references(project_url, wiki_text):
|
||||||
return re.sub(r"(\s|^)#(\d+)(\s|$)", template, wiki_text, 0, re.M)
|
return re.sub(r"(\s|^)#(\d+)(\s|$)", template, wiki_text, 0, re.M)
|
||||||
|
|
||||||
|
|
||||||
class IssuesEventHook(BaseEventHook):
|
class IssuesEventHook(BaseGitLabEventHook, BaseNewIssueEventHook):
|
||||||
def process_event(self):
|
def ignore(self):
|
||||||
if self.payload.get('object_attributes', {}).get("action", "") != "open":
|
return self.payload.get('object_attributes', {}).get("action", "") != "open"
|
||||||
return
|
|
||||||
|
|
||||||
subject = self.payload.get('object_attributes', {}).get('title', None)
|
def get_data(self):
|
||||||
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)
|
|
||||||
|
|
|
@ -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
|
|
||||||
|
|
|
@ -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) == ""
|
||||||
|
|
|
@ -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) == ""
|
||||||
|
|
|
@ -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"] = [{
|
||||||
|
"message": """test message
|
||||||
test TG-%s #%s ok
|
test TG-%s #%s ok
|
||||||
bye!
|
bye!
|
||||||
""" % (issue.ref, new_status.slug)},
|
""" % (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) == ""
|
||||||
|
|
Loading…
Reference in New Issue