# HG changeset patch # User Eivind Tagseth # Date 1489415693 -3600 # Node ID b60fb9461b1839dd7c56f81ab6ca80b86037b4e4 # Parent 986efdcfaf64f9cb52ac4d20ddf62ddfca6fcea7 Add JSON-RPC API for reading changeset status Allows reading a changeset status as json. This is useful for e.g. reporting, extracting review status for all changesets between two releases. diff -r 986efdcfaf64 -r b60fb9461b18 docs/api/api.rst --- a/docs/api/api.rst Thu May 11 00:19:14 2017 +0200 +++ b/docs/api/api.rst Mon Mar 13 15:34:53 2017 +0100 @@ -1007,6 +1007,75 @@ } error: null +get_changeset +^^^^^^^^^^^^^ + +Get information and review status for a given changeset. This command can only +be executed using the api_key of a user with read permissions to the +repository. + +INPUT:: + + id : + api_key : "" + method : "get_changeset" + args: { + "repoid" : "", + "raw_id" : "", + "with_reviews": " = Optional(False)" + } + +OUTPUT:: + + id : + result: { + "author": "", + "date": "", + "message": "", + "raw_id": "", + "revision": "", + "short_id": "", + "reviews": [{ + "reviewer": "", + "modified_at": "", # iso 8601 date, server's timezone + "status": "", # "under_review", "approved" or "rejected" + }, + ... + ] + } + error: null + +Example output:: + + { + "id" : 1, + "error" : null, + "result" : { + "author" : { + "email" : "user@example.com", + "name" : "Kallithea Admin" + }, + "changed" : [], + "short_id" : "e1022d3d28df", + "date" : "2017-03-28T09:09:03", + "added" : [ + "README.rst" + ], + "removed" : [], + "revision" : 0, + "raw_id" : "e1022d3d28dfba02f626cde65dbe08f4ceb0e4e7", + "message" : "Added file via Kallithea", + "id" : "e1022d3d28dfba02f626cde65dbe08f4ceb0e4e7", + "reviews" : [ + { + "status" : "under_review", + "modified_at" : "2017-03-28T09:17:08.618", + "reviewer" : "user" + } + ] + } + } + API access for web views ------------------------ diff -r 986efdcfaf64 -r b60fb9461b18 kallithea/controllers/api/api.py --- a/kallithea/controllers/api/api.py Thu May 11 00:19:14 2017 +0200 +++ b/kallithea/controllers/api/api.py Mon Mar 13 15:34:53 2017 +0100 @@ -47,12 +47,15 @@ from kallithea.model.user import UserModel from kallithea.model.user_group import UserGroupModel from kallithea.model.gist import GistModel +from kallithea.model.changeset_status import ChangesetStatusModel from kallithea.model.db import ( Repository, Setting, UserIpMap, Permission, User, Gist, RepoGroup, UserGroup) from kallithea.lib.compat import json from kallithea.lib.exceptions import ( DefaultUserException, UserGroupsAssignedException) +from kallithea.lib.vcs.exceptions import ChangesetDoesNotExistError +from kallithea.lib.vcs.backends.base import EmptyChangeset log = logging.getLogger(__name__) @@ -2469,3 +2472,22 @@ log.error(traceback.format_exc()) raise JSONRPCError('failed to delete gist ID:%s' % (gist.gist_access_id,)) + + # permission check inside + def get_changeset(self, repoid, raw_id, with_reviews=Optional(False)): + repo = get_repo_or_error(repoid) + if not HasRepoPermissionLevel('read')(repo.repo_name): + raise JSONRPCError('Access denied to repo %s' % repo.repo_name) + changeset = repo.get_changeset(raw_id) + if isinstance(changeset, EmptyChangeset): + raise JSONRPCError('Changeset %s does not exist' % raw_id) + + info = dict(changeset.as_dict()) + + with_reviews = Optional.extract(with_reviews) + if with_reviews: + reviews = ChangesetStatusModel().get_statuses( + repo.repo_name, raw_id) + info["reviews"] = reviews + + return info diff -r 986efdcfaf64 -r b60fb9461b18 kallithea/model/db.py --- a/kallithea/model/db.py Thu May 11 00:19:14 2017 +0200 +++ b/kallithea/model/db.py Mon Mar 13 15:34:53 2017 +0100 @@ -2287,6 +2287,13 @@ def status_lbl(self): return ChangesetStatus.get_status_lbl(self.status) + def __json__(self): + return dict( + status=self.status, + modified_at=self.modified_at, + reviewer=self.author.username, + ) + class PullRequest(Base, BaseDbModel): __tablename__ = 'pull_requests' diff -r 986efdcfaf64 -r b60fb9461b18 kallithea/tests/api/api_base.py --- a/kallithea/tests/api/api_base.py Thu May 11 00:19:14 2017 +0200 +++ b/kallithea/tests/api/api_base.py Mon Mar 13 15:34:53 2017 +0100 @@ -2449,3 +2449,51 @@ response = api_call(self, params) expected = Setting.get_server_info() self._compare_ok(id_, expected, given=response.body) + + def test_api_get_changeset(self): + review = fixture.review_changeset(self.REPO, self.TEST_REVISION, "approved") + id_, params = _build_data(self.apikey, 'get_changeset', + repoid=self.REPO, raw_id = self.TEST_REVISION) + response = api_call(self, params) + result = json.loads(response.body)["result"] + assert result["raw_id"] == self.TEST_REVISION + assert not result.has_key("reviews") + + def test_api_get_changeset_with_reviews(self): + reviewobjs = fixture.review_changeset(self.REPO, self.TEST_REVISION, "approved") + id_, params = _build_data(self.apikey, 'get_changeset', + repoid=self.REPO, raw_id = self.TEST_REVISION, + with_reviews = True) + response = api_call(self, params) + result = json.loads(response.body)["result"] + assert result["raw_id"] == self.TEST_REVISION + assert result.has_key("reviews") + assert len(result["reviews"]) == 1 + review = result["reviews"][0] + expected = { + 'status': 'approved', + 'modified_at': reviewobjs[0].modified_at.isoformat()[:-3], + 'reviewer': 'test_admin', + } + assert review == expected + + def test_api_get_changeset_that_does_not_exist(self): + """ Fetch changeset status for non-existant changeset. + revision id is the above git hash used in the test above with the + last 3 nibbles replaced with 0xf. Should not exist for git _or_ hg. + """ + id_, params = _build_data(self.apikey, 'get_changeset', + repoid=self.REPO, raw_id = '7ab37bc680b4aa72c34d07b230c866c28e9fcfff') + response = api_call(self, params) + expected = u'Changeset %s does not exist' % ('7ab37bc680b4aa72c34d07b230c866c28e9fcfff',) + self._compare_error(id_, expected, given=response.body) + + def test_api_get_changeset_without_permission(self): + review = fixture.review_changeset(self.REPO, self.TEST_REVISION, "approved") + RepoModel().revoke_user_permission(repo=self.REPO, user=self.TEST_USER_LOGIN) + RepoModel().revoke_user_permission(repo=self.REPO, user="default") + id_, params = _build_data(self.apikey_regular, 'get_changeset', + repoid=self.REPO, raw_id = self.TEST_REVISION) + response = api_call(self, params) + expected = u'Access denied to repo %s' % self.REPO + self._compare_error(id_, expected, given=response.body) diff -r 986efdcfaf64 -r b60fb9461b18 kallithea/tests/api/test_api_git.py --- a/kallithea/tests/api/test_api_git.py Thu May 11 00:19:14 2017 +0200 +++ b/kallithea/tests/api/test_api_git.py Mon Mar 13 15:34:53 2017 +0100 @@ -12,10 +12,11 @@ # You should have received a copy of the GNU General Public License # along with this program. If not, see . -from kallithea.tests.base import TestController, GIT_REPO +from kallithea.tests.base import TestController, GIT_REPO, GIT_TEST_REVISION from kallithea.tests.api.api_base import _BaseTestApi class TestGitApi(_BaseTestApi, TestController): REPO = GIT_REPO REPO_TYPE = 'git' + TEST_REVISION = GIT_TEST_REVISION diff -r 986efdcfaf64 -r b60fb9461b18 kallithea/tests/api/test_api_hg.py --- a/kallithea/tests/api/test_api_hg.py Thu May 11 00:19:14 2017 +0200 +++ b/kallithea/tests/api/test_api_hg.py Mon Mar 13 15:34:53 2017 +0100 @@ -12,10 +12,11 @@ # You should have received a copy of the GNU General Public License # along with this program. If not, see . -from kallithea.tests.base import TestController, HG_REPO +from kallithea.tests.base import TestController, HG_REPO, HG_TEST_REVISION from kallithea.tests.api.api_base import _BaseTestApi class TestHgApi(_BaseTestApi, TestController): REPO = HG_REPO REPO_TYPE = 'hg' + TEST_REVISION = HG_TEST_REVISION diff -r 986efdcfaf64 -r b60fb9461b18 kallithea/tests/base.py --- a/kallithea/tests/base.py Thu May 11 00:19:14 2017 +0200 +++ b/kallithea/tests/base.py Mon Mar 13 15:34:53 2017 +0100 @@ -48,7 +48,7 @@ 'TEST_USER_REGULAR2_PASS', 'TEST_USER_REGULAR2_EMAIL', 'TEST_HG_REPO', 'TEST_HG_REPO_CLONE', 'TEST_HG_REPO_PULL', 'TEST_GIT_REPO', 'TEST_GIT_REPO_CLONE', 'TEST_GIT_REPO_PULL', 'HG_REMOTE_REPO', - 'GIT_REMOTE_REPO', 'SCM_TESTS', + 'GIT_REMOTE_REPO', 'SCM_TESTS', 'HG_TEST_REVISION', 'GIT_TEST_REVISION', ] # Invoke websetup with the current config file @@ -80,6 +80,10 @@ HG_FORK = u'vcs_test_hg_fork' GIT_FORK = u'vcs_test_git_fork' +HG_TEST_REVISION = u"a53d9201d4bc278910d416d94941b7ea007ecd52" +GIT_TEST_REVISION = u"7ab37bc680b4aa72c34d07b230c866c28e9fc204" + + ## VCS SCM_TESTS = ['hg', 'git'] uniq_suffix = str(int(time.mktime(datetime.datetime.now().timetuple()))) diff -r 986efdcfaf64 -r b60fb9461b18 kallithea/tests/fixture.py --- a/kallithea/tests/fixture.py Thu May 11 00:19:14 2017 +0200 +++ b/kallithea/tests/fixture.py Mon Mar 13 15:34:53 2017 +0100 @@ -22,7 +22,7 @@ import tarfile from os.path import dirname -from kallithea.model.db import Repository, User, RepoGroup, UserGroup, Gist +from kallithea.model.db import Repository, User, RepoGroup, UserGroup, Gist, ChangesetStatus from kallithea.model.meta import Session from kallithea.model.repo import RepoModel from kallithea.model.user import UserModel @@ -30,6 +30,8 @@ from kallithea.model.user_group import UserGroupModel from kallithea.model.gist import GistModel from kallithea.model.scm import ScmModel +from kallithea.model.comment import ChangesetCommentsModel +from kallithea.model.changeset_status import ChangesetStatusModel from kallithea.lib.db_manage import DbManage from kallithea.lib.vcs.backends.base import EmptyChangeset from kallithea.tests.base import invalidate_all_caches, GIT_REPO, HG_REPO, TESTS_TMP_PATH, TEST_USER_ADMIN_LOGIN @@ -309,6 +311,12 @@ ) return cs + def review_changeset(self, repo, revision, status, author=TEST_USER_ADMIN_LOGIN): + comment = ChangesetCommentsModel().create(u"review comment", repo, author, revision=revision, send_email=False) + csm = ChangesetStatusModel().set_status(repo, ChangesetStatus.STATUS_APPROVED, author, comment, revision=revision) + Session().commit() + return csm + #============================================================================== # Global test environment setup