diff options
Diffstat (limited to 'pygithub3')
-rw-r--r-- | pygithub3/requests/issues/comments.py | 2 | ||||
-rw-r--r-- | pygithub3/requests/issues/labels.py | 81 | ||||
-rw-r--r-- | pygithub3/requests/issues/milestones.py | 38 | ||||
-rw-r--r-- | pygithub3/requests/repos/__init__.py | 16 | ||||
-rw-r--r-- | pygithub3/resources/issues.py | 26 | ||||
-rw-r--r-- | pygithub3/services/issues/__init__.py | 7 | ||||
-rw-r--r-- | pygithub3/services/issues/comments.py | 2 | ||||
-rw-r--r-- | pygithub3/services/issues/events.py | 2 | ||||
-rw-r--r-- | pygithub3/services/issues/labels.py | 159 | ||||
-rw-r--r-- | pygithub3/services/issues/milestones.py | 104 | ||||
-rw-r--r-- | pygithub3/services/repos/__init__.py | 30 | ||||
-rw-r--r-- | pygithub3/tests/services/test_issues.py | 107 | ||||
-rw-r--r-- | pygithub3/tests/services/test_repos.py | 12 |
13 files changed, 578 insertions, 8 deletions
diff --git a/pygithub3/requests/issues/comments.py b/pygithub3/requests/issues/comments.py index 0601db3..638c9cf 100644 --- a/pygithub3/requests/issues/comments.py +++ b/pygithub3/requests/issues/comments.py @@ -39,4 +39,4 @@ class Edit(Request): class Delete(Request): uri = 'repos/{user}/{repo}/issues/comments/{id}' - resource = Comment
\ No newline at end of file + resource = Comment diff --git a/pygithub3/requests/issues/labels.py b/pygithub3/requests/issues/labels.py new file mode 100644 index 0000000..47337f9 --- /dev/null +++ b/pygithub3/requests/issues/labels.py @@ -0,0 +1,81 @@ +# -*- encoding: utf-8 -*- + +from pygithub3.requests.base import Request, ValidationError +from pygithub3.resources.issues import Label + + + +class Get(Request): + uri = 'repos/{user}/{repo}/labels/{name}' + resource = Label + + +class Create(Request): + uri = 'repos/{user}/{repo}/labels' + resource = Label + body_schema = { + 'schema': ('name', 'color'), + 'required': ('name', 'color' ) + } + + def validate_color(color): + color = color.get('color', '') + if not Label.is_valid_color(color): + raise ValidationError('colors must have 6 hexadecimal characters, ' + 'without # in the beggining') + + +class Update(Request): + + uri = 'repos/{user}/{repo}/labels/{name}' + resource = Label + body_schema = { + 'schema': ('name', 'color'), + 'required': ('name', 'color' ) + } + + def validate_color(color): + color = color.get('color', '') + if not Label.is_valid_color(color): + raise ValidationError('colors must have 6 hexadecimal characters, ' + 'without # in the beggining') + + +class Delete(Request): + uri = 'repos/{user}/{repo}/labels/{name}' + resource = Label + + +class List_by_repo(Request): + uri = 'repos/{user}/{repo}/labels' + resource = Label + + + +class List_by_issue(Request): + uri = 'repos/{user}/{repo}/issues/{number}/labels' + resource = Label + + +class Add_to_issue(Request): + uri = 'repos/{user}/{repo}/issues/{number}/labels' + resource = Label + +class Remove_from_issue(Request): + uri = 'repos/{user}/{repo}/issues/{number}/labels/{name}' + resource = Label + + +class Replace_all(Request): + uri = 'repos/{user}/{repo}/issues/{number}/labels' + resource = Label + + +class Remove_all(Request): + uri = 'repos/{user}/{repo}/issues/{number}/labels' + resource = Label + + +class List_by_milestone(Request): + uri = 'repos/{user}/{repo}/milestones/{number}/labels' + resource = Label diff --git a/pygithub3/requests/issues/milestones.py b/pygithub3/requests/issues/milestones.py new file mode 100644 index 0000000..355c3b0 --- /dev/null +++ b/pygithub3/requests/issues/milestones.py @@ -0,0 +1,38 @@ +# -*- encoding: utf-8 -*- + +from pygithub3.requests.base import Request +from pygithub3.resources.issues import Milestone + + +class List(Request): + uri = 'repos/{user}/{repo}/milestones' + resource = Milestone + + +class Get(Request): + uri = 'repos/{user}/{repo}/milestones/{number}' + resource = Milestone + + +class Create(Request): + uri = 'repos/{user}/{repo}/milestones' + resource = Milestone + body_schema = { + 'schema': ('title', 'state', 'description', 'due_on'), + 'required': ('title',) + } + + +class Update(Request): + + uri = 'repos/{user}/{repo}/milestones/{number}' + resource = Milestone + body_schema = { + 'schema': ('title', 'state', 'description', 'due_on'), + 'required': ('title',) + } + + +class Delete(Request): + uri = 'repos/{user}/{repo}/milestones/{number}' + resource = Milestone diff --git a/pygithub3/requests/repos/__init__.py b/pygithub3/requests/repos/__init__.py index cd920fe..7a145f2 100644 --- a/pygithub3/requests/repos/__init__.py +++ b/pygithub3/requests/repos/__init__.py @@ -2,6 +2,7 @@ from pygithub3.requests.base import Request, ValidationError from pygithub3.resources.users import User +from pygithub3.resources.issues import Label, Milestone from pygithub3.resources.repos import Repo, Team, Tag, Branch class List(Request): @@ -78,3 +79,18 @@ class List_branches(Request): uri = 'repos/{user}/{repo}/branches' resource = Branch + +class List_labels(Request): + + uri = 'repos/{user}/{repo}/labels' + resource = Label + +class List_milestones(Request): + + uri = 'repos/{user}/{repo}/milestones' + resource = Milestone + # TODO: validate + body_schema = { + 'schema': ('state', 'sort', 'direction'), + 'required': () + } diff --git a/pygithub3/resources/issues.py b/pygithub3/resources/issues.py index e864e79..c560faa 100644 --- a/pygithub3/resources/issues.py +++ b/pygithub3/resources/issues.py @@ -1,9 +1,33 @@ #!/usr/bin/env python # -*- encoding: utf-8 -*- +import re + from .base import Resource from .users import User + +class Label(Resource): + @staticmethod + def is_valid_color(color): + valid_color = re.compile(r'[0-9abcdefABCDEF]{6}') + match = valid_color(color) + if match is None: + return False + return match.start() == 0 and match.end() == len(color) + + def __str__(self): + return '<Label (%s)>' % getattr(self, 'name', '') + + +class Milestone(Resource): + _dates = ('created_at', 'due_on') + _maps = {'creator': User} + + def __str__(self): + return '<Milestone (%s)>' % getattr(self, 'title', '') + + class Issue(Resource): _dates = ('created_at', 'updated_at') @@ -28,4 +52,4 @@ class Event(Resource): _maps = {'actor': User, 'issue': Issue} def __str__(self): - return '<Event (%s)>' % (getattr(self, 'commit_id', ''))
\ No newline at end of file + return '<Event (%s)>' % (getattr(self, 'commit_id', '')) diff --git a/pygithub3/services/issues/__init__.py b/pygithub3/services/issues/__init__.py index 0699f9e..62ed105 100644 --- a/pygithub3/services/issues/__init__.py +++ b/pygithub3/services/issues/__init__.py @@ -1,9 +1,10 @@ -#!/usr/bin/env python # -*- encoding: utf-8 -*- from pygithub3.services.base import Service from .comments import Comments from .events import Events +from .labels import Labels +from .milestones import Milestones class Issue(Service): """ Consume `Issues API <http://developer.github.com/v3/issues>`_ """ @@ -11,6 +12,8 @@ class Issue(Service): def __init__(self, **config): self.comments = Comments(**config) self.events = Events(**config) + self.labels = Labels(**config) + self.milestones = Milestones(**config) super(Issue, self).__init__(**config) def list(self, data={}): @@ -79,4 +82,4 @@ class Issue(Service): """ request = self.request_builder('issues.edit', user=user, repo=repo, number=number, body=data) - return self._patch(request)
\ No newline at end of file + return self._patch(request) diff --git a/pygithub3/services/issues/comments.py b/pygithub3/services/issues/comments.py index f367a58..5d6980a 100644 --- a/pygithub3/services/issues/comments.py +++ b/pygithub3/services/issues/comments.py @@ -72,4 +72,4 @@ class Comments(Service): """ request = self.request_builder('issues.comments.delete', user=user, repo=repo, id=id) - self._delete(request)
\ No newline at end of file + self._delete(request) diff --git a/pygithub3/services/issues/events.py b/pygithub3/services/issues/events.py index 0111db4..8eb35e4 100644 --- a/pygithub3/services/issues/events.py +++ b/pygithub3/services/issues/events.py @@ -39,4 +39,4 @@ class Events(Service): """ request = self.request_builder('issues.events.get', user=user, repo=repo, id=id) - return self._get(request)
\ No newline at end of file + return self._get(request) diff --git a/pygithub3/services/issues/labels.py b/pygithub3/services/issues/labels.py new file mode 100644 index 0000000..0355918 --- /dev/null +++ b/pygithub3/services/issues/labels.py @@ -0,0 +1,159 @@ +# -*- encoding: utf-8 -*- + +from pygithub3.services.base import Service + + +class Labels(Service): + """ Consume `Labels API + <http://developer.github.com/v3/issues/labels>`_ """ + + def get(self, user, repo, name): + """ Get a single label + + :param str user: Username + :param str repo: Repo name + :param str name: Label name + """ + request = self.request_builder('issues.labels.get', user=user, + repo=repo, name=name) + return self._get(request) + + def create(self, user, repo, name, color): + """ Create a label on an repo + + :param str user: Username + :param str repo: Repo name + :param str name: Label name + :param str color: Label color + + .. warning:: + You must be authenticated + """ + request = self.request_builder('issues.labels.create', + user=user, + repo=repo, + body={'name': name, + 'color': color,}) + return self._post(request) + + def update(self, user, repo, name, new_name, color): + """ Update a label on an repo + + :param str user: Username + :param str repo: Repo name + :param str name: Label name + :param str name: Label new name + :param str color: Label color + + .. warning:: + You must be authenticated + """ + request = self.request_builder('issues.labels.update', + user=user, + repo=repo, + name=name, + body={'name': new_name, + 'color': color,}) + return self._patch(request) + + def delete(self, user, repo, name): + """ Delete a label on an repo + + :param str user: Username + :param str repo: Repo name + :param str name: Label name + + .. warning:: + You must be authenticated + """ + request = self.request_builder('issues.labels.delete', + user=user, + repo=repo, + name=name) + return self._delete(request) + + def list_by_repo(self, user, repo): + """ List all labels for a repo + + :param str user: Username + :param str repo: Repo name + :returns: A :doc:`result` + """ + request = self.request_builder('issues.labels.list_by_repo', + user=user, + repo=repo,) + return self._get(request) + + def list_by_issue(self, user, repo, number): + """ List labels for an issue + + :param str user: Username + :param str repo: Repo name + :param int number: Issue number + :returns: A :doc:`result` + """ + request = self.request_builder('issues.labels.list_by_issue', user=user, + repo=repo, number=number) + return self._get(request) + + def add_to_issue(self, user, repo, number, labels): + """ Add labels to issue + + :param str user: Username + :param str repo: Repo name + :param int number: Issue number + :param list labels: List of label names + :returns: A :doc:`result` + """ + request = self.request_builder('issues.labels.add_to_issue', + user=user, + repo=repo, + number=number, + body=labels) + return self._post(request) + + def remove_from_issue(self, user, repo, number, label): + """ Remove a label from an issue + + :param str user: Username + :param str repo: Repo name + :param int number: Issue number + :param str label: Label name + :returns: A :doc:`result` + """ + request = self.request_builder('issues.labels.remove_from_issue', + user=user, + repo=repo, + number=number, + name=label) + return self._delete(request) + + def replace_all(self, user, repo, number, labels): + """ Replace all labels of a issue + + :param str user: Username + :param str repo: Repo name + :param int number: Issue number + :param list labels: New labels + :returns: A :doc:`result` + """ + request = self.request_builder('issues.labels.replace_all', + user=user, + repo=repo, + number=number, + body=labels,) + return self._put(request) + + def remove_all(self, user, repo, number): + """ Remove all labels from a issue + + :param str user: Username + :param str repo: Repo name + :param int number: Issue number + :returns: A :doc:`result` + """ + request = self.request_builder('issues.labels.remove_all', + user=user, + repo=repo, + number=number,) + return self._delete(request) diff --git a/pygithub3/services/issues/milestones.py b/pygithub3/services/issues/milestones.py new file mode 100644 index 0000000..aba6dd4 --- /dev/null +++ b/pygithub3/services/issues/milestones.py @@ -0,0 +1,104 @@ +# -*- encoding: utf-8 -*- + +from pygithub3.services.base import Service + +class Milestones(Service): + """ Consume `Milestones API + <http://developer.github.com/v3/issues/milestones>`_ """ + + def list(self, user, repo): + """ List milestones for a repo + + :param str user: Username + :param str repo: Repo name + :returns: A :doc:`result` + """ + request = self.request_builder('issues.milestones.list', + user=user, + repo=repo) + return self._get_result(request) + + def get(self, user, repo, number): + """ Get a single milestone + + :param str user: Username + :param str repo: Repo name + :param int number: Milestone number + """ + request = self.request_builder('issues.milestones.get', user=user, + repo=repo, number=number) + return self._get(request) + + def create(self, + user, + repo, + title, + state=None, + description=None, + due_on=None): + """ Create a milestone + + :param str user: Username + :param str repo: Repo name + :param str title: Milestone title + :param str state: Milestone state + :param str description: Milestone description + :param date due_on: Milestone due date + + .. warning:: + You must be authenticated + """ + request = self.request_builder('issues.milestones.create', + user=user, + repo=repo, + body={'title': title, + 'state': state, + 'due_on': due_on}) + return self._post(request) + + def update(self, + user, + repo, + number, + title, + state=None, + description=None, + due_on=None): + """ Update a milestone + + :param str user: Username + :param str repo: Repo name + :param int number: Milestone number + :param str title: Milestone title + :param str state: Milestone state + :param str description: Milestone description + :param date due_on: Milestone due date + + .. warning:: + You must be authenticated + """ + request = self.request_builder('issues.milestones.update', + user=user, + repo=repo, + number=number, + body={'title': title, + 'state': state, + 'description': description, + 'due_on': due_on, }) + return self._patch(request) + + def delete(self, user, repo, number): + """ Delete a milestone + + :param str user: Username + :param str repo: Repo name + :param int number: Milestone number + + ... warning:: + You must be authenticated + """ + request = self.request_builder('issues.milestones.delete', + user=user, + repo=repo, + number=number) + self._delete(request) diff --git a/pygithub3/services/repos/__init__.py b/pygithub3/services/repos/__init__.py index 628e9d6..a7e61fc 100644 --- a/pygithub3/services/repos/__init__.py +++ b/pygithub3/services/repos/__init__.py @@ -190,3 +190,33 @@ class Repo(Service): request = self.make_request('repos.list_branches', user=user, repo=repo) return self._get_result(request) + + def list_labels(self, user=None, repo=None): + """ Get repository's labels + + :param str user: Username + :param str repo: Repository + :returns: A :doc:`result` + + .. note:: + Remember :ref:`config precedence` + """ + request = self.make_request('repos.list_labels', + user=user, + repo=repo) + return self._get_result(request) + + def list_milestones(self, user=None, repo=None): + """ Get repository's milestones + + :param str user: Username + :param str repo: Repository + :returns: A :doc:`result` + + .. note:: + Remember :ref:`config precedence` + """ + request = self.make_request('repos.list_milestones', + user=user, + repo=repo) + return self._get_result(request) diff --git a/pygithub3/tests/services/test_issues.py b/pygithub3/tests/services/test_issues.py index dfc56ca..33ce754 100644 --- a/pygithub3/tests/services/test_issues.py +++ b/pygithub3/tests/services/test_issues.py @@ -6,7 +6,7 @@ from mock import patch, Mock from pygithub3.tests.utils.core import TestCase from pygithub3.resources.base import json -from pygithub3.services.issues import Issue, Comments, Events +from pygithub3.services.issues import Issue, Comments, Events, Labels, Milestones from pygithub3.tests.utils.base import (mock_response, mock_response_result, mock_json) from pygithub3.tests.utils.services import _ @@ -112,4 +112,107 @@ class TestEventsService(TestCase): request_method.return_value = mock_response() self.ev.get('octocat', 'Hello-World', 1) self.assertEqual(request_method.call_args[0], - ('get', _('repos/octocat/Hello-World/issues/events/1')))
\ No newline at end of file + ('get', _('repos/octocat/Hello-World/issues/events/1'))) + + +@patch.object(requests.sessions.Session, 'request') +class TestLabelsService(TestCase): + + def setUp(self): + self.lb = Labels() + + def test_GET(self, request_method): + request_method.return_value = mock_response() + self.lb.get('octocat', 'Hello-World', 'bug') + self.assertEqual(request_method.call_args[0], + ('get', _('repos/octocat/Hello-World/labels/bug'))) + + def test_CREATE(self, request_method): + request_method.return_value = mock_response('post') + self.lb.create('octocat', 'Hello-World', 'bug', 'FF0000') + self.assertEqual(request_method.call_args[0], + ('post', _('repos/octocat/Hello-World/labels'))) + + def test_UPDATE(self, request_method): + request_method.return_value = mock_response('patch') + self.lb.update('octocat', 'Hello-World', 'bug', 'critical', 'FF0000') + self.assertEqual(request_method.call_args[0], + ('patch', _('repos/octocat/Hello-World/labels/bug'))) + + def test_DELETE(self, request_method): + request_method.return_value = mock_response('delete') + self.lb.delete('octocat', 'Hello-World', 'bug') + self.assertEqual(request_method.call_args[0], + ('delete', _('repos/octocat/Hello-World/labels/bug'))) + + def test_LIST_by_repo(self, request_method): + request_method.return_value = mock_response() + self.lb.list_by_repo('octocat', 'Hello-World') + self.assertEqual(request_method.call_args[0], + ('get', _('repos/octocat/Hello-World/labels'))) + + def test_LIST_by_issue(self, request_method): + request_method.return_value = mock_response() + self.lb.list_by_issue('octocat', 'Hello-World', 1) + self.assertEqual(request_method.call_args[0], + ('get', _('repos/octocat/Hello-World/issues/1/labels'))) + + def test_ADD_to_issue(self, request_method): + request_method.return_value = mock_response('post') + self.lb.add_to_issue('octocat', 'Hello-World', 1, ['bug', 'critical']) + self.assertEqual(request_method.call_args[0], + ('post', _('repos/octocat/Hello-World/issues/1/labels'))) + + def test_REMOVE_from_issue(self, request_method): + request_method.return_value = mock_response('delete') + self.lb.remove_from_issue('octocat', 'Hello-World', 1, 'bug') + self.assertEqual(request_method.call_args[0], + ('delete', _('repos/octocat/Hello-World/issues/1/labels/bug'))) + + def test_REPLACE_all(self, request_method): + self.lb.replace_all('octocat', 'Hello-World', 1, ['bug', 'critical']) + self.assertEqual(request_method.call_args[0], + ('put', _('repos/octocat/Hello-World/issues/1/labels'))) + + def test_REMOVE_all(self, request_method): + request_method.return_value = mock_response('delete') + self.lb.remove_all('octocat', 'Hello-World', 1) + self.assertEqual(request_method.call_args[0], + ('delete', _('repos/octocat/Hello-World/issues/1/labels'))) + + +@patch.object(requests.sessions.Session, 'request') +class TestMilestonesService(TestCase): + + def setUp(self): + self.mi = Milestones() + + def test_LIST_by_repo(self, request_method): + request_method.return_value = mock_response_result() + self.mi.list('octocat', 'Hello-World').all() + self.assertEqual(request_method.call_args[0], + ('get', _('repos/octocat/Hello-World/milestones'))) + + def test_GET(self, request_method): + request_method.return_value = mock_response() + self.mi.get('octocat', 'Hello-World', 1) + self.assertEqual(request_method.call_args[0], + ('get', _('repos/octocat/Hello-World/milestones/1'))) + + def test_CREATE(self, request_method): + request_method.return_value = mock_response('post') + self.mi.create('octocat', 'Hello-World', 'title') + self.assertEqual(request_method.call_args[0], + ('post', _('repos/octocat/Hello-World/milestones'))) + + def test_UPDATE(self, request_method): + request_method.return_value = mock_response('patch') + self.mi.update('octocat', 'Hello-World', 1, 'critical') + self.assertEqual(request_method.call_args[0], + ('patch', _('repos/octocat/Hello-World/milestones/1'))) + + def test_DELETE(self, request_method): + request_method.return_value = mock_response('delete') + self.mi.delete('octocat', 'Hello-World', 1) + self.assertEqual(request_method.call_args[0], + ('delete', _('repos/octocat/Hello-World/milestones/1'))) diff --git a/pygithub3/tests/services/test_repos.py b/pygithub3/tests/services/test_repos.py index e21d474..a07635a 100644 --- a/pygithub3/tests/services/test_repos.py +++ b/pygithub3/tests/services/test_repos.py @@ -134,6 +134,18 @@ class TestRepoService(TestCase): self.assertEqual(request_method.call_args[0], ('get', _('repos/octocat/octocat_repo/branches'))) + def test_LIST_labels(self, request_method): + request_method.return_value = mock_response_result() + self.rs.list_labels().all() + self.assertEqual(request_method.call_args[0], + ('get', _('repos/octocat/octocat_repo/labels'))) + + def test_LIST_milestones(self, request_method): + request_method.return_value = mock_response_result() + self.rs.list_milestones().all() + self.assertEqual(request_method.call_args[0], + ('get', _('repos/octocat/octocat_repo/milestones'))) + @patch.object(requests.sessions.Session, 'request') class TestCollaboratorsService(TestCase): |