Commit 94735ff0 authored by Vamshi Krishna's avatar Vamshi Krishna

Organization: Add issues property and filter_issues method

Closes #142
parent 8ee2227d
......@@ -3,16 +3,25 @@ Here you go: GitHub organizations can be used in IGitt.
"""
from functools import lru_cache
from typing import Set
from typing import Optional
from urllib.parse import quote_plus
from IGitt.GitHub import GH_INSTANCE_URL
from IGitt.GitHub import GitHubMixin
from IGitt.GitHub.GitHubIssue import GitHubIssue
from IGitt.GitHub.GitHubUser import GitHubUser
from IGitt.Interfaces import get
from IGitt.Interfaces.Organization import Organization
from IGitt.Interfaces.Repository import Repository
GH_ISSUE_STATE_TRANSLATION = {
'opened': 'open',
'closed': 'closed',
'all': 'all'
}
class GitHubOrganization(GitHubMixin, Organization):
"""
Represents an organization on GitHub.
......@@ -94,3 +103,32 @@ class GitHubOrganization(GitHubMixin, Organization):
return {GitHubRepository.from_data(repo, self._token, repo['id'])
for repo in get(self._token, self.url + '/repos')}
def filter_issues(self,
state: Optional[str]=None,
label: Optional[str]=None,
assignee: Optional[str]=None) -> Set[GitHubIssue]:
"""
Filters the issues in the organization based on properties
:param state: 'opened' or 'closed' or 'all'.
:param label: Label of the issue
:param assignee: username of issue assignee
:return: Set of GitHubIssue objects
"""
from IGitt.GitHub.GitHub import GitHub
query = 'user:' + self.name
if state:
query += ' state:' + GH_ISSUE_STATE_TRANSLATION[state]
if label:
query += ' label:' + label
if assignee:
query += ' assignee:' + assignee
return set(GitHub.raw_search(self._token, query))
@property
def issues(self) -> Set[GitHubIssue]:
"""
Returns the set of Issues in this organization.
"""
return self.filter_issues(state='opened')
......@@ -2,13 +2,16 @@
This module contains the Issue abstraction class which provides properties and
actions related to issues and bug reports.
"""
import re
from functools import lru_cache
from typing import Set
from typing import Optional
from urllib.parse import quote_plus
from IGitt.GitLab import GL_INSTANCE_URL
from IGitt.GitLab import GitLabMixin
from IGitt.GitLab.GitLabUser import GitLabUser
from IGitt.GitLab.GitLabIssue import GitLabIssue
from IGitt.Interfaces import get
from IGitt.Interfaces import AccessLevel
from IGitt.Interfaces.Organization import Organization
......@@ -140,3 +143,37 @@ class GitLabOrganization(GitLabMixin, Organization):
}.union({
repo for org in self.suborgs for repo in org.repositories
})
def filter_issues(self,
state: Optional[str]=None,
label: Optional[str]=None,
assignee: Optional[str]=None
) -> Set[GitLabIssue]:
"""
Filters the issues in the organization based on properties
:param state: 'opened' or 'closed' or 'all'
:param label: Label of the issue
:param assignee: username of issue assignee
:return: Set of GitLabIssue objects
"""
params = dict()
if state:
params['state'] = state
if label:
params['labels'] = label
if assignee:
params['assignee_id'] = GitLabUser(self._token,
assignee).identifier
url = re.compile(r'https://(?:[^/]+)/(.+)/issues/(\d+)')
return {GitLabIssue.from_data(issue, self._token,
url.match(issue['web_url']).group(0),
issue['iid'])
for issue in get(self._token, self.url + '/issues', params)}
@property
def issues(self) -> Set[GitLabIssue]:
"""
Returns the list of issue objects in this organization.
"""
return self.filter_issues(state='opened')
......@@ -3,9 +3,11 @@ This module contains the Issue abstraction class which provides properties and
actions related to issues and bug reports.
"""
from typing import Set
from typing import Optional
from IGitt.Interfaces import IGittObject
from IGitt.Interfaces.User import User
from IGitt.Interfaces.Issue import Issue
from IGitt.Interfaces.Repository import Repository
......@@ -62,3 +64,24 @@ class Organization(IGittObject):
Returns the list of repositories contained in this organization.
"""
raise NotImplementedError
def filter_issues(self,
state: Optional[str]='opened',
label: Optional[str]=None,
assignee: Optional[str]=None) -> Set[Issue]:
"""
Filters the issues in the organization based on properties
:param state: 'opened' or 'closed' or 'all'
:param label: Label of the issue
:param assignee: username of issue assignee
:return: Set of Issue objects
"""
raise NotImplementedError
@property
def issues(self) -> Set[Issue]:
"""
Returns set of issue objects in this organization.
"""
raise NotImplementedError
interactions:
- request:
body: '{}'
headers:
Accept: ['*/*']
Accept-Encoding: ['gzip, deflate']
Connection: [keep-alive]
Content-Length: ['2']
Content-Type: [application/json]
User-Agent: [IGitt]
method: GET
uri: https://api.github.com/search/issues?per_page=100&q=user%3Agitmate-test-org+state%3Aopen
response:
body:
string: !!binary |
H4sIAAAAAAAAA+1YbW/aMBD+K5U/Q00CpCRSNW1qN20SVNvo61QhkzjBqxNHsQMjEf995wRaiDo6
KKv2IRIfgnP3+Hy+tyc5UkIRPnJFGinkmA3EIleEMaeKjhIqU64kcnzCJYVXiobw70eO0oQjB02U
iqWDMYnZccDUJB0fgy5OaCwkhoWQKNpUVKqmSAKsHzCTMqUSt1EDFWJMiWQ+2hcOUDgZUy73Rng0
CJdAOY5ISBcADCcJaaQOAb2CAlQ6PRBmCQSIExXyyvHX7uLFW2Aectpt2+jY3XargSLh0ZFeQ/2z
S+v7zSDzri+zfvbwa3D2YPSz96ewZZSGY5qAXgMppjgF6S+pVEe+SI7Ikb5nEEqlFskRFwGLQOKK
hHLCbBteaXyzZVt2t2dtbvnVuroZcPfn59nF8LY7GAYmiJMpUSSpXnGxKM1l4OndXBEp8G4Rgyle
bfBuetoBkCBZwhSH0/ZtC2ENJ/Gaydu9vCboC87FDLSr9m7myOYG+FELDCufWRTsgQBaORZqQsFd
cAQdxwGTLwVxxZhCI4cElgpCQWNIcHVCvZ0MWuqAObMILMmLslCApWPpJixWTES7eWlDE5CgqpCI
ZWR3JNCUAFCUoJ1OVWiA5t/kccWtpUqO44RNiTvXrkioS9kUHLsHXEUX0NQ81ql4qRMP3AzVekS8
UCdfUb8Xq2JZVHCdBnbP6rWt1kmvmvfDTx/Z3fWse3F22+lnt7NBFui835oy26p+WVuLDtAsngFM
11mwdmPNFVxA0UC+7xtjH4Q86hNoQasT3BehqLSeiGkEAly4DxSOsuxQREoWRBQE6sLzfHOuC09d
eN6+8Kzyspwe65HgubG5zsw6M986M6GhhoxDWxYR9Mwo5fyJ+CAH+ICbUOi33ohAD0Zmy+g1Wyfw
GxodxzQdo3Onx4LYe17GctqG0zW1jMuFXMKUu5BUTUQygsIgXFZMcLBB/7z/4fwbiI+FNy/HdOmK
BEwzjluLxut5p6YT/xXvNP8d7zTx4XmniQ/BO/UtPPFOIJ/V+bPCO7OL4fk67zSfeOcQYveo+Kig
A7GmnByy5g+fZer+UveXt+4va5RzB+627BBLLqdnxtf0KcN2utbWPtVxHmUO0afuF78BqYjpOFYV
AAA=
headers:
Access-Control-Allow-Origin: ['*']
Access-Control-Expose-Headers: ['ETag, Link, Retry-After, X-GitHub-OTP, X-RateLimit-Limit,
X-RateLimit-Remaining, X-RateLimit-Reset, X-OAuth-Scopes, X-Accepted-OAuth-Scopes,
X-Poll-Interval']
Cache-Control: [no-cache]
Content-Encoding: [gzip]
Content-Security-Policy: [default-src 'none']
Content-Type: [application/json; charset=utf-8]
Date: ['Mon, 09 Jul 2018 20:22:11 GMT']
Referrer-Policy: ['origin-when-cross-origin, strict-origin-when-cross-origin']
Server: [GitHub.com]
Status: [200 OK]
Strict-Transport-Security: [max-age=31536000; includeSubdomains; preload]
X-Accepted-OAuth-Scopes: ['']
X-Content-Type-Options: [nosniff]
X-Frame-Options: [deny]
X-GitHub-Media-Type: [github.v3; format=json]
X-GitHub-Request-Id: ['158C:12A2:136EA48:2D19BA9:5B43C3F2']
X-OAuth-Scopes: ['admin:gpg_key, admin:org, admin:org_hook, admin:public_key,
admin:repo_hook, gist, notifications, repo, user']
X-RateLimit-Limit: ['30']
X-RateLimit-Remaining: ['25']
X-RateLimit-Reset: ['1531167783']
X-Runtime-rack: ['0.118758']
X-XSS-Protection: [1; mode=block]
status: {code: 200, message: OK}
version: 1
......@@ -49,3 +49,13 @@ class GitHubOrganizationTest(IGittTestCase):
def test_repositories(self):
self.assertEqual({r.full_name for r in self.org.repositories},
{'gitmate-test-org/test', 'gitmate-test-org/test-1'})
def test_filter_issues(self):
self.assertEqual(len(self.org.filter_issues()), 3)
self.assertEqual(len(self.org.filter_issues(state='closed')),
1)
self.assertEqual(len(self.org.filter_issues(label='test-label')), 1)
self.assertEqual(len(self.org.filter_issues(assignee='Vamshi99')), 1)
def test_issues(self):
self.assertEqual(len(self.org.issues), 2)
interactions:
- request:
body: '{}'
headers:
Accept: ['*/*']
Accept-Encoding: ['gzip, deflate']
Connection: [keep-alive]
Content-Length: ['2']
Content-Type: [application/json]
If-None-Match: [W/"54798fc9fecdb1f9f040be1ff2be47f9"]
User-Agent: [IGitt]
method: GET
uri: https://gitlab.com/api/v4/groups/gitmate-test-org/issues?per_page=100&state=opened
response:
body: {string: '[{"id":12610314,"iid":3,"project_id":5731027,"title":"Just for
a test","description":"","state":"opened","created_at":"2018-07-07T14:27:18.608Z","updated_at":"2018-07-07T14:27:18.608Z","closed_at":null,"closed_by":null,"labels":[],"milestone":null,"assignees":[],"author":{"id":1137314,"name":"Vamshi
Krishna","username":"Vamshi99","state":"active","avatar_url":"https://secure.gravatar.com/avatar/cfbd6bc03e4540f65e8d4e91a96f4907?s=80\u0026d=identicon","web_url":"https://gitlab.com/Vamshi99"},"assignee":null,"user_notes_count":0,"upvotes":0,"downvotes":0,"due_date":null,"confidential":false,"discussion_locked":null,"web_url":"https://gitlab.com/gitmate-test-org/test/issues/3","time_stats":{"time_estimate":0,"total_time_spent":0,"human_time_estimate":null,"human_total_time_spent":null},"weight":null},{"id":12610311,"iid":2,"project_id":5731027,"title":"Test
issue","description":"","state":"opened","created_at":"2018-07-07T14:27:03.420Z","updated_at":"2018-07-07T16:33:00.267Z","closed_at":null,"closed_by":null,"labels":["test-label"],"milestone":null,"assignees":[{"id":1137314,"name":"Vamshi
Krishna","username":"Vamshi99","state":"active","avatar_url":"https://secure.gravatar.com/avatar/cfbd6bc03e4540f65e8d4e91a96f4907?s=80\u0026d=identicon","web_url":"https://gitlab.com/Vamshi99"}],"author":{"id":1137314,"name":"Vamshi
Krishna","username":"Vamshi99","state":"active","avatar_url":"https://secure.gravatar.com/avatar/cfbd6bc03e4540f65e8d4e91a96f4907?s=80\u0026d=identicon","web_url":"https://gitlab.com/Vamshi99"},"assignee":{"id":1137314,"name":"Vamshi
Krishna","username":"Vamshi99","state":"active","avatar_url":"https://secure.gravatar.com/avatar/cfbd6bc03e4540f65e8d4e91a96f4907?s=80\u0026d=identicon","web_url":"https://gitlab.com/Vamshi99"},"user_notes_count":0,"upvotes":0,"downvotes":0,"due_date":null,"confidential":false,"discussion_locked":null,"web_url":"https://gitlab.com/gitmate-test-org/test/issues/2","time_stats":{"time_estimate":0,"total_time_spent":0,"human_time_estimate":null,"human_total_time_spent":null},"weight":null}]'}
headers:
Cache-Control: ['max-age=0, private, must-revalidate']
Content-Length: ['2062']
Content-Type: [application/json]
Date: ['Mon, 09 Jul 2018 20:22:29 GMT']
Etag: [W/"afd741ebbd06b8b6130777e07bc668ee"]
Link: ['<https://gitlab.com/api/v4/groups/gitmate-test-org/issues?id=gitmate-test-org&order_by=created_at&page=1&per_page=100&sort=desc&state=opened>;
rel="first", <https://gitlab.com/api/v4/groups/gitmate-test-org/issues?id=gitmate-test-org&order_by=created_at&page=1&per_page=100&sort=desc&state=opened>;
rel="last"']
RateLimit-Limit: ['600']
RateLimit-Observed: ['4']
RateLimit-Remaining: ['596']
RateLimit-Reset: ['1531167809']
RateLimit-ResetTime: ['Tue, 09 Jul 2018 20:23:29 GMT']
Server: [nginx]
Strict-Transport-Security: [max-age=31536000]
Vary: [Origin]
X-Content-Type-Options: [nosniff]
X-Frame-Options: [SAMEORIGIN]
X-Next-Page: ['']
X-Page: ['1']
X-Per-Page: ['100']
X-Prev-Page: ['']
X-Request-Id: [9d051478-238b-46d9-9cb0-66a86a1e691f]
X-Runtime: ['0.111204']
X-Total: ['2']
X-Total-Pages: ['1']
status: {code: 200, message: OK}
version: 1
......@@ -65,3 +65,13 @@ class GitLabOrganizationTest(IGittTestCase):
{'gitmate-test-org/test',
'gitmate-test-org/subgroup/test',
'gitmate-test-org/another-subgroup/nested-subgroup/test'})
def test_filter_issues(self):
self.assertEqual(len(self.org.filter_issues()), 3)
self.assertEqual(len(self.org.filter_issues(state='closed')),
1)
self.assertEqual(len(self.org.filter_issues(label='test-label')), 1)
self.assertEqual(len(self.org.filter_issues(assignee='Vamshi99')), 1)
def test_issues(self):
self.assertEqual(len(self.org.issues), 2)
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment