From c48bfdb9fcc5a8c12918ac806015afe808bd0a70 Mon Sep 17 00:00:00 2001 From: Pierre-Yves Chibon Date: Jun 01 2015 08:33:53 +0000 Subject: [PATCH 1/23] Add the PullRequestFlag object to the DB model --- diff --git a/pagure/lib/model.py b/pagure/lib/model.py index db434fc..4248d53 100644 --- a/pagure/lib/model.py +++ b/pagure/lib/model.py @@ -829,6 +829,57 @@ class PullRequestComment(BASE): return self.pull_request +class PullRequestFlag(BASE): + """ Stores the flags attached to a pull-request. + + Table -- pull_request_tags + """ + + __tablename__ = 'pull_request_tags' + + id = sa.Column(sa.Integer, primary_key=True) + pull_request_uid = sa.Column( + sa.Text, + sa.ForeignKey( + 'pull_requests.uid', ondelete='CASCADE', onupdate='CASCADE'), + nullable=False) + commit_id = sa.Column( + sa.String(40), + nullable=True, + index=True) + user_id = sa.Column( + sa.Integer, + sa.ForeignKey('users.id', onupdate='CASCADE'), + nullable=False, + index=True) + username = sa.Column( + sa.Text(), + nullable=False) + percent = sa.Column( + sa.Integer(), + nullable=False) + comment = sa.Column( + sa.Text(), + nullable=False) + + date_created = sa.Column(sa.DateTime, nullable=False, + default=datetime.datetime.utcnow) + + user = relation('User', foreign_keys=[user_id], + remote_side=[User.id], + backref=backref( + 'pull_request_flags', + order_by="PullRequestFlag.date_created")) + + pull_request = relation( + 'PullRequest', + backref=backref( + 'flags', cascade="delete, delete-orphan", + ), + foreign_keys=[pull_request_uid], + remote_side=[PullRequest.uid]) + + class PagureGroupType(BASE): """ A list of the type a group can have definition. From 1c061864f2886092e522e8ba5991795eb17d5dc6 Mon Sep 17 00:00:00 2001 From: Pierre-Yves Chibon Date: Jun 01 2015 08:33:53 +0000 Subject: [PATCH 2/23] Adjust the name of the pull_request_flags table --- diff --git a/pagure/lib/model.py b/pagure/lib/model.py index 4248d53..200cd0e 100644 --- a/pagure/lib/model.py +++ b/pagure/lib/model.py @@ -832,10 +832,10 @@ class PullRequestComment(BASE): class PullRequestFlag(BASE): """ Stores the flags attached to a pull-request. - Table -- pull_request_tags + Table -- pull_request_flags """ - __tablename__ = 'pull_request_tags' + __tablename__ = 'pull_request_flags' id = sa.Column(sa.Integer, primary_key=True) pull_request_uid = sa.Column( From 0c1b4c9c8e5a8fb528e5a4dc6275f127e7b8a26e Mon Sep 17 00:00:00 2001 From: Pierre-Yves Chibon Date: Jun 01 2015 08:33:53 +0000 Subject: [PATCH 3/23] Add a toRGB filter converting a percentage to a RGB color Thanks to @puiterwijk for the work on this one --- diff --git a/pagure/ui/filters.py b/pagure/ui/filters.py index 276cc06..fe6e79f 100644 --- a/pagure/ui/filters.py +++ b/pagure/ui/filters.py @@ -300,3 +300,23 @@ def no_js(content): content = content.replace('', '</script>') return content + + + +@APP.template_filter('toRGB') +def int_to_rgb(percent): + """ Template filter converting a given percentage to a css RGB value. + """ + output = "rgb(255, 0, 0);" + try: + percent = int(percent) + if percent < 50: + red = 255 + green = (255.0/50) * percent + else: + green = 255 + red = (255.0/50) * (100 - percent) + output = "rgb(%s, %s, 0);" % (int(red), int(green)) + except ValueError: + pass + return output From a617f20208a20d70bccd6f0563b945652106ccc3 Mon Sep 17 00:00:00 2001 From: Pierre-Yves Chibon Date: Jun 01 2015 08:33:53 +0000 Subject: [PATCH 4/23] List and make pretty the flags linked to a pull-request --- diff --git a/pagure/static/pagure.css b/pagure/static/pagure.css index f6cd533..151a0c3 100644 --- a/pagure/static/pagure.css +++ b/pagure/static/pagure.css @@ -867,3 +867,15 @@ span.CONFLICTS { .tabs .ui-tabs-active a:hover{ color: #e59728!important; } + +#pr_flags table{ + width: 100%; + border-spacing: 0; + border-collapse: collapse; + margin: 1em 0em 1em 0em; + color: black; +} + +#pr_flags table tr{ + margin-bottom: 1em; +} diff --git a/pagure/templates/pull_request.html b/pagure/templates/pull_request.html index 59d1995..a74be85 100644 --- a/pagure/templates/pull_request.html +++ b/pagure/templates/pull_request.html @@ -136,6 +136,21 @@ + +{% if pull_request.flags %} +
+ + {% for flag in pull_request.flags %} + + + + + + {% endfor %} +
{{ flag.percent }}%{{ flag.username }}{{ flag.comment }}
+
+{% endif %} + {% endif %}
From 08bfe072b8c5851a726d79dc3fdbc37461baa62f Mon Sep 17 00:00:00 2001 From: Pierre-Yves Chibon Date: Jun 01 2015 08:33:53 +0000 Subject: [PATCH 5/23] Flags must provide an URL (even if it is to the service itself) --- diff --git a/pagure/lib/model.py b/pagure/lib/model.py index 200cd0e..07572dc 100644 --- a/pagure/lib/model.py +++ b/pagure/lib/model.py @@ -861,6 +861,9 @@ class PullRequestFlag(BASE): comment = sa.Column( sa.Text(), nullable=False) + url = sa.Column( + sa.Text(), + nullable=False) date_created = sa.Column(sa.DateTime, nullable=False, default=datetime.datetime.utcnow) From 7f28fb7ab901970ba76937f1f2dae9eca1416504 Mon Sep 17 00:00:00 2001 From: Pierre-Yves Chibon Date: Jun 01 2015 08:33:53 +0000 Subject: [PATCH 6/23] Link the username to the service/build and provide the time of the flag creation --- diff --git a/pagure/templates/pull_request.html b/pagure/templates/pull_request.html index a74be85..c06b98e 100644 --- a/pagure/templates/pull_request.html +++ b/pagure/templates/pull_request.html @@ -143,8 +143,11 @@ {% for flag in pull_request.flags %} {{ flag.percent }}% - {{ flag.username }} + {{ flag.username }} {{ flag.comment }} + + {{ flag.date_created | humanize }} + {% endfor %} From 93a61d99e986cdaa1d6a16b6e69385593f69e6fe Mon Sep 17 00:00:00 2001 From: Pierre-Yves Chibon Date: Jun 01 2015 09:51:38 +0000 Subject: [PATCH 7/23] Add a unique identifier to the pull_request_flags table This unique identifier can be provided by the 3rd party tool and thus be used to update an previously inserted flag. --- diff --git a/pagure/lib/model.py b/pagure/lib/model.py index 07572dc..d1d1cc7 100644 --- a/pagure/lib/model.py +++ b/pagure/lib/model.py @@ -838,6 +838,7 @@ class PullRequestFlag(BASE): __tablename__ = 'pull_request_flags' id = sa.Column(sa.Integer, primary_key=True) + uid = sa.Column(sa.String(32), unique=True, nullable=False) pull_request_uid = sa.Column( sa.Text, sa.ForeignKey( From ac25ea905737d21599ec0f5eab46a50494864b6a Mon Sep 17 00:00:00 2001 From: Pierre-Yves Chibon Date: Jun 01 2015 11:54:24 +0000 Subject: [PATCH 8/23] Drop the reference to a specific commit in the pull-request flags for now We might re-introduce it later but let's do without for now --- diff --git a/pagure/lib/model.py b/pagure/lib/model.py index d1d1cc7..c4ea288 100644 --- a/pagure/lib/model.py +++ b/pagure/lib/model.py @@ -844,10 +844,6 @@ class PullRequestFlag(BASE): sa.ForeignKey( 'pull_requests.uid', ondelete='CASCADE', onupdate='CASCADE'), nullable=False) - commit_id = sa.Column( - sa.String(40), - nullable=True, - index=True) user_id = sa.Column( sa.Integer, sa.ForeignKey('users.id', onupdate='CASCADE'), From 72794729c856d5c7f5d20ac8328a3b6b8fe862d7 Mon Sep 17 00:00:00 2001 From: Pierre-Yves Chibon Date: Jun 01 2015 11:54:54 +0000 Subject: [PATCH 9/23] Create the AddPullRequestFlagForm --- diff --git a/pagure/forms.py b/pagure/forms.py index 587668d..2d4b2d6 100644 --- a/pagure/forms.py +++ b/pagure/forms.py @@ -158,6 +158,19 @@ class AddPullRequestCommentForm(wtf.Form): [wtforms.validators.Required()] ) +class AddPullRequestFlagForm(wtf.Form): + ''' Form to add a flag to a pull-request. ''' + username = wtforms.TextField( + 'Username', [wtforms.validators.Required()]) + percent = wtforms.TextField( + 'Percentage of completion', [wtforms.validators.Required()]) + comment = wtforms.TextAreaField( + 'Comment', [wtforms.validators.Required()]) + url = wtforms.TextField( + 'URL', [wtforms.validators.Required()]) + uid = wtforms.TextField( + 'UID', [wtforms.validators.optional()]) + class UserSettingsForm(wtf.Form): ''' Form to create or edit project. ''' From d471796a9fbec61a40432aa9146cd6765bad347f Mon Sep 17 00:00:00 2001 From: Pierre-Yves Chibon Date: Jun 01 2015 12:05:45 +0000 Subject: [PATCH 10/23] pagure.lib.add_pull_request_comment can raise a PagureException, so catch it --- diff --git a/pagure/api/fork.py b/pagure/api/fork.py index 52b5bd2..4f35112 100644 --- a/pagure/api/fork.py +++ b/pagure/api/fork.py @@ -477,6 +477,9 @@ def api_pull_request_add_comment(repo, requestid, username=None): ) SESSION.commit() output['message'] = message + except pagure.exceptions.PagureException as err: + raise pagure.exceptions.APIError( + 400, error_code=APIERROR.ENOCODE, error=str(err)) except SQLAlchemyError, err: # pragma: no cover APP.logger.exception(err) SESSION.rollback() From d917c05f3b1eb09431318e940aafee9cb4edd66e Mon Sep 17 00:00:00 2001 From: Pierre-Yves Chibon Date: Jun 01 2015 12:36:29 +0000 Subject: [PATCH 11/23] Make the code easier to read on 80 char screens --- diff --git a/pagure/lib/model.py b/pagure/lib/model.py index c4ea288..a09e5a6 100644 --- a/pagure/lib/model.py +++ b/pagure/lib/model.py @@ -698,7 +698,11 @@ class PullRequest(BASE): ''' Return the list of comments related to the pull-request itself, ie: not related to a specific commit. ''' - return [comment for comment in self.comments if not comment.commit_id] + return [ + comment + for comment in self.comments + if not comment.commit_id + ] @property def score(self): From 521fcd63ea21a75aa220aefd8572c1095d9b1016 Mon Sep 17 00:00:00 2001 From: Pierre-Yves Chibon Date: Jun 01 2015 12:40:09 +0000 Subject: [PATCH 12/23] Ensure we have comments, just no discussion and commit the changes --- diff --git a/tests/test_progit_lib.py b/tests/test_progit_lib.py index 2462518..23186b1 100644 --- a/tests/test_progit_lib.py +++ b/tests/test_progit_lib.py @@ -1312,8 +1312,10 @@ class PagureLibtests(tests.Modeltests): requestfolder=None, ) self.assertEqual(msg, 'Comment added') + self.session.commit() self.assertEqual(len(request.discussion), 0) + self.assertEqual(len(request.comments), 1) self.assertEqual(request.score, 0) def test_search_pull_requests(self): From 3935414877a57508400fddcc004cad77447b6802 Mon Sep 17 00:00:00 2001 From: Pierre-Yves Chibon Date: Jun 01 2015 12:40:28 +0000 Subject: [PATCH 13/23] Add add_pull_request_flag to the internal library --- diff --git a/pagure/lib/__init__.py b/pagure/lib/__init__.py index b9f17c9..9718786 100644 --- a/pagure/lib/__init__.py +++ b/pagure/lib/__init__.py @@ -679,6 +679,39 @@ def add_pull_request_comment(session, request, commit, filename, row, return 'Comment added' +def add_pull_request_flag(session, request, username, percent, comment, url, + uid, user, requestfolder): + ''' Add a flag to a pull-request. ''' + user_obj = __get_user(session, user) + + pr_flag = model.PullRequestFlag( + pull_request_uid=request.uid, + uid=uid or uuid.uuid4().hex, + username=username, + percent=percent, + comment=comment, + url=url, + user_id=user_obj.id, + ) + session.add(pr_flag) + # Make sure we won't have SQLAlchemy error before we create the repo + session.flush() + + pagure.lib.git.update_git( + request, repo=request.project, repofolder=requestfolder) + + pagure.lib.notify.log( + request.project, + topic='pull-request.flag.added', + msg=dict( + pullrequest=request.to_json(), + agent=user_obj.username, + ) + ) + + return 'Flag added' + + def new_project(session, user, name, blacklist, gitfolder, docfolder, ticketfolder, requestfolder, description=None, parent_id=None): From c349169c1ef2fdb8ab92902e7c573db84e1b2c2c Mon Sep 17 00:00:00 2001 From: Pierre-Yves Chibon Date: Jun 01 2015 12:40:38 +0000 Subject: [PATCH 14/23] Add unit-tests for the method pagure.lib.add_pull_request_flag --- diff --git a/tests/test_progit_lib.py b/tests/test_progit_lib.py index 23186b1..99c4748 100644 --- a/tests/test_progit_lib.py +++ b/tests/test_progit_lib.py @@ -1318,6 +1318,32 @@ class PagureLibtests(tests.Modeltests): self.assertEqual(len(request.comments), 1) self.assertEqual(request.score, 0) + @patch('pagure.lib.notify.send_email') + def test_add_pull_request_flag(self, mockemail): + """ Test add_pull_request_flag of pagure.lib. """ + mockemail.return_value = True + + self.test_new_pull_request() + + request = pagure.lib.search_pull_requests(self.session, requestid=1) + self.assertEqual(len(request.flags), 0) + + msg = pagure.lib.add_pull_request_flag( + session=self.session, + request=request, + username="jenkins", + percent=100, + comment="Build passes", + url="http://jenkins.cloud.fedoraproject.org", + uid="jenkins_build_pagure_34", + user='foo', + requestfolder=None, + ) + self.assertEqual(msg, 'Flag added') + self.session.commit() + + self.assertEqual(len(request.flags), 1) + def test_search_pull_requests(self): """ Test search_pull_requests of pagure.lib. """ From 4eb5ada8d96521d4c9ee06e380d50036bb72ed61 Mon Sep 17 00:00:00 2001 From: Pierre-Yves Chibon Date: Jun 01 2015 12:42:05 +0000 Subject: [PATCH 15/23] Make sure we do not send emails during the tests --- diff --git a/tests/test_progit_flask_api_fork.py b/tests/test_progit_flask_api_fork.py index 66eb32e..6ea4a50 100644 --- a/tests/test_progit_flask_api_fork.py +++ b/tests/test_progit_flask_api_fork.py @@ -511,8 +511,11 @@ class PagureFlaskApiForktests(tests.Modeltests): {"message": "Changes merged!"} ) - def test_api_pull_request_add_comment(self): + @patch('pagure.lib.notify.send_email') + def test_api_pull_request_add_comment(self, mockemail): """ Test the api_pull_request_add_comment method of the flask api. """ + mockemail.return_value = True + tests.create_projects(self.session) tests.create_tokens(self.session) tests.create_acls(self.session) From d236dcddb656d913e5e65282e8e0e7fae09f83df Mon Sep 17 00:00:00 2001 From: Pierre-Yves Chibon Date: Jun 01 2015 12:55:12 +0000 Subject: [PATCH 16/23] Add a method get_pull_request_flag_by_uid in the internal library --- diff --git a/pagure/lib/__init__.py b/pagure/lib/__init__.py index 9718786..44f901a 100644 --- a/pagure/lib/__init__.py +++ b/pagure/lib/__init__.py @@ -1563,6 +1563,27 @@ def get_request_by_uid(session, request_uid): return query.first() +def get_pull_request_flag_by_uid(session, flag_uid): + ''' Return the flag corresponding to the specified unique identifier. + + :arg session: the session to use to connect to the database. + :arg flag_uid: the unique identifier of a request. This identifier is + unique accross all flags on this pagure instance and should be + unique accross multiple pagure instances as well + :type request_uid: str or None + + :return: A single Issue object. + :rtype: pagure.lib.model.PullRequestFlag + + ''' + query = session.query( + model.PullRequestFlag + ).filter( + model.PullRequestFlag.uid == flag_uid.strip() if flag_uid else None + ) + return query.first() + + def set_up_user(session, username, fullname, default_email, emails=None): ''' Set up a new user into the database or update its information. ''' user = search_user(session, username=username) From 032826bcc9dacd09b1667154090ad267743704e9 Mon Sep 17 00:00:00 2001 From: Pierre-Yves Chibon Date: Jun 01 2015 12:55:26 +0000 Subject: [PATCH 17/23] Adjust add_pull_request_flag in the internal library to support update This way one can either create or update (edit) a flag attached to a PullRequest --- diff --git a/pagure/lib/__init__.py b/pagure/lib/__init__.py index 44f901a..3526e00 100644 --- a/pagure/lib/__init__.py +++ b/pagure/lib/__init__.py @@ -684,15 +684,23 @@ def add_pull_request_flag(session, request, username, percent, comment, url, ''' Add a flag to a pull-request. ''' user_obj = __get_user(session, user) - pr_flag = model.PullRequestFlag( - pull_request_uid=request.uid, - uid=uid or uuid.uuid4().hex, - username=username, - percent=percent, - comment=comment, - url=url, - user_id=user_obj.id, - ) + action = 'added' + pr_flag = get_pull_request_flag_by_uid(session, uid) + if pr_flag: + action = 'updated' + pr_flag.comment = comment + pr_flag.percent = percent + pr_flag.url = url + else: + pr_flag = model.PullRequestFlag( + pull_request_uid=request.uid, + uid=uid or uuid.uuid4().hex, + username=username, + percent=percent, + comment=comment, + url=url, + user_id=user_obj.id, + ) session.add(pr_flag) # Make sure we won't have SQLAlchemy error before we create the repo session.flush() @@ -702,14 +710,14 @@ def add_pull_request_flag(session, request, username, percent, comment, url, pagure.lib.notify.log( request.project, - topic='pull-request.flag.added', + topic='pull-request.flag.%s' % action, msg=dict( pullrequest=request.to_json(), agent=user_obj.username, ) ) - return 'Flag added' + return 'Flag %s' % action def new_project(session, user, name, blacklist, From e39f18c1248849bb15d0475477daa5ec2704f8e4 Mon Sep 17 00:00:00 2001 From: Pierre-Yves Chibon Date: Jun 01 2015 12:55:58 +0000 Subject: [PATCH 18/23] Create a new API endpoint to flag pull-requests: api_pull_request_add_flag --- diff --git a/pagure/api/fork.py b/pagure/api/fork.py index 4f35112..d1ea3c1 100644 --- a/pagure/api/fork.py +++ b/pagure/api/fork.py @@ -490,3 +490,107 @@ def api_pull_request_add_comment(repo, requestid, username=None): jsonout = flask.jsonify(output) return jsonout + + +@API.route('//pull-request//flag', + methods=['POST']) +@API.route('/fork///pull-request//flag', + methods=['POST']) +@api_login_required(acls=['pull_request_flag']) +@api_method +def api_pull_request_add_flag(repo, requestid, username=None): + """ + Flag a pull-request + ------------------- + This endpoint can be used to add or edit flags on a pull-request + + :: + + /api/0//pull-request//flag + + /api/0/fork///pull-request//flag + + Accepts POST queries only. + + :arg username: The name of the application as it should be presented to + the user on the pull-request page (for example: jenkins, travis-ci, + pep8bot...) + :arg percent: A percentage of completion compared to the goal, it can + be a percentage of coverage, a 0 vs 100 for fail vs pass. + The percentage also determine the background color of the flag on + the pull-request page. + :arg comment: Small information message summarizing the results presented + here. + :arg url: An URL to the link the flag to. This can be the URL of a + specific build or test, or the URL of the application itself, but + there must be one. + :kwarg uid: An unique identifier used to identify a flag on a pull-request + if you do not provide it, one will be automatically generated. + If you do provide it, sending a second request with the same UID will + update the flag instead of adding a new one. + Maximum length: ``32`` characters. + :kwarg commit: The hash of the commit you use + + Sample response: + + :: + + { + "message": "Flag added" + } + + """ + repo = pagure.lib.get_project(SESSION, repo, user=username) + output = {} + + if repo is None: + raise pagure.exceptions.APIError(404, error_code=APIERROR.ENOPROJECT) + + if not repo.settings.get('pull_requests', True): + raise pagure.exceptions.APIError( + 404, error_code=APIERROR.EPULLREQUESTSDISABLED) + + if repo.fullname != flask.g.token.project.fullname: + raise pagure.exceptions.APIError(401, error_code=APIERROR.EINVALIDTOK) + + request = pagure.lib.search_pull_requests( + SESSION, project_id=repo.id, requestid=requestid) + + if not request: + raise pagure.exceptions.APIError(404, error_code=APIERROR.ENOREQ) + + form = pagure.forms.AddPullRequestFlagForm(csrf_enabled=False) + if form.validate_on_submit(): + username = form.username.data + percent = form.percent.data + comment = form.comment.data.strip() + url = form.url.data.strip() + uid = form.uid.data.strip() if form.uid.data else None + try: + # New Flag + message = pagure.lib.add_pull_request_flag( + SESSION, + request=request, + username=username, + percent=percent, + comment=comment, + url=url, + uid=uid, + user=flask.g.fas_user.username, + requestfolder=APP.config['REQUESTS_FOLDER'], + ) + SESSION.commit() + output['message'] = message + except pagure.exceptions.PagureException as err: + raise pagure.exceptions.APIError( + 400, error_code=APIERROR.ENOCODE, error=str(err)) + except SQLAlchemyError, err: # pragma: no cover + APP.logger.exception(err) + SESSION.rollback() + raise pagure.exceptions.APIError(400, error_code=APIERROR.EDBERROR) + + else: + raise pagure.exceptions.APIError(400, error_code=APIERROR.EINVALIDREQ) + + jsonout = flask.jsonify(output) + return jsonout From e18f81eefa7e6f032be02f6954779d7e143a74a6 Mon Sep 17 00:00:00 2001 From: Pierre-Yves Chibon Date: Jun 01 2015 12:56:15 +0000 Subject: [PATCH 19/23] Add unit-tests for the API endpoint: api_pull_request_add_flag --- diff --git a/tests/__init__.py b/tests/__init__.py index 0e6ad63..d04ebf2 100644 --- a/tests/__init__.py +++ b/tests/__init__.py @@ -261,6 +261,7 @@ def create_acls(session): for acl in [ 'issue_create', 'pull_request_merge', 'pull_request_comment', 'issue_change_status', 'issue_comment', 'pull_request_close', + 'pull_request_flag', ]: item = pagure.lib.model.ACL( name=acl, @@ -273,7 +274,7 @@ def create_acls(session): def create_tokens_acl(session): """ Create some acls for the tokens. """ - for aclid in range(6): + for aclid in range(7): item = pagure.lib.model.TokenAcl( token_id='aaabbbcccddd', acl_id=aclid + 1, diff --git a/tests/test_progit_flask_api_fork.py b/tests/test_progit_flask_api_fork.py index 6ea4a50..592a572 100644 --- a/tests/test_progit_flask_api_fork.py +++ b/tests/test_progit_flask_api_fork.py @@ -625,6 +625,154 @@ class PagureFlaskApiForktests(tests.Modeltests): self.session, project_id=1, requestid=1) self.assertEqual(len(request.comments), 1) + @patch('pagure.lib.notify.send_email') + def test_api_pull_request_add_flag(self, mockemail): + """ Test the api_pull_request_add_flag method of the flask api. """ + mockemail.return_value = True + + tests.create_projects(self.session) + tests.create_tokens(self.session) + tests.create_acls(self.session) + tests.create_tokens_acl(self.session) + + headers = {'Authorization': 'token aaabbbcccddd'} + + # Invalid project + output = self.app.post( + '/api/0/foo/pull-request/1/flag', headers=headers) + self.assertEqual(output.status_code, 404) + data = json.loads(output.data) + self.assertDictEqual( + data, + { + "error": "Project not found", + "error_code": "ENOPROJECT", + } + ) + + # Valid token, wrong project + output = self.app.post( + '/api/0/test2/pull-request/1/flag', headers=headers) + self.assertEqual(output.status_code, 401) + data = json.loads(output.data) + self.assertDictEqual( + data, + { + "error": "Invalid or expired token. Please visit " \ + "https://pagure.org/ to get or renew your API token.", + "error_code": "EINVALIDTOK", + } + ) + + # No input + output = self.app.post( + '/api/0/test/pull-request/1/flag', headers=headers) + self.assertEqual(output.status_code, 404) + data = json.loads(output.data) + self.assertDictEqual( + data, + { + "error": "Pull-Request not found", + "error_code": "ENOREQ", + } + ) + + # Create a pull-request + repo = pagure.lib.get_project(self.session, 'test') + forked_repo = pagure.lib.get_project(self.session, 'test') + msg = pagure.lib.new_pull_request( + session=self.session, + repo_from=forked_repo, + branch_from='master', + repo_to=repo, + branch_to='master', + title='test pull-request', + user='pingou', + requestfolder=None, + ) + self.session.commit() + self.assertEqual(msg, 'Request created') + + # Check comments before + request = pagure.lib.search_pull_requests( + self.session, project_id=1, requestid=1) + self.assertEqual(len(request.flags), 0) + + data = { + 'username': 'Jenkins', + 'percent': 100, + 'url': 'http://jenkins.cloud.fedoraproject.org/', + 'uid': 'jenkins_build_pagure_100+seed', + } + + # Incomplete request + output = self.app.post( + '/api/0/test/pull-request/1/flag', data=data, headers=headers) + self.assertEqual(output.status_code, 400) + data = json.loads(output.data) + self.assertDictEqual( + data, + { + "error": "Invalid or incomplete input submited", + "error_code": "EINVALIDREQ", + } + ) + + # No change + request = pagure.lib.search_pull_requests( + self.session, project_id=1, requestid=1) + self.assertEqual(len(request.flags), 0) + + data = { + 'username': 'Jenkins', + 'percent': 0, + 'comment': 'Tests failed', + 'url': 'http://jenkins.cloud.fedoraproject.org/', + 'uid': 'jenkins_build_pagure_100+seed', + } + + # Valid request + output = self.app.post( + '/api/0/test/pull-request/1/flag', data=data, headers=headers) + self.assertEqual(output.status_code, 200) + data = json.loads(output.data) + self.assertDictEqual( + data, + {'message': 'Flag added'} + ) + + # One flag added + request = pagure.lib.search_pull_requests( + self.session, project_id=1, requestid=1) + self.assertEqual(len(request.flags), 1) + self.assertEqual(request.flags[0].comment, 'Tests failed') + self.assertEqual(request.flags[0].percent, 0) + + # Update flag + data = { + 'username': 'Jenkins', + 'percent': 100, + 'comment': 'Tests passed', + 'url': 'http://jenkins.cloud.fedoraproject.org/', + 'uid': 'jenkins_build_pagure_100+seed', + } + + output = self.app.post( + '/api/0/test/pull-request/1/flag', data=data, headers=headers) + self.assertEqual(output.status_code, 200) + data = json.loads(output.data) + self.assertDictEqual( + data, + {'message': 'Flag updated'} + ) + + # One flag added + request = pagure.lib.search_pull_requests( + self.session, project_id=1, requestid=1) + self.assertEqual(len(request.flags), 1) + self.assertEqual(request.flags[0].comment, 'Tests passed') + self.assertEqual(request.flags[0].percent, 100) + if __name__ == '__main__': SUITE = unittest.TestLoader().loadTestsFromTestCase( From d5d683141135c9879ce77503ce5d4c70c6c2bdf2 Mon Sep 17 00:00:00 2001 From: Pierre-Yves Chibon Date: Jun 01 2015 12:57:05 +0000 Subject: [PATCH 20/23] Document api_pull_request_add_flag_doc in the main API documentation page --- diff --git a/pagure/api/__init__.py b/pagure/api/__init__.py index 0034579..5f50546 100644 --- a/pagure/api/__init__.py +++ b/pagure/api/__init__.py @@ -364,7 +364,9 @@ def api(): api_pull_request_view_doc = load_doc(fork.api_pull_request_view) api_pull_request_merge_doc = load_doc(fork.api_pull_request_merge) api_pull_request_close_doc = load_doc(fork.api_pull_request_close) - api_pull_request_add_comment_doc = load_doc(fork.api_pull_request_add_comment) + api_pull_request_add_comment_doc = load_doc( + fork.api_pull_request_add_comment) + api_pull_request_add_flag_doc = load_doc(fork.api_pull_request_add_flag) api_version_doc = load_doc(api_version) api_users_doc = load_doc(api_users) @@ -383,6 +385,7 @@ def api(): api_pull_request_merge_doc, api_pull_request_close_doc, api_pull_request_add_comment_doc, + api_pull_request_add_flag_doc, ], users=[ api_users_doc, From bbd07b7a4caca94c1ab4fa65f8daca152534ffe7 Mon Sep 17 00:00:00 2001 From: Pierre-Yves Chibon Date: Jun 01 2015 13:04:49 +0000 Subject: [PATCH 21/23] Add the pull_request_flag API ACL to the configuration file --- diff --git a/pagure/default_config.py b/pagure/default_config.py index e1ca12e..143a7ce 100644 --- a/pagure/default_config.py +++ b/pagure/default_config.py @@ -148,4 +148,5 @@ ACLS = { 'pull_request_merge': 'Merge a pull-request of this project', 'pull_request_close': 'Close a pull-request of this project', 'pull_request_comment': 'Comment on a pull-request of this project', + 'pull_request_flag': 'Flag a pull-request of this project', } From db8de8838efc26361caaeeaa103f5ba9ff1243b8 Mon Sep 17 00:00:00 2001 From: Pierre-Yves Chibon Date: Jun 01 2015 13:27:15 +0000 Subject: [PATCH 22/23] Adjust the comments as per @ralph @ralphbean's suggestions --- diff --git a/pagure/lib/__init__.py b/pagure/lib/__init__.py index 3526e00..5c55717 100644 --- a/pagure/lib/__init__.py +++ b/pagure/lib/__init__.py @@ -156,7 +156,7 @@ def add_issue_comment(session, issue, comment, user, ticketfolder, user_id=user_obj.id, ) session.add(issue_comment) - # Make sure we won't have SQLAlchemy error before we create the repo + # Make sure we won't have SQLAlchemy error before we continue session.commit() pagure.lib.git.update_git( @@ -208,7 +208,7 @@ def add_issue_tag(session, issue, tags, user, ticketfolder): tag=tagobj.tag, ) session.add(issue_tag) - # Make sure we won't have SQLAlchemy error before we create the repo + # Make sure we won't have SQLAlchemy error before we continue session.flush() added_tags.append(tagobj.tag) @@ -355,7 +355,7 @@ def add_issue_dependency(session, issue, issue_blocked, user, ticketfolder): child_issue_id=issue.uid ) session.add(i2i) - # Make sure we won't have SQLAlchemy error before we create the repo + # Make sure we won't have SQLAlchemy error before we continue session.flush() pagure.lib.git.update_git( issue, @@ -400,7 +400,7 @@ def remove_issue_dependency(session, issue, issue_blocked, user, ticketfolder): child_del.append(child.id) issue.children.remove(child) - # Make sure we won't have SQLAlchemy error before we create the repo + # Make sure we won't have SQLAlchemy error before we continue session.flush() pagure.lib.git.update_git( issue, @@ -581,7 +581,7 @@ def add_user_to_project(session, project, new_user, user): user_id=new_user_obj.id, ) session.add(project_user) - # Make sure we won't have SQLAlchemy error before we create the repo + # Make sure we won't have SQLAlchemy error before we continue session.flush() pagure.lib.notify.log( @@ -628,7 +628,7 @@ def add_group_to_project(session, project, new_group, user): group_id=group_obj.id, ) session.add(project_group) - # Make sure we won't have SQLAlchemy error before we create the repo + # Make sure we won't have SQLAlchemy error before we continue session.flush() pagure.lib.notify.log( @@ -658,7 +658,7 @@ def add_pull_request_comment(session, request, commit, filename, row, user_id=user_obj.id, ) session.add(pr_comment) - # Make sure we won't have SQLAlchemy error before we create the repo + # Make sure we won't have SQLAlchemy error before we continue session.flush() pagure.lib.git.update_git( @@ -702,7 +702,7 @@ def add_pull_request_flag(session, request, username, percent, comment, url, user_id=user_obj.id, ) session.add(pr_flag) - # Make sure we won't have SQLAlchemy error before we create the repo + # Make sure we won't have SQLAlchemy error before we continue session.flush() pagure.lib.git.update_git( From 7d7b3759c0f981018d2d9bb67637d64054576f28 Mon Sep 17 00:00:00 2001 From: Pierre-Yves Chibon Date: Jun 01 2015 15:36:58 +0000 Subject: [PATCH 23/23] Include the JSON representation of the flag in the fedmsg message sent --- diff --git a/pagure/lib/__init__.py b/pagure/lib/__init__.py index 5c55717..155c84c 100644 --- a/pagure/lib/__init__.py +++ b/pagure/lib/__init__.py @@ -713,6 +713,7 @@ def add_pull_request_flag(session, request, username, percent, comment, url, topic='pull-request.flag.%s' % action, msg=dict( pullrequest=request.to_json(), + flag=pr_flag.to_json(), agent=user_obj.username, ) ) diff --git a/pagure/lib/model.py b/pagure/lib/model.py index a09e5a6..aced64a 100644 --- a/pagure/lib/model.py +++ b/pagure/lib/model.py @@ -883,6 +883,23 @@ class PullRequestFlag(BASE): foreign_keys=[pull_request_uid], remote_side=[PullRequest.uid]) + def to_json(self, public=False): + ''' Returns a dictionnary representation of the pull-request. + + ''' + output = { + 'uid': self.uid, + 'pull_request_uid': self.pull_request_uid, + 'username': self.username, + 'percent': self.percent, + 'comment': self.comment, + 'url': self.url, + 'date_created': self.date_created.strftime('%s'), + 'user': self.user.to_json(public=public), + } + + return output + class PagureGroupType(BASE): """