Skip to content

Commit

Permalink
[api] Bug.create() now accepts new parameter auto_report=False
Browse files Browse the repository at this point in the history
- when auto_report=True will automatically try to comment on the
issue using IssueTracker integrations.

- front-end now uses this new RPC instead of legacy AJAX view.
  Fixes #18
  • Loading branch information
atodorov committed Feb 8, 2019
1 parent 2541cdb commit 552d918
Show file tree
Hide file tree
Showing 8 changed files with 41 additions and 154 deletions.
2 changes: 2 additions & 0 deletions tcms/core/ajax.py
Original file line number Diff line number Diff line change
Expand Up @@ -243,6 +243,8 @@ def update_bugs_to_caseruns(request):
if action == "add":
for run in runs:
for bug_id in bug_ids:
# todo: TestCaseRun.add_bug and TestCase.add_bug should be removed
# once this function has been refactored to JSON RPC
run.add_bug(bug_id=bug_id,
bug_system_id=bug_system_id,
bz_external_track=bz_external_track)
Expand Down
2 changes: 2 additions & 0 deletions tcms/core/utils/validations.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@
)


# todo: scheduled for removal together with validation regexes
# and validateIssueID on the JavaScript side
def validate_bug_id(bug_id, bug_system_id):
if not isinstance(bug_id, (str, list, tuple)):
raise ValidationError('Type error of bug_id.')
Expand Down
1 change: 0 additions & 1 deletion tcms/static/js/tcms_actions.js
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,6 @@ var default_messages = {
logout: '/accounts/logout/',

case_details: '/case/$id/',
case_run_bug: '/runs/$id/bug/',
search_case: '/cases/',
},

Expand Down
63 changes: 20 additions & 43 deletions tcms/static/js/testrun_actions.js
Original file line number Diff line number Diff line change
Expand Up @@ -435,7 +435,8 @@ AddIssueDialog.prototype.show = function () {

AddIssueDialog.prototype.get_data = function () {
var form_data = Nitrate.Utils.formSerialize(this.form);
form_data.bug_validation_regexp = jQ('#bug_system_id option:selected').data('validation-regexp');
form_data.bug_validation_regexp = $('#bug_system_id option:selected').data('validation-regexp');
form_data.bz_external_track = $('input[name=bz_external_track]').is(':checked');
return form_data;
};

Expand Down Expand Up @@ -465,9 +466,8 @@ function fileCaseRunBug(run_id, title_container, container, case_id, case_run_id
dialog.show();
}

function addCaseRunBug(run_id, title_container, container, case_id, case_run_id, callback) {
function addCaseRunBug(run_id, title_container, container, case_id, case_run_id) {
var dialog = new AddIssueDialog({
'extraFormHiddenData': { 'case_run': case_run_id, 'case': case_id },
'onSubmit': function (e, dialog) {
e.stopPropagation();
e.preventDefault();
Expand All @@ -479,46 +479,23 @@ function addCaseRunBug(run_id, title_container, container, case_id, case_run_id,
return;
}

if (!validateIssueID(form_data.bug_validation_regexp, form_data.bug_id)) {
return false;
}

var success_callback = function(t) {
jQ('#dialog').hide();
var returnobj = t;

if (returnobj.rc === 0) {
if (callback) {
return callback();
}

// Update bugs count associated with just updated case run
var jqCaserunBugCount = jQ('span#' + case_run_id + '_case_bug_count');
if (jqCaserunBugCount.text() == '0') {
jqCaserunBugCount.addClass('have_bug');
}
jqCaserunBugCount.text(returnobj.caserun_bugs_count);

// Update the total bugs count of this run
var html = null;
if (jQ('span#total_run_bug_count a').text() === 'No Bugs') {
html = "<a title='Show All Bugs' href='/runs/" + run_id + "/report/#buglist'>Bugs [" + returnobj.run_bug_count + "]</a>";
jQ('span#total_run_bug_count').html(html);
} else {
html = "Bugs [" + returnobj.run_bug_count + "]";
jQ('span#total_run_bug_count a').html(html);
}

return constructCaseRunZone(container, title_container, case_id);
} else {
window.alert(returnobj.response);
return false;
}
};

var url = Nitrate.http.URLConf.reverse({ 'name': 'case_run_bug', 'arguments': {'id': case_run_id} });

jQ.ajax({ url: url, dataType: 'json', data: form_data, success: success_callback });
jsonRPC('Bug.create', [{
case_id: case_id,
case_run_id: case_run_id,
bug_id: form_data.bug_id,
bug_system_id: form_data.bug_system_id
}, form_data.bz_external_track],
function(result) {
// todo: missing error handling when bz_external_track is true
$('#dialog').hide();

// Update bugs count associated with just updated case run
var jqCaserunBugCount = $('span#' + case_run_id + '_case_bug_count');
jqCaserunBugCount.addClass('have_bug');

// refresh the links of bugs
constructCaseRunZone(container, title_container, case_id);
});
}
});

Expand Down
43 changes: 0 additions & 43 deletions tcms/testruns/tests/test_views.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@
from django.urls import reverse
from django.contrib.auth.models import Permission

from tcms.testcases.models import BugSystem
from tcms.testruns.models import TestCaseRunStatus
from tcms.testruns.models import TestRun
from tcms.utils.permissions import initiate_user_with_default_setups
Expand Down Expand Up @@ -362,48 +361,6 @@ def test_refuse_if_user_not_exist(self):
self.assert_cc(response, [self.cc_user_2, self.cc_user_3])


class TestBugActions(BaseCaseRun):
"""Test bug view method"""

@classmethod
def setUpTestData(cls):
super(TestBugActions, cls).setUpTestData()

user_should_have_perm(cls.tester, 'testruns.change_testrun')
user_should_have_perm(cls.tester, 'testcases.delete_bug')

cls.bugzilla = BugSystem.objects.get(name='Bugzilla')
cls.jira = BugSystem.objects.get(name='JIRA')

cls.case_run_bug_url = reverse('testruns-bug', args=[cls.case_run_1.pk])

cls.bug_12345 = '12345'
cls.jira_kiwi_100 = 'KIWI-100'
cls.case_run_1.add_bug(cls.bug_12345, bug_system_id=cls.bugzilla.pk)
cls.case_run_1.add_bug(cls.jira_kiwi_100, bug_system_id=cls.jira.pk)

def test_404_if_case_run_id_not_exist(self):
self.case_run_bug_url = reverse('testruns-bug', args=[999])

response = self.client.get(self.case_run_bug_url, {})
self.assert404(response)

def test_refuse_if_action_is_unknown(self):
post_data = {
'a': 'unknown action',
'case_run': self.case_run_1.pk,
'case': self.case_run_1.case.pk,
'bug_system_id': BugSystem.objects.get(name='Bugzilla').pk,
'bug_id': '123456',
}

response = self.client.get(self.case_run_bug_url, post_data)

self.assertJsonResponse(
response,
{'rc': 1, 'response': 'Unrecognizable actions'})


class TestRemoveCaseRuns(BaseCaseRun):
"""Test remove_case_run view method"""

Expand Down
2 changes: 0 additions & 2 deletions tcms/testruns/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,4 @@
name='testruns-update_caserun_status'),

url(r'^search/$', views.search, name='testruns-search'),

url(r'^(?P<case_run_id>\d+)/bug/$', views.bug, name='testruns-bug'),
]
62 changes: 0 additions & 62 deletions tcms/testruns/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@
from django.urls import reverse
from django.db.models import Count
from django.db.models import Q
from django.forms import ValidationError
from django.http import HttpResponseRedirect, Http404, JsonResponse
from django.shortcuts import get_object_or_404, render
from django.utils.decorators import method_decorator
Expand All @@ -25,7 +24,6 @@
from django_comments.models import Comment

from tcms.core.utils import clean_request
from tcms.core.utils.validations import validate_bug_id
from tcms.management.models import Priority, Tag
from tcms.testcases.models import TestCasePlan, TestCaseStatus, BugSystem
from tcms.testcases.views import get_selected_testcases
Expand Down Expand Up @@ -400,66 +398,6 @@ def get_context_data(self, **kwargs):
return context


@require_GET
@permission_required('testruns.change_testrun')
def bug(request, case_run_id):
"""Process the bugs for case runs."""

class CaseRunBugActions:

def __init__(self, request, case_run):
self.request = request
self.case_run = case_run

def add(self):
if not self.request.user.has_perm('testcases.add_bug'):
return JsonResponse({'rc': 1, 'response': 'Permission denied'})

bug_id = request.GET.get('bug_id')
bug_system_id = request.GET.get('bug_system_id')

try:
validate_bug_id(bug_id, bug_system_id)
except ValidationError as error:
return JsonResponse({'rc': 1,
'response': str(error)})

bz_external_track = bool(request.GET.get('bz_external_track', False))

try:
test_case_run.add_bug(bug_id=bug_id,
bug_system_id=bug_system_id,
bz_external_track=bz_external_track)
except ValueError as error:
msg = str(error) if str(error) else 'Failed to add bug %s' % bug_id
return JsonResponse({'rc': 1,
'response': msg})

return JsonResponse({'rc': 0,
'response': 'ok',
'run_bug_count': self.get_run_bug_count(),
'caserun_bugs_count': self.case_run.get_bugs_count()})

def get_run_bug_count(self):
run = self.case_run.run
return run.get_bug_count()

try:
test_case_run = TestCaseRun.objects.get(case_run_id=case_run_id)
except ObjectDoesNotExist:
raise Http404

case_run_bug_actions = CaseRunBugActions(request=request,
case_run=test_case_run)

func = getattr(case_run_bug_actions, request.GET['a'], None)
if func is None:
return JsonResponse({'rc': 1,
'response': 'Unrecognizable actions'})

return func()


@require_POST
def clone(request, run_id):
"""Clone cases from filter caserun"""
Expand Down
20 changes: 17 additions & 3 deletions tcms/xmlrpc/api/bug.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,14 +43,16 @@ def filter(query): # pylint: disable=redefined-builtin

@permissions_required('testcases.add_bug')
@rpc_method(name='Bug.create')
def create(values):
def create(values, auto_report=False):
"""
.. function:: XML-RPC Bug.create(values)
.. function:: XML-RPC Bug.create(values, auto_report=False)
Attach a bug to pre-existing TestCase or TestCaseRun object.
:param values: Field values for :class:`tcms.testcases.models.Bug`
:type values: dict
:param auto_report: Automatically report to Issue Tracker
:type auto_report: bool, default=False
:return: Serialized :class:`tcms.testcases.models.Bug` object
:raises: PermissionDenied if missing the *testcases.add_bug* permission
Expand All @@ -70,7 +72,19 @@ def create(values):
})
"""
bug, _ = Bug.objects.get_or_create(**values)
return bug.serialize()
response = bug.serialize()
response['rc'] = 0

if auto_report:
tracker = IssueTrackerType.from_name(bug.bug_system.tracker_type)(bug.bug_system)

if not tracker.is_adding_testcase_to_issue_disabled():
tracker.add_testcase_to_issue([bug.case], bug)
else:
response['rc'] = 1
response['response'] = _('Enable linking test cases by configuring '
'API parameters for this Issue Tracker!')
return response


@permissions_required('testcases.delete_bug')
Expand Down

0 comments on commit 552d918

Please sign in to comment.