JiraRepository: Implement Repository interface

parent 0be225aa
"""
Contains a JIRA project implementation.
"""
from datetime import datetime
from urllib.parse import urljoin
from typing import Optional
from typing import Set
from typing import Union
import logging
import re
from IGitt.Interfaces import delete
from IGitt.Interfaces import get
from IGitt.Interfaces import post
from IGitt.Interfaces import AccessLevel
from IGitt.Interfaces import BasicAuthorizationToken
from IGitt.Interfaces import IssueStates
from IGitt.Interfaces.Repository import Repository
from IGitt.Interfaces.Repository import WebhookEvents
from IGitt.Jira import JiraMixin
from IGitt.Jira import JiraOAuth1Token
from IGitt.Jira import BASE_URL
from IGitt.Jira import JIRA_INSTANCE_URL
from IGitt.Jira.JiraIssue import JiraIssue
_HTTP_REGEX = re.compile(r'https?://')
JIRA_WEBHOOK_TRANSLATION = {
WebhookEvents.PUSH: (None, ),
WebhookEvents.ISSUE: ('jira:issue_created',
'jira:issue_updated',
'jira:issue_deleted',
'jira:worklog_updated'),
WebhookEvents.MERGE_REQUEST: (None, ),
WebhookEvents.COMMIT_COMMENT: (None, ),
WebhookEvents.MERGE_REQUEST_COMMENT: (None, ),
WebhookEvents.ISSUE_COMMENT: ('jira:comment_created',
'jira:comment_updated',
'jira:comment_deleted'),
}
class JiraRepository(JiraMixin, Repository):
"""
Represents a project resource on JIRA.
"""
def __init__(self,
token: Union[JiraOAuth1Token, BasicAuthorizationToken],
identifier: Union[str, int]):
"""
Instantiates a new JiraRepository object with the given details.
:param token:
The OAuth v1.0 token to be used for authentication.
:param identifier:
The unique identifier or key of the project.
"""
self._identifier = identifier
self._token = token
self._url = '/project/{}'.format(identifier)
self._hook_url = urljoin(JIRA_INSTANCE_URL,
'/rest/webhooks/1.0/webhook')
@property
def identifier(self) -> int:
"""
Returns the unique identifier of the corresponding repository.
"""
try:
return int(self._identifier)
except ValueError:
return int(self.data['id'])
@property
def web_url(self) -> str:
"""
Returns a human accessible web url for the corresponding project.
"""
return urljoin(JIRA_INSTANCE_URL,
'/projects/{}'.format(self.data['key']))
@property
def top_level_org(self):
"""
JIRA doesn't support organizations.
"""
raise NotImplementedError
@property
def full_name(self):
"""
JIRA doesn't have an account based naming scheme like GitHub. So, this
property returns just the project name.
"""
return self.data['name']
@property
def commits(self):
"""
JIRA projects don't actually hold a codebase and hence has no commits.
"""
raise NotImplementedError
@property
def clone_url(self):
"""
JIRA projects don't actually hold a codebase which can be cloned.
"""
raise NotImplementedError
def get_labels(self):
"""
Retrieves the list of available labels for this project.
"""
raise NotImplementedError
def create_label(self,
name: str,
description: Optional[str]=None,
label_type: Optional[str]=None,
**kwargs):
"""
Creates a new label.
"""
raise NotImplementedError
def delete_label(self, name: str):
"""
Deletes the specified label.
:raises: ElementDoesntExistError if no such label exists.
"""
raise NotImplementedError
def get_issue(self, issue_number: int):
"""
Retrieves the specified issue from the project.
:return: A JiraIssue object representing the specified issue.
"""
return JiraIssue(self._token, issue_number)
def get_mr(self, mr_number: int):
"""
JIRA doesn't actually hold a codebase and doesn't support sending merge
requests.
"""
raise NotImplementedError
@property
def hooks(self):
"""
Retrieves all the webhooks this project is hooked to.
:return: A set of URLs.
"""
params = {'jqlFilter': 'project = {}'.format(self.data['key'])}
return {hook['url']
for hook in get(self._token, self._hook_url, params)}
def register_hook(self,
url: str,
_: Optional[str]=None,
events: Optional[Set[WebhookEvents]]=None):
"""
Registers a webhook to the given URL.
"""
if url in self.hooks:
return
reg_events = [x for event in events
for x in JIRA_WEBHOOK_TRANSLATION[event]
if x is not None]
config = {
'name': 'An IGitt webhook',
'url': url,
'events': reg_events,
'jqlFilter': 'project = {}'.format(self.data['key']),
'excludeIssueDetails': False
}
post(self._token, self._hook_url, config)
logging.warning('Be careful with JIRA webhooks as they are system '
'wide. i.e. Every single project sends a webhook for '
'one registration.')
def delete_hook(self, url: str):
"""
Deletes all the webhooks to the specified URL.
"""
for hook in get(self._token, self._hook_url):
if hook['url'] == url:
delete(self._token, hook['self'])
def filter_issues(self, state: str='opened') -> set:
"""
Filters issues from a repository based on the chosen properties.
"""
raise NotImplementedError
@property
def issues(self) -> set:
"""
Retrieves the set of JiraIssue objects for this project.
"""
params = {'jql': 'Project="{}"'.format(self.data['key'])}
return {JiraIssue.from_data(iss, self._token, iss['id'])
for iss in get(self._token,
self.absolute_url('/search'),
params)['issues']
}
@property
def merge_requests(self) -> set:
"""
JIRA projects don't actually hold a codebase, so merge requests do not
exist.
"""
raise NotImplementedError
def create_issue(self,
issue_type: str,
title: str,
body: str='') -> JiraIssue:
"""
Creates a new issue in the project.
"""
return JiraIssue.create(
self._token, self.identifier, title, body, issue_type=issue_type)
def create_fork(self, *args, **kwargs):
"""
JIRA projects don't actually have a codebase to be forked.
"""
raise NotImplementedError
def delete(self):
"""
Deletes the JIRA project.
"""
delete(self._token, self.url)
def create_merge_request(self, *args, **kwargs):
"""
JIRA projects don't actually hold a codebase to merge changes into.
"""
raise NotImplementedError
def create_file(self, *args, **kwargs):
"""
JIRA projects don't actually hold a codebase. So, new files can't be
created.
"""
raise NotImplementedError
def search_mrs(self, *args, **kwargs):
"""
JIRA doesn't support a merge request resource.
"""
raise NotImplementedError
def search_issues(self,
created_after: Optional[datetime]=None,
created_before: Optional[datetime]=None,
updated_after: Optional[datetime]=None,
updated_before: Optional[datetime]=None,
state: Optional[IssueStates] = None):
"""
List open issues in the repository.
"""
raise NotImplementedError
def get_permission_level(self, *args, **kwargs) -> AccessLevel:
"""
JIRA provides support for custom permission schemes for users which
cannot be therefore generalized into an ``AccessLevel`` enum.
"""
raise NotImplementedError
@property
def parent(self):
"""
JIRA projects do not support or maintain a fork relationship between
each other.
"""
return None
@staticmethod
def create(token: Union[JiraOAuth1Token, BasicAuthorizationToken],
name: str,
project_type: Optional[str]=None,
project_key: Optional[str]=None,
project_lead: Optional[str]=None,
**kwargs):
"""
Creates a new JIRA project and returns it.
:param name:
The name of the project.
:param project_type:
The type of the project.
:param project_key:
The key identifier of the project to be set.
:param project_lead:
The project lead.
"""
repo = post(token,
BASE_URL + '/project',
{
'key': project_key,
'name': name,
'projectTypeKey': project_type,
'lead': project_lead
})
return JiraRepository.from_data(repo, token, repo['id'])
interactions:
- request:
body: '{"key": "TEX", "name": "Test", "projectTypeKey": "software", "lead": "nkprince007"}'
headers:
Accept:
- !!binary |
Ki8q
Accept-Encoding:
- !!binary |
Z3ppcCwgZGVmbGF0ZQ==
Connection:
- !!binary |
a2VlcC1hbGl2ZQ==
Content-Length: ['83']
Content-Type:
- !!binary |
YXBwbGljYXRpb24vanNvbg==
User-Agent:
- !!binary |
SUdpdHQ=
method: POST
uri: https://jira.gitmate.io/rest/api/2/project
response:
body:
string: !!binary |
H4sIAAAAAAAAAKpWKk7NSVOyUsooKSkottLXz8osStRLzyzJTSxJ1cvM1y9KLS7RTyzI1DfSLyjK
z0pNLtE3NDAwMFbSUcpMUbICs3WUslMrgWaEuEYo1QIAAAD//wMAYTwj8FIAAAA=
headers:
Cache-Control: ['no-cache, no-store, no-transform']
Content-Encoding: [gzip]
Content-Length: ['104']
Content-Security-Policy: [frame-ancestors 'self']
Content-Type: [application/json;charset=UTF-8]
Date: ['Sun, 01 Apr 2018 13:21:41 GMT']
Location: ['https://jira.gitmate.io/rest/api/2/project/10003']
Set-Cookie: [JSESSIONID=EFC5B0D6879491F82F691103A162AA02;path=/;HttpOnly, atlassian.xsrf.token=B15V-IRV7-Q0YS-ZCZZ|d321e3226aa77d2f2cbd8e563c2ead764d10f5bd|lin;path=/]
Strict-Transport-Security: [max-age=315569260; preload]
Vary: [User-Agent]
X-Arequestid: [801x9107x1]
X-Asen: [SEN-L11373089]
X-Asessionid: [r69954]
X-Ausername: [nkprince007]
X-Content-Type-Options: [nosniff]
X-Frame-Options: [DENY, SAMEORIGIN]
X-Seraph-Loginreason: [OK]
X-Xss-Protection: [1; mode=block, 1; mode=block]
status: {code: 201, message: Created}
- request:
body: '{}'
headers:
Accept:
- !!binary |
Ki8q
Accept-Encoding:
- !!binary |
Z3ppcCwgZGVmbGF0ZQ==
Connection:
- !!binary |
a2VlcC1hbGl2ZQ==
Content-Length: ['2']
Content-Type:
- !!binary |
YXBwbGljYXRpb24vanNvbg==
User-Agent:
- !!binary |
SUdpdHQ=
method: DELETE
uri: https://jira.gitmate.io/rest/api/2/project/10003
response:
body: {string: ''}
headers:
Cache-Control: ['no-cache, no-store, no-transform']
Content-Security-Policy: [frame-ancestors 'self']
Content-Type: [application/json;charset=UTF-8]
Date: ['Sun, 01 Apr 2018 13:21:43 GMT']
Set-Cookie: [JSESSIONID=A3168A22DD044938F0F2F524898B7059;path=/;HttpOnly, atlassian.xsrf.token=B15V-IRV7-Q0YS-ZCZZ|cedf65f91ae2bfbc26a049efd5ce3a0a0193d999|lin;path=/]
Strict-Transport-Security: [max-age=315569260; preload]
X-Arequestid: [801x9108x1]
X-Asen: [SEN-L11373089]
X-Asessionid: [azxax6]
X-Ausername: [nkprince007]
X-Content-Type-Options: [nosniff]
X-Frame-Options: [DENY, SAMEORIGIN]
X-Seraph-Loginreason: [OK]
X-Xss-Protection: [1; mode=block, 1; mode=block]
status: {code: 204, message: No Content}
- request:
body: '{}'
headers:
Accept:
- !!binary |
Ki8q
Accept-Encoding:
- !!binary |
Z3ppcCwgZGVmbGF0ZQ==
Connection:
- !!binary |
a2VlcC1hbGl2ZQ==
Content-Length: ['2']
Content-Type:
- !!binary |
YXBwbGljYXRpb24vanNvbg==
User-Agent:
- !!binary |
SUdpdHQ=
method: GET
uri: https://jira.gitmate.io/rest/api/2/project/10003?per_page=100
response:
body:
string: !!binary |
H4sIAAAAAAAAAKpWSi0qyi/yTS0uTkxPLVayilbyy1coKMrPSk0uUUjOL81JUUhKVUjLL81LUSjP
LMlQyExRUDc0MDAwVtdTitWBaAfqq66tBQAAAP//AwA5m9JxTAAAAA==
headers:
Cache-Control: ['no-cache, no-store, no-transform']
Content-Encoding: [gzip]
Content-Length: ['97']
Content-Security-Policy: [frame-ancestors 'self']
Content-Type: [application/json;charset=UTF-8]
Date: ['Sun, 01 Apr 2018 13:21:44 GMT']
Set-Cookie: [JSESSIONID=CDFC4C9049412EB1C1932186CE5E3B3E;path=/;HttpOnly, atlassian.xsrf.token=B15V-IRV7-Q0YS-ZCZZ|83c752dda597b36f11583920892240c9d481a68b|lin;path=/]
Strict-Transport-Security: [max-age=315569260; preload]
Vary: [User-Agent]
X-Arequestid: [801x9109x1]
X-Asen: [SEN-L11373089]
X-Asessionid: [kz5qwi]
X-Ausername: [nkprince007]
X-Content-Type-Options: [nosniff]
X-Frame-Options: [DENY, SAMEORIGIN]
X-Seraph-Loginreason: [OK]
X-Xss-Protection: [1; mode=block, 1; mode=block]
status: {code: 404, message: Not Found}
version: 1
interactions:
- request:
body: '{}'
headers:
Accept:
- !!binary |
Ki8q
Accept-Encoding:
- !!binary |
Z3ppcCwgZGVmbGF0ZQ==
Connection:
- !!binary |
a2VlcC1hbGl2ZQ==
Content-Length: ['2']
Content-Type:
- !!binary |
YXBwbGljYXRpb24vanNvbg==
User-Agent:
- !!binary |
SUdpdHQ=
method: GET
uri: https://jira.gitmate.io/rest/api/2/project/LTK?per_page=100
response:
body:
string: !!binary |
H4sIAAAAAAAAALRWTW/iMBD9K1YOPVHyxaIKqarYbbViqXpY6Knag0kG4jaxI4/Dx1b89x0nKU0L
KlC6lyjjeN5M3ryx59mBZc5l7PScGDDSIjdCyVYKPG4VOm3lWj1CZIawQqflIKRT2pkYk2PPdR+F
5u2ZMBk30BbK1YDG5blwA7f2c33P83zyFDbCi/EEK7Jux0N6b0SlNVqwoZ3e8xGxCgR9ZR+SZ3CJ
IsVNjNqwH14tPueG63tNBsXpXCw7Fx8EQogKDWWQyvFKLSToQVxGOqvWyPK9b55H6EFnGXSOwkPx
l9LOeJqefQztd5d+93jo5SHYYbAMg+OxM4hFkX2IvaYiC8xTvrqrynDLEYGNoqQQOuNS2pJERszp
m9EF0P5IZbmSIA1V6OEPqQexgPEqB2sfI43S0ZBjKcSgKcRgS3x9Zjg+MZNwwyRAjMwoNgEWUypt
6xopSarZT9JcwGJHARq8hP5Fbdq/utyk+arVMaViO66Y2KSc3pSnCC/aHdBPlCDr1ufZCJtshFts
jBNgFP285ERNiRZgJcBXM9Hdw8SoTqLJhtXJezK6p5CxdUa9JeOHBkKI2WTFfg1+99lITc2Ca2Dn
pA4mlWHUB4YpzWJIgWKxgYVnFp9NaZkz2zkMjdKrw7QkMj4DdO1GfE0W3QoC57MGQ3ZpSyyn0NFp
0tHZ0Sl0vk9SyNgiEVHCRJZzodH+f65hbhu31Mu0kJF1wRcBkVtcROaru8kL92joezHb10xeeAph
XpMw73/oZyJmDQ1tn1ITrZ5AEtxCniYwyEX0Vl83tLItLzqX6SAXM0rC0k777u/6o9Hg593NNe2e
g0Zb+iNP7Nptd1PW+fhtyzDXUUKXRrwppybqONqF6nioZ5CqvgRgM5bNK2hMYdmQywm3d5BWKZQT
wTUpOFU5JfKJWce1MPTqlyrox5mQAo3mVLRT4Ox9tf7k6FID1j3U7Jugc/jA8halMbNsAR44puwA
3NHaJeKBw8kOxHo+eYe43ojDKndYjYp1SzrrfwAAAP//AwBrbb4qFAsAAA==
headers:
Cache-Control: ['no-cache, no-store, no-transform']
Content-Encoding: [gzip]
Content-Length: ['784']
Content-Security-Policy: [frame-ancestors 'self']
Content-Type: [application/json;charset=UTF-8]
Date: ['Sat, 31 Mar 2018 21:42:20 GMT']
Set-Cookie: [JSESSIONID=B0C2C9C4A34AD24804043E6783B7B0FE;path=/;HttpOnly, atlassian.xsrf.token=B15V-IRV7-Q0YS-ZCZZ|51986e924c223fda4fa08d843277e1323d766014|lin;path=/]
Strict-Transport-Security: [max-age=315569260; preload]
Vary: [User-Agent]
X-Arequestid: [1302x8877x1]
X-Asen: [SEN-L11373089]
X-Asessionid: [1llg2ct]
X-Ausername: [nkprince007]
X-Content-Type-Options: [nosniff]
X-Frame-Options: [DENY, SAMEORIGIN]
X-Seraph-Loginreason: [OK]
X-Xss-Protection: [1; mode=block, 1; mode=block]
status: {code: 200, message: OK}
version: 1
interactions:
- request:
body: '{}'
headers:
Accept:
- !!binary |
Ki8q
Accept-Encoding:
- !!binary |
Z3ppcCwgZGVmbGF0ZQ==
Connection:
- !!binary |
a2VlcC1hbGl2ZQ==
Content-Length: ['2']
Content-Type:
- !!binary |
YXBwbGljYXRpb24vanNvbg==
User-Agent:
- !!binary |
SUdpdHQ=
method: GET
uri: https://jira.gitmate.io/rest/api/2/issue/10001?per_page=100
response:
body:
string: !!binary |
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
CiwAAA==
headers:
Cache-Control: ['no-cache, no-store, no-transform']
Content-Encoding: [gzip]
Content-Security-Policy: [frame-ancestors 'self']
Content-Type: [application/json;charset=UTF-8]
Date: ['Sun, 01 Apr 2018 08:26:15 GMT']
Set-Cookie: [JSESSIONID=4F0B43942F2826BC5AD008B6B4921E5A;path=/;HttpOnly, atlassian.xsrf.token=B15V-IRV7-Q0YS-ZCZZ|7bbdd6a72875a4316fc87a5c73b1ca8ad49f5ceb|lin;path=/]
Strict-Transport-Security: [max-age=315569260; preload]
Vary: [User-Agent]
X-Arequestid: [506x8884x1]
X-Asen: [SEN-L11373089]
X-Asessionid: [6tnxt6]
X-Ausername: [nkprince007]
X-Content-Type-Options: [nosniff]
X-Frame-Options: [DENY, SAMEORIGIN]
X-Seraph-Loginreason: [OK]
X-Xss-Protection: [1; mode=block, 1; mode=block]
status: {code: 200, message: OK}