diff --git a/doc/configuration.rst b/doc/configuration.rst index 32fece0..51a112d 100644 --- a/doc/configuration.rst +++ b/doc/configuration.rst @@ -891,6 +891,33 @@ Defaults to: ``['pretty please pagure-ci rebuild']`` .. note:: The sentences defined in this configuration key should be lower case only! +FLAG_STATUSES_LABELS +~~~~~~~~~~~~~~~~~~~~ + +By default, Pagure has ``success``, ``failure``, ``error``, ``pending`` and +``canceled`` statuses of PR and commit flags. This setting allows you to +define a custom mapping of statuses to their respective Bootstrap labels. + +FLAG_SUCCESS +~~~~~~~~~~~~ + +Holds name of PR/commit flag that is considered a success. + +Defaults to: ``success`` + +FLAG_FAILURE +~~~~~~~~~~~~ + +Holds name of PR/commit flag that is considered a failure. + +Defaults to: ``failure`` + +FLAG_PENDING +~~~~~~~~~~~~ + +Holds name of PR/commit flag that is considered a pending state. + +Defaults to: ``pending`` EXTERNAL_COMMITTER ~~~~~~~~~~~~~~~~~~ diff --git a/pagure/api/fork.py b/pagure/api/fork.py index f3c0439..eedd6f3 100644 --- a/pagure/api/fork.py +++ b/pagure/api/fork.py @@ -626,15 +626,17 @@ def api_pull_request_add_flag(repo, requestid, username=None, namespace=None): | | | | of this flag | +---------------+---------+--------------+-----------------------------+ | ``status`` | string | Optional | | The status of the task, | - | | | | can be any of: success, | - | | | | failure, error, pending, | - | | | | canceled | - | | | | If not provided it will be| - | | | | set to ``success`` if | - | | | | percent is higher than 0, | - | | | | ``failure`` if it is 0 and| - | | | | ``pending`` if percent is | - | | | | not specified | + | | | | can be any of: | + | | | | $$FLAG_STATUSES_COMMAS$$ | + | | | | If not provided it will | + | | | | be set to | + | | | | ``$$FLAG_SUCCESS$$`` if | + | | | | percent is higher than 0 | + | | | | ``$$FLAG_FAILURE$$`` if | + | | | | it is 0 and | + | | | | ``$$FLAG_PENDING$$`` | + | | | | if percent is not | + | | | | specified | +---------------+---------+--------------+-----------------------------+ | ``percent`` | int | Optional | | A percentage of | | | | | completion compared to | @@ -738,9 +740,10 @@ def api_pull_request_add_flag(repo, requestid, username=None, namespace=None): status = form.status.data.strip() else: if percent is None: - status = 'pending' + status = pagure_config['FLAG_PENDING'] else: - status = 'success' if percent != '0' else 'failure' + status = pagure_config['FLAG_SUCCESS'] if percent != '0' else \ + pagure_config['FLAG_FAILURE'] try: # New Flag message, uid = pagure.lib.add_pull_request_flag( diff --git a/pagure/api/project.py b/pagure/api/project.py index f4d72b6..d0910ca 100644 --- a/pagure/api/project.py +++ b/pagure/api/project.py @@ -1351,9 +1351,8 @@ def api_commit_add_flag(repo, commit_hash, username=None, namespace=None): | | | | of this flag | +---------------+---------+--------------+-----------------------------+ | ``status`` | string | Mandatory | | The status of the task, | - | | | | can be any of: success, | - | | | | failure, error, pending, | - | | | | canceled | + | | | | can be any of: | + | | | | $$FLAG_STATUSES_COMMAS$$ | +---------------+---------+--------------+-----------------------------+ | ``percent`` | int | Optional | | A percentage of | | | | | completion compared to | diff --git a/pagure/default_config.py b/pagure/default_config.py index 18c179f..271a56f 100644 --- a/pagure/default_config.py +++ b/pagure/default_config.py @@ -314,6 +314,17 @@ EXCLUDE_GROUP_INDEX = [] TRIGGER_CI = ['pretty please pagure-ci rebuild'] +FLAG_STATUSES_LABELS = { + 'success': 'label-success', + 'failure': 'label-danger', + 'error': 'label-danger', + 'pending': 'label-info', + 'canceled': 'label-warning', +} +FLAG_SUCCESS = 'success' +FLAG_FAILURE = 'failure' +FLAG_PENDING = 'pending' + # Never enable this option, this is intended for tests only, and can allow # easy denial of service to the system if enabled. ALLOW_PROJECT_DOWAIT = False diff --git a/pagure/doc_utils.py b/pagure/doc_utils.py index 9d0d483..dc3fb14 100644 --- a/pagure/doc_utils.py +++ b/pagure/doc_utils.py @@ -17,6 +17,7 @@ import kitchen.text.converters as ktc import markupsafe import textwrap +from pagure.config import config as pagure_config import pagure.lib import pagure.lib.encoding_utils @@ -63,6 +64,11 @@ def modify_html(html): substitutions = { '': '', '': '', + '$$FLAG_STATUSES_COMMAS$$': + ', '.join(sorted(pagure_config['FLAG_STATUSES_LABELS'].keys())), + '$$FLAG_SUCCESS$$': pagure_config['FLAG_SUCCESS'], + '$$FLAG_FAILURE$$': pagure_config['FLAG_FAILURE'], + '$$FLAG_PENDING$$': pagure_config['FLAG_PENDING'], } for old, new in substitutions.items(): html = html.replace(old, new) diff --git a/pagure/forms.py b/pagure/forms.py index c0a68fd..0afd626 100644 --- a/pagure/forms.py +++ b/pagure/forms.py @@ -488,16 +488,20 @@ class AddPullRequestFlagFormV1(PagureForm): class AddPullRequestFlagForm(AddPullRequestFlagFormV1): ''' Form to add a flag to a pull-request or commit. ''' + def __init__(self, *args, **kwargs): + # we need to instantiate dynamically because the configuration + # values may change during tests and we want to always respect + # the currently set value + super(AddPullRequestFlagForm, self).__init__(*args, **kwargs) + self.status.choices = list(zip( + pagure_config['FLAG_STATUSES_LABELS'].keys(), + pagure_config['FLAG_STATUSES_LABELS'].keys() + )) + status = wtforms.SelectField( 'status', [wtforms.validators.Required()], - choices=[ - ('success', 'success'), - ('failure', 'failure'), - ('error', 'error'), - ('canceled', 'canceled'), - ('pending', 'pending'), - ], + choices=[], ) diff --git a/pagure/ui/filters.py b/pagure/ui/filters.py index 45c8378..8794b0c 100644 --- a/pagure/ui/filters.py +++ b/pagure/ui/filters.py @@ -663,11 +663,4 @@ def table_get_link_order(column, order_key, order): def flag_to_label(flag): """ For a given flag return the bootstrap label to use """ - status = { - 'success': 'label-success', - 'failure': 'label-danger', - 'error': 'label-danger', - 'pending': 'label-info', - 'canceled': 'label-warning', - } - return status[flag.status.lower()] + return pagure_config['FLAG_STATUSES_LABELS'][flag.status.lower()] diff --git a/tests/test_pagure_flask_api_pr_flag.py b/tests/test_pagure_flask_api_pr_flag.py index d711e8e..9f1b47e 100644 --- a/tests/test_pagure_flask_api_pr_flag.py +++ b/tests/test_pagure_flask_api_pr_flag.py @@ -19,6 +19,7 @@ sys.path.insert(0, os.path.join(os.path.dirname( os.path.abspath(__file__)), '..')) import pagure # noqa +import pagure.config # noqa import pagure.lib # noqa import tests # noqa @@ -425,6 +426,76 @@ class PagureFlaskApiPRFlagtests(tests.Modeltests): self.assertEqual(request.flags[1].comment, 'Tests running again') self.assertEqual(request.flags[1].percent, None) + @patch.dict('pagure.config.config', + { + 'FLAG_STATUSES_LABELS': + { + 'pend!': 'label-info', + 'succeed!': 'label-success', + 'fail!': 'label-danger', + 'what?': 'label-warning', + }, + 'FLAG_PENDING': 'pend!', + 'FLAG_SUCCESS': 'succeed!', + 'FLAG_FAILURE': 'fail!', + }) + def test_flagging_a_pull_request_while_having_custom_statuses(self): + """ Test flagging a PR while having custom statuses. """ + headers = {'Authorization': 'token aaabbbcccddd'} + + # No status and no percent => should use FLAG_PENDING + send_data = { + 'username': 'Jenkins', + 'comment': 'Tests running', + 'url': 'http://jenkins.cloud.fedoraproject.org/', + 'uid': 'jenkins_build_pagure_100+seed', + } + + output = self.app.post( + '/api/0/test/pull-request/1/flag', data=send_data, headers=headers) + data = json.loads(output.data) + self.assertEqual(output.status_code, 200) + self.assertEqual(data['flag']['status'], 'pend!') + + # No status and 50 % => should use FLAG_SUCCESS + send_data['percent'] = 50 + output = self.app.post( + '/api/0/test/pull-request/1/flag', data=send_data, headers=headers) + data = json.loads(output.data) + self.assertEqual(output.status_code, 200) + self.assertEqual(data['flag']['status'], 'succeed!') + + # No status and 0 % => should use FLAG_FAILURE + send_data['percent'] = 0 + output = self.app.post( + '/api/0/test/pull-request/1/flag', data=send_data, headers=headers) + data = json.loads(output.data) + self.assertEqual(output.status_code, 200) + self.assertEqual(data['flag']['status'], 'fail!') + + # Explicitly set status + send_data['status'] = 'what?' + output = self.app.post( + '/api/0/test/pull-request/1/flag', data=send_data, headers=headers) + data = json.loads(output.data) + self.assertEqual(output.status_code, 200) + self.assertEqual(data['flag']['status'], 'what?') + + # Explicitly set wrong status + send_data['status'] = 'nooo.....' + output = self.app.post( + '/api/0/test/pull-request/1/flag', data=send_data, headers=headers) + data = json.loads(output.data) + self.assertEqual(output.status_code, 400) + self.assertDictEqual( + data, + { + "error": "Invalid or incomplete input submitted", + "error_code": "EINVALIDREQ", + "errors": {"status": ["Not a valid choice"]} + } + ) + class PagureFlaskApiPRFlagUserTokentests(tests.Modeltests): """ Tests for the flask API of pagure for flagging pull-requests using diff --git a/tests/test_pagure_flask_api_project.py b/tests/test_pagure_flask_api_project.py index 742425d..665bef8 100644 --- a/tests/test_pagure_flask_api_project.py +++ b/tests/test_pagure_flask_api_project.py @@ -3108,6 +3108,56 @@ class PagureFlaskApiProjectFlagtests(tests.Modeltests): user_from=u'Jenkins' ) + @patch.dict('pagure.config.config', + { + 'FLAG_STATUSES_LABELS': + { + 'pend!': 'label-info', + 'succeed!': 'label-success', + 'fail!': 'label-danger', + 'what?': 'label-warning', + }, + 'FLAG_PENDING': 'pend!', + 'FLAG_SUCCESS': 'succeed!', + 'FLAG_FAILURE': 'fail!', + }) + def test_flag_commit_with_custom_flags(self): + """ Test flagging when custom flags are set up + """ + repo_obj = pygit2.Repository(self.git_path) + commit = repo_obj.revparse_single('HEAD') + + headers = {'Authorization': 'token aaabbbcccddd'} + send_data = { + 'username': 'Jenkins', + 'percent': 100, + 'comment': 'Tests passed', + 'url': 'http://jenkins.cloud.fedoraproject.org/', + 'status': 'succeed!', + } + output = self.app.post( + '/api/0/test/c/%s/flag' % commit.oid.hex, + headers=headers, data=send_data) + self.assertEqual(output.status_code, 200) + data = json.loads(output.data) + self.assertEqual(data['flag']['status'], 'succeed!') + + # Try invalid flag status + send_data['status'] = 'nooooo....' + output = self.app.post( + '/api/0/test/c/%s/flag' % commit.oid.hex, + headers=headers, data=send_data) + self.assertEqual(output.status_code, 400) + data = json.loads(output.data) + self.assertEqual( + data, + { + u'errors': {u'status': [u'Not a valid choice']}, + u'error_code': u'EINVALIDREQ', + u'error': u'Invalid or incomplete input submitted' + } + ) + if __name__ == '__main__': unittest.main(verbosity=2) diff --git a/tests/test_pagure_flask_ui_repo_flag_commit.py b/tests/test_pagure_flask_ui_repo_flag_commit.py index 6b6c267..482f3b2 100644 --- a/tests/test_pagure_flask_ui_repo_flag_commit.py +++ b/tests/test_pagure_flask_ui_repo_flag_commit.py @@ -12,6 +12,7 @@ import unittest import sys import os +from mock import patch import pygit2 sys.path.insert(0, os.path.join(os.path.dirname( @@ -263,6 +264,55 @@ class ViewCommitFlagtests(tests.SimplePagureTest): self.assertIn( 'Build canceled', output.data) + @patch.dict('pagure.config.config', + { + 'FLAG_STATUSES_LABELS': + { + 'status1': 'label-warning', + 'otherstatus': 'label-success', + }, + }) + def test_view_commit_with_custom_flags(self): + """ Test the view_commit endpoint while having custom flags. """ + repo = pagure.lib.get_authorized_project(self.session, 'test') + + msg = pagure.lib.add_commit_flag( + session=self.session, + repo=repo, + commit_hash=self.commit.oid.hex, + username='simple-koji-ci', + status='status1', + percent=None, + comment='Build canceled', + url='https://koji.fp.o/koji...', + uid='uid', + user='foo', + token='aaabbbcccddd' + ) + self.session.commit() + self.assertEqual(msg, ('Flag added', 'uid')) + + # View first commit + output = self.app.get('/test/c/%s' % self.commit.oid.hex) + self.assertEqual(output.status_code, 200) + self.assertIn( + 'Commit - test - %s - Pagure' % self.commit.oid.hex, + output.data) + self.assertIn( + '