Support for updating epic status via commit message
parent
564cd43504
commit
4e50135234
|
@ -20,7 +20,8 @@ import re
|
||||||
|
|
||||||
from django.utils.translation import ugettext as _
|
from django.utils.translation import ugettext as _
|
||||||
from django.contrib.auth import get_user_model
|
from django.contrib.auth import get_user_model
|
||||||
from taiga.projects.models import IssueStatus, TaskStatus, UserStoryStatus
|
from taiga.projects.models import IssueStatus, TaskStatus, UserStoryStatus, EpicStatus
|
||||||
|
from taiga.projects.epics.models import Epic
|
||||||
from taiga.projects.issues.models import Issue
|
from taiga.projects.issues.models import Issue
|
||||||
from taiga.projects.tasks.models import Task
|
from taiga.projects.tasks.models import Task
|
||||||
from taiga.projects.userstories.models import UserStory
|
from taiga.projects.userstories.models import UserStory
|
||||||
|
@ -189,7 +190,10 @@ class BasePushEventHook(BaseEventHook):
|
||||||
return _simple_status_change_message.format(platform=self.platform)
|
return _simple_status_change_message.format(platform=self.platform)
|
||||||
|
|
||||||
def get_item_classes(self, ref):
|
def get_item_classes(self, ref):
|
||||||
if Issue.objects.filter(project=self.project, ref=ref).exists():
|
if Epic.objects.filter(project=self.project, ref=ref).exists():
|
||||||
|
modelClass = Epic
|
||||||
|
statusClass = EpicStatus
|
||||||
|
elif Issue.objects.filter(project=self.project, ref=ref).exists():
|
||||||
modelClass = Issue
|
modelClass = Issue
|
||||||
statusClass = IssueStatus
|
statusClass = IssueStatus
|
||||||
elif Task.objects.filter(project=self.project, ref=ref).exists():
|
elif Task.objects.filter(project=self.project, ref=ref).exists():
|
||||||
|
|
|
@ -116,6 +116,10 @@ class RelatedUserStory(WatchedModelMixin, models.Model):
|
||||||
def project_id(self):
|
def project_id(self):
|
||||||
return self.epic.project_id
|
return self.epic.project_id
|
||||||
|
|
||||||
|
@property
|
||||||
|
def owner(self):
|
||||||
|
return self.epic.owner
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def owner_id(self):
|
def owner_id(self):
|
||||||
return self.epic.owner_id
|
return self.epic.owner_id
|
||||||
|
|
|
@ -80,7 +80,7 @@ _values_impl_map = {}
|
||||||
# Not important fields for models (history entries with only
|
# Not important fields for models (history entries with only
|
||||||
# this fields are marked as hidden).
|
# this fields are marked as hidden).
|
||||||
_not_important_fields = {
|
_not_important_fields = {
|
||||||
"epics.epic": frozenset(["epics_order"]),
|
"epics.epic": frozenset(["epics_order", "user_stories"]),
|
||||||
"userstories.userstory": frozenset(["backlog_order", "sprint_order", "kanban_order"]),
|
"userstories.userstory": frozenset(["backlog_order", "sprint_order", "kanban_order"]),
|
||||||
"tasks.task": frozenset(["us_order", "taskboard_order"]),
|
"tasks.task": frozenset(["us_order", "taskboard_order"]),
|
||||||
}
|
}
|
||||||
|
|
|
@ -242,31 +242,31 @@ def test_epic_related_userstories_create(client, data):
|
||||||
]
|
]
|
||||||
|
|
||||||
create_data = json.dumps({
|
create_data = json.dumps({
|
||||||
"user_story": data.public_us.id,
|
"user_story": f.UserStoryFactory(project=data.public_project).id,
|
||||||
"epic": data.public_epic.id
|
"epic": data.public_epic.id
|
||||||
})
|
})
|
||||||
url = reverse('epics-related-userstories-list', args=[data.public_epic.pk])
|
url = reverse('epics-related-userstories-list', args=[data.public_epic.pk])
|
||||||
results = helper_test_http_method(client, 'post', url, create_data, users)
|
results = helper_test_http_method(client, 'post', url, create_data, users)
|
||||||
assert results == [401, 403, 403, 201, 201]
|
assert results == [401, 403, 403, 201, 400]
|
||||||
|
|
||||||
create_data = json.dumps({
|
create_data = json.dumps({
|
||||||
"user_story": data.private_us1.id,
|
"user_story": f.UserStoryFactory(project=data.private_project1).id,
|
||||||
"epic": data.private_epic1.id
|
"epic": data.private_epic1.id
|
||||||
})
|
})
|
||||||
url = reverse('epics-related-userstories-list', args=[data.private_epic1.pk])
|
url = reverse('epics-related-userstories-list', args=[data.private_epic1.pk])
|
||||||
results = helper_test_http_method(client, 'post', url, create_data, users)
|
results = helper_test_http_method(client, 'post', url, create_data, users)
|
||||||
assert results == [401, 403, 403, 201, 201]
|
assert results == [401, 403, 403, 201, 400]
|
||||||
|
|
||||||
create_data = json.dumps({
|
create_data = json.dumps({
|
||||||
"user_story": data.private_us2.id,
|
"user_story": f.UserStoryFactory(project=data.private_project2).id,
|
||||||
"epic": data.private_epic2.id
|
"epic": data.private_epic2.id
|
||||||
})
|
})
|
||||||
url = reverse('epics-related-userstories-list', args=[data.private_epic2.pk])
|
url = reverse('epics-related-userstories-list', args=[data.private_epic2.pk])
|
||||||
results = helper_test_http_method(client, 'post', url, create_data, users)
|
results = helper_test_http_method(client, 'post', url, create_data, users)
|
||||||
assert results == [401, 403, 403, 201, 201]
|
assert results == [401, 403, 403, 201, 400]
|
||||||
|
|
||||||
create_data = json.dumps({
|
create_data = json.dumps({
|
||||||
"user_story": data.blocked_us.id,
|
"user_story": f.UserStoryFactory(project=data.blocked_project).id,
|
||||||
"epic": data.blocked_epic.id
|
"epic": data.blocked_epic.id
|
||||||
})
|
})
|
||||||
url = reverse('epics-related-userstories-list', args=[data.blocked_epic.pk])
|
url = reverse('epics-related-userstories-list', args=[data.blocked_epic.pk])
|
||||||
|
@ -379,14 +379,29 @@ def test_bulk_create_related_userstories(client, data):
|
||||||
]
|
]
|
||||||
|
|
||||||
bulk_data = json.dumps({
|
bulk_data = json.dumps({
|
||||||
"userstories": "test1\ntest2",
|
"bulk_userstories": "test1\ntest2",
|
||||||
|
"project_id": data.public_project.id
|
||||||
})
|
})
|
||||||
|
|
||||||
results = helper_test_http_method(client, 'post', public_url, bulk_data, users)
|
results = helper_test_http_method(client, 'post', public_url, bulk_data, users)
|
||||||
assert results == [401, 403, 403, 200, 200]
|
assert results == [401, 403, 403, 200, 200]
|
||||||
|
|
||||||
|
bulk_data = json.dumps({
|
||||||
|
"bulk_userstories": "test1\ntest2",
|
||||||
|
"project_id": data.private_project1.id
|
||||||
|
})
|
||||||
results = helper_test_http_method(client, 'post', private_url1, bulk_data, users)
|
results = helper_test_http_method(client, 'post', private_url1, bulk_data, users)
|
||||||
assert results == [401, 403, 403, 200, 200]
|
assert results == [401, 403, 403, 200, 200]
|
||||||
|
|
||||||
|
bulk_data = json.dumps({
|
||||||
|
"bulk_userstories": "test1\ntest2",
|
||||||
|
"project_id": data.private_project2.id
|
||||||
|
})
|
||||||
results = helper_test_http_method(client, 'post', private_url2, bulk_data, users)
|
results = helper_test_http_method(client, 'post', private_url2, bulk_data, users)
|
||||||
assert results == [401, 403, 403, 200, 200]
|
assert results == [401, 403, 403, 200, 200]
|
||||||
|
|
||||||
|
bulk_data = json.dumps({
|
||||||
|
"bulk_userstories": "test1\ntest2",
|
||||||
|
"project_id": data.blocked_project.id
|
||||||
|
})
|
||||||
results = helper_test_http_method(client, 'post', blocked_url, bulk_data, users)
|
results = helper_test_http_method(client, 'post', blocked_url, bulk_data, users)
|
||||||
assert results == [401, 403, 403, 451, 451]
|
assert results == [401, 403, 403, 451, 451]
|
||||||
|
|
|
@ -31,6 +31,7 @@ from taiga.hooks.bitbucket import event_hooks
|
||||||
from taiga.hooks.bitbucket.api import BitBucketViewSet
|
from taiga.hooks.bitbucket.api import BitBucketViewSet
|
||||||
from taiga.hooks.exceptions import ActionSyntaxException
|
from taiga.hooks.exceptions import ActionSyntaxException
|
||||||
from taiga.projects import choices as project_choices
|
from taiga.projects import choices as project_choices
|
||||||
|
from taiga.projects.epics.models import Epic
|
||||||
from taiga.projects.issues.models import Issue
|
from taiga.projects.issues.models import Issue
|
||||||
from taiga.projects.tasks.models import Task
|
from taiga.projects.tasks.models import Task
|
||||||
from taiga.projects.userstories.models import UserStory
|
from taiga.projects.userstories.models import UserStory
|
||||||
|
@ -239,6 +240,38 @@ def test_push_event_detected(client):
|
||||||
assert response.status_code == 204
|
assert response.status_code == 204
|
||||||
|
|
||||||
|
|
||||||
|
def test_push_event_epic_processing(client):
|
||||||
|
creation_status = f.EpicStatusFactory()
|
||||||
|
role = f.RoleFactory(project=creation_status.project, permissions=["view_epics"])
|
||||||
|
f.MembershipFactory(project=creation_status.project, role=role, user=creation_status.project.owner)
|
||||||
|
new_status = f.EpicStatusFactory(project=creation_status.project)
|
||||||
|
epic = f.EpicFactory.create(status=creation_status, project=creation_status.project, owner=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 #%s ok bye!" % (epic.ref, new_status.slug) }
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
mail.outbox = []
|
||||||
|
ev_hook = event_hooks.PushEventHook(epic.project, payload)
|
||||||
|
ev_hook.process_event()
|
||||||
|
epic = Epic.objects.get(id=epic.id)
|
||||||
|
assert epic.status.id == new_status.id
|
||||||
|
assert len(mail.outbox) == 1
|
||||||
|
|
||||||
|
|
||||||
def test_push_event_issue_processing(client):
|
def test_push_event_issue_processing(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"])
|
||||||
|
@ -534,6 +567,36 @@ def test_push_event_task_bad_processing_non_existing_ref(client):
|
||||||
assert len(mail.outbox) == 0
|
assert len(mail.outbox) == 0
|
||||||
|
|
||||||
|
|
||||||
|
def test_push_event_task_bad_processing_non_existing_ref(client):
|
||||||
|
issue_status = f.IssueStatusFactory()
|
||||||
|
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-6666666 #%s ok bye!" % (issue_status.slug) }
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
mail.outbox = []
|
||||||
|
|
||||||
|
ev_hook = event_hooks.PushEventHook(issue_status.project, payload)
|
||||||
|
with pytest.raises(ActionSyntaxException) as excinfo:
|
||||||
|
ev_hook.process_event()
|
||||||
|
|
||||||
|
assert str(excinfo.value) == "The referenced element doesn't exist"
|
||||||
|
assert len(mail.outbox) == 0
|
||||||
|
|
||||||
|
|
||||||
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 = {
|
||||||
|
|
|
@ -29,6 +29,7 @@ from taiga.hooks.github import event_hooks
|
||||||
from taiga.hooks.github.api import GitHubViewSet
|
from taiga.hooks.github.api import GitHubViewSet
|
||||||
from taiga.hooks.exceptions import ActionSyntaxException
|
from taiga.hooks.exceptions import ActionSyntaxException
|
||||||
from taiga.projects import choices as project_choices
|
from taiga.projects import choices as project_choices
|
||||||
|
from taiga.projects.epics.models import Epic
|
||||||
from taiga.projects.issues.models import Issue
|
from taiga.projects.issues.models import Issue
|
||||||
from taiga.projects.tasks.models import Task
|
from taiga.projects.tasks.models import Task
|
||||||
from taiga.projects.userstories.models import UserStory
|
from taiga.projects.userstories.models import UserStory
|
||||||
|
@ -111,6 +112,26 @@ def test_push_event_detected(client):
|
||||||
assert response.status_code == 204
|
assert response.status_code == 204
|
||||||
|
|
||||||
|
|
||||||
|
def test_push_event_epic_processing(client):
|
||||||
|
creation_status = f.EpicStatusFactory()
|
||||||
|
role = f.RoleFactory(project=creation_status.project, permissions=["view_epics"])
|
||||||
|
f.MembershipFactory(project=creation_status.project, role=role, user=creation_status.project.owner)
|
||||||
|
new_status = f.EpicStatusFactory(project=creation_status.project)
|
||||||
|
epic = f.EpicFactory.create(status=creation_status, project=creation_status.project, owner=creation_status.project.owner)
|
||||||
|
payload = {"commits": [
|
||||||
|
{"message": """test message
|
||||||
|
test TG-%s #%s ok
|
||||||
|
bye!
|
||||||
|
""" % (epic.ref, new_status.slug)},
|
||||||
|
]}
|
||||||
|
mail.outbox = []
|
||||||
|
ev_hook = event_hooks.PushEventHook(epic.project, payload)
|
||||||
|
ev_hook.process_event()
|
||||||
|
epic = Epic.objects.get(id=epic.id)
|
||||||
|
assert epic.status.id == new_status.id
|
||||||
|
assert len(mail.outbox) == 1
|
||||||
|
|
||||||
|
|
||||||
def test_push_event_issue_processing(client):
|
def test_push_event_issue_processing(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"])
|
||||||
|
|
|
@ -30,6 +30,7 @@ from taiga.hooks.gitlab import event_hooks
|
||||||
from taiga.hooks.gitlab.api import GitLabViewSet
|
from taiga.hooks.gitlab.api import GitLabViewSet
|
||||||
from taiga.hooks.exceptions import ActionSyntaxException
|
from taiga.hooks.exceptions import ActionSyntaxException
|
||||||
from taiga.projects import choices as project_choices
|
from taiga.projects import choices as project_choices
|
||||||
|
from taiga.projects.epics.models import Epic
|
||||||
from taiga.projects.issues.models import Issue
|
from taiga.projects.issues.models import Issue
|
||||||
from taiga.projects.tasks.models import Task
|
from taiga.projects.tasks.models import Task
|
||||||
from taiga.projects.userstories.models import UserStory
|
from taiga.projects.userstories.models import UserStory
|
||||||
|
@ -446,6 +447,30 @@ def test_push_event_detected(client):
|
||||||
assert response.status_code == 204
|
assert response.status_code == 204
|
||||||
|
|
||||||
|
|
||||||
|
def test_push_event_epic_processing(client):
|
||||||
|
creation_status = f.EpicStatusFactory()
|
||||||
|
role = f.RoleFactory(project=creation_status.project, permissions=["view_epics"])
|
||||||
|
f.MembershipFactory(project=creation_status.project, role=role, user=creation_status.project.owner)
|
||||||
|
new_status = f.EpicStatusFactory(project=creation_status.project)
|
||||||
|
epic = f.EpicFactory.create(status=creation_status, project=creation_status.project, owner=creation_status.project.owner)
|
||||||
|
payload = deepcopy(push_base_payload)
|
||||||
|
payload["commits"] = [{
|
||||||
|
"message": """test message
|
||||||
|
test TG-%s #%s ok
|
||||||
|
bye!
|
||||||
|
""" % (epic.ref, new_status.slug),
|
||||||
|
"id": "b6568db1bc1dcd7f8b4d5a946b0b91f9dacd7327",
|
||||||
|
"url": "http://example.com/mike/diaspora/commit/b6568db1bc1dcd7f8b4d5a946b0b91f9dacd7327",
|
||||||
|
}]
|
||||||
|
payload["total_commits_count"] = 1
|
||||||
|
mail.outbox = []
|
||||||
|
ev_hook = event_hooks.PushEventHook(epic.project, payload)
|
||||||
|
ev_hook.process_event()
|
||||||
|
epic = Epic.objects.get(id=epic.id)
|
||||||
|
assert epic.status.id == new_status.id
|
||||||
|
assert len(mail.outbox) == 1
|
||||||
|
|
||||||
|
|
||||||
def test_push_event_issue_processing(client):
|
def test_push_event_issue_processing(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"])
|
||||||
|
|
|
@ -29,6 +29,7 @@ from taiga.hooks.gogs import event_hooks
|
||||||
from taiga.hooks.gogs.api import GogsViewSet
|
from taiga.hooks.gogs.api import GogsViewSet
|
||||||
from taiga.hooks.exceptions import ActionSyntaxException
|
from taiga.hooks.exceptions import ActionSyntaxException
|
||||||
from taiga.projects import choices as project_choices
|
from taiga.projects import choices as project_choices
|
||||||
|
from taiga.projects.epics.models import Epic
|
||||||
from taiga.projects.issues.models import Issue
|
from taiga.projects.issues.models import Issue
|
||||||
from taiga.projects.tasks.models import Task
|
from taiga.projects.tasks.models import Task
|
||||||
from taiga.projects.userstories.models import UserStory
|
from taiga.projects.userstories.models import UserStory
|
||||||
|
@ -120,6 +121,36 @@ def test_push_event_detected(client):
|
||||||
assert response.status_code == 204
|
assert response.status_code == 204
|
||||||
|
|
||||||
|
|
||||||
|
def test_push_event_epic_processing(client):
|
||||||
|
creation_status = f.EpicStatusFactory()
|
||||||
|
role = f.RoleFactory(project=creation_status.project, permissions=["view_epics"])
|
||||||
|
f.MembershipFactory(project=creation_status.project, role=role, user=creation_status.project.owner)
|
||||||
|
new_status = f.EpicStatusFactory(project=creation_status.project)
|
||||||
|
epic = f.EpicFactory.create(status=creation_status, project=creation_status.project, owner=creation_status.project.owner)
|
||||||
|
payload = {
|
||||||
|
"commits": [
|
||||||
|
{
|
||||||
|
"message": """test message
|
||||||
|
test TG-%s #%s ok
|
||||||
|
bye!
|
||||||
|
""" % (epic.ref, new_status.slug),
|
||||||
|
"author": {
|
||||||
|
"username": "test",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"repository": {
|
||||||
|
"url": "http://test-url/test/project"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
mail.outbox = []
|
||||||
|
ev_hook = event_hooks.PushEventHook(epic.project, payload)
|
||||||
|
ev_hook.process_event()
|
||||||
|
epic = Epic.objects.get(id=epic.id)
|
||||||
|
assert epic.status.id == new_status.id
|
||||||
|
assert len(mail.outbox) == 1
|
||||||
|
|
||||||
|
|
||||||
def test_push_event_issue_processing(client):
|
def test_push_event_issue_processing(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"])
|
||||||
|
|
Loading…
Reference in New Issue