Skip to content

Commit b2e99f2

Browse files
author
Gonchik Tsymzhitov
committed
2 parents 768b7d2 + 64a56ea commit b2e99f2

16 files changed

+949
-13
lines changed

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,8 @@ instance/
7070

7171
# Sphinx documentation
7272
docs/_build/
73+
Thumbs.db
74+
.DS_Store
7375

7476
# PyBuilder
7577
target/

README.rst

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,20 @@ Also, you can use the Bitbucket module e.g. for get project list
5858
data = bitbucket.project_list()
5959
print(data)
6060
61+
Now you can use Jira Service Desk module. See docs.
62+
Example to get your requests:
63+
64+
.. code-block:: python
65+
66+
from atlassian import ServiceDesk
67+
68+
sd = ServiceDesk(
69+
url='http://localhost:7990',
70+
username='admin',
71+
password='admin')
72+
my_requests = sd.get_my_customer_requests()
73+
print(my_requests)
74+
6175
Please make sure, you've checked ``examples/`` directory on how to build scripts using the API.
6276
If you want to see response in pretty print format json. Feel free for use construction like:
6377

atlassian/VERSION

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
1.10.3
1+
1.11.0

atlassian/__init__.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,5 +5,6 @@
55
from .portfolio import Portfolio
66
from .bamboo import Bamboo
77
from .crowd import Crowd
8+
from .service_desk import ServiceDesk
89

9-
__all__ = ['Confluence', 'Jira', 'Bitbucket', 'Portfolio', 'Bamboo', 'Stash', 'Crowd']
10+
__all__ = ['Confluence', 'Jira', 'Bitbucket', 'Portfolio', 'Bamboo', 'Stash', 'Crowd', 'ServiceDesk']

atlassian/confluence.py

Lines changed: 28 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ def get_page_child_by_type(self, page_id, type='page', start=None, limit=None):
3434
:param page_id: A string containing the id of the type content container.
3535
:param type:
3636
:param start: OPTIONAL: The start point of the collection to return. Default: None (0).
37-
:param limit: OPTIONAL: how many items should be returned after the start index. Default: Site limit.
37+
:param limit: OPTIONAL: how many items should be returned after the start index. Default: Site limit 200.
3838
:return:
3939
"""
4040
params = {}
@@ -46,7 +46,7 @@ def get_page_child_by_type(self, page_id, type='page', start=None, limit=None):
4646
url = 'rest/api/content/{page_id}/child/{type}'.format(page_id=page_id, type=type)
4747
log.info(url)
4848
try:
49-
return self.get(url)
49+
return (self.get(url, params=params) or {}).get('results')
5050
except IndexError as e:
5151
log.error(e)
5252
return None
@@ -66,7 +66,7 @@ def get_page_space(self, page_id):
6666
:param page_id: content ID
6767
:return:
6868
"""
69-
return self.get_page_by_id(page_id, expand='space')['space']['key']
69+
return ((self.get_page_by_id(page_id, expand='space') or {}).get('space') or {}).get('key')
7070

7171
def get_page_by_title(self, space, title, start=None, limit=None):
7272
"""
@@ -91,7 +91,7 @@ def get_page_by_title(self, space, title, start=None, limit=None):
9191
params['title'] = str(title)
9292
url = 'rest/api/content'
9393
try:
94-
return self.get(url, params=params).get('results')[0]
94+
return (self.get(url, params=params) or {}).get('results')[0]
9595
except IndexError as e:
9696
log.error(e)
9797
return None
@@ -159,7 +159,7 @@ def get_all_pages_from_space(self, space, start=0, limit=500):
159159
url = 'rest/api/content?spaceKey={space}&limit={limit}&start={start}'.format(space=space,
160160
limit=limit,
161161
start=start)
162-
return self.get(url)['results']
162+
return (self.get(url) or {}).get('results')
163163

164164
def get_all_pages_from_space_trash(self, space, start=0, limit=500, status='trashed'):
165165
"""
@@ -460,7 +460,7 @@ def get_page_ancestors(self, page_id):
460460
:return: get properties
461461
"""
462462
url = 'rest/api/content/{page_id}?expand=ancestors'.format(page_id=page_id)
463-
return self.get(path=url).get('ancestors')
463+
return (self.get(path=url) or {}).get('ancestors')
464464

465465
def clean_all_caches(self):
466466
""" Clean all caches from cache management"""
@@ -580,4 +580,25 @@ def export_page(self, page_id):
580580
:param page_id: Page ID
581581
:return: PDF File
582582
"""
583-
return self.get_page_as_pdf(page_id)
583+
return self.get_page_as_pdf(page_id)
584+
585+
def get_descendant_page_id(self, space, parent_id, title):
586+
"""
587+
Provide space, parent_id and title of the descendant page, it will return the descendant page_id
588+
:param space: str
589+
:param parent_id: int
590+
:param title: str
591+
:return: page_id of the page whose title is passed in argument
592+
"""
593+
page_id = ""
594+
595+
url = 'rest/api/content/search?cql=parent={}%20AND%20space="{}"'.format(
596+
parent_id, space
597+
)
598+
response = self.get(url, {})
599+
600+
for each_page in response.get("results", []):
601+
if each_page.get("title") == title:
602+
page_id = each_page.get("id")
603+
break
604+
return page_id

atlassian/jira.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -292,11 +292,11 @@ def issue_create_or_update(self, fields):
292292
def get_issue_transitions(self, issue_key):
293293
url = 'rest/api/2/issue/{issue_key}?expand=transitions.fields&fields=status'.format(issue_key=issue_key)
294294
return [{'name': transition['name'], 'id': int(transition['id']), 'to': transition['to']['name']}
295-
for transition in self.get(url)['transitions']]
295+
for transition in (self.get(url) or {}).get('transitions')]
296296

297297
def get_status_id_from_name(self, status_name):
298298
url = 'rest/api/2/status/{name}'.format(name=status_name)
299-
return int(self.get(url)['id'])
299+
return int((self.get(url) or {}).get('id'))
300300

301301
def get_transition_id_to_status_name(self, issue_key, status_name):
302302
for transition in self.get_issue_transitions(issue_key):
@@ -313,7 +313,7 @@ def set_issue_status(self, issue_key, status_name):
313313

314314
def get_issue_status(self, issue_key):
315315
url = 'rest/api/2/issue/{issue_key}?fields=status'.format(issue_key=issue_key)
316-
return self.get(url)['fields']['status']['name']
316+
return (self.get(url) or {}).get('fields').get('status').get('name')
317317

318318
def component(self, component_id):
319319
return self.get('rest/api/2/component/{component_id}'.format(component_id=component_id))

atlassian/service_desk.py

Lines changed: 137 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,137 @@
1+
# coding: utf8
2+
import logging
3+
from .rest_client import AtlassianRestAPI
4+
5+
log = logging.getLogger(__name__)
6+
7+
8+
class ServiceDesk(AtlassianRestAPI):
9+
def get_info(self):
10+
""" Get info about Service Desk app """
11+
return self.get('rest/servicedeskapi/info')
12+
13+
def create_customer(self, full_name, email):
14+
"""
15+
Creating customer user
16+
17+
:param full_name: str
18+
:param email: str
19+
:return: New customer
20+
"""
21+
log.warning('Creating customer...')
22+
data = {'fullName': full_name, 'email': email}
23+
headers = {'Content-Type': 'application/json',
24+
'Accept': 'application/json',
25+
'X-ExperimentalApi': 'opt-in'
26+
}
27+
return self.post('rest/servicedeskapi/customer', headers=headers, data=data)
28+
29+
def get_customer_request(self, issue_id_or_key):
30+
"""
31+
Get single request
32+
33+
:param issue_id_or_key: str
34+
:return: Customer request
35+
"""
36+
return self.get('rest/servicedeskapi/request/{}'.format(issue_id_or_key))
37+
38+
def get_my_customer_requests(self):
39+
""" Returning requests where you are the assignee """
40+
requests = self.get('rest/servicedeskapi/request')
41+
requests_values = requests.get('values')
42+
return requests_values
43+
44+
def create_customer_request(self, service_desk_id, request_type_id, values_dict):
45+
"""
46+
Creating customer request
47+
48+
:param service_desk_id: str
49+
:param request_type_id: str
50+
:param values_dict: str
51+
:return: New request
52+
"""
53+
log.warning('Creating request...')
54+
data = {"serviceDeskId": service_desk_id,
55+
"requestTypeId": request_type_id,
56+
"requestFieldValues": values_dict
57+
}
58+
return self.post('rest/servicedeskapi/request', data=data)
59+
60+
def get_customer_request_status(self, issue_id_or_key):
61+
"""
62+
Get customer request status name
63+
64+
:param issue_id_or_key: str
65+
:return: Status name
66+
"""
67+
request = self.get('rest/servicedeskapi/request/{}/status'.format(issue_id_or_key)).get('values')
68+
status = request[0].get('status')
69+
return status
70+
71+
def perform_transition(self, issue_id_or_key, transition_id, comment=None):
72+
"""
73+
Perform a customer transition for a given request and transition ID.
74+
An optional comment can be included to provide a reason for the transition.
75+
76+
:param issue_id_or_key: str
77+
:param transition_id: str
78+
:param comment: OPTIONAL: str
79+
:return: None
80+
"""
81+
log.warning('Performing transition...')
82+
headers = {'Content-Type': 'application/json',
83+
'Accept': 'application/json',
84+
'X-ExperimentalApi': 'opt-in'
85+
}
86+
data = {'id': transition_id, 'additionalComment': {'body': comment}}
87+
url = 'rest/servicedeskapi/request/{}/transition'.format(issue_id_or_key)
88+
return self.post(url, headers=headers, data=data)
89+
90+
def create_request_comment(self, issue_id_or_key, body, public=True):
91+
"""
92+
Creating request comment
93+
94+
:param issue_id_or_key: str
95+
:param body: str
96+
:param public: OPTIONAL: bool (default is True)
97+
:return: New comment
98+
"""
99+
log.warning('Creating comment...')
100+
data = {"body": body, "public": public}
101+
return self.post('rest/servicedeskapi/request/{}/comment'.format(issue_id_or_key), data=data)
102+
103+
def get_request_comments(self, issue_id_or_key):
104+
"""
105+
Get all comments in issue
106+
107+
:param issue_id_or_key: str
108+
:return: Issue comments
109+
"""
110+
return self.get('rest/servicedeskapi/request/{}/comment'.format(issue_id_or_key))
111+
112+
def get_request_comment_by_id(self, issue_id_or_key, comment_id):
113+
"""
114+
Get single comment by ID
115+
116+
:param issue_id_or_key: str
117+
:param comment_id: str
118+
:return: Single comment
119+
"""
120+
return self.get('rest/servicedeskapi/request/{0}/comment/{1}'.format(issue_id_or_key, comment_id))
121+
122+
def get_organisations(self, start=0, limit=50):
123+
"""
124+
Returns a list of organizations in the JIRA instance. If the user is not an agent, the resource returns a list of organizations the user is a member of.
125+
:param start: OPTIONAL: int The starting index of the returned objects.
126+
Base index: 0. See the Pagination section for more details.
127+
:param limit: OPTIONAL: int The maximum number of users to return per page.
128+
Default: 50. See the Pagination section for more details.
129+
:return:
130+
"""
131+
params = {}
132+
if start is not None:
133+
params["start"] = int(start)
134+
if limit is not None:
135+
params["limit"] = int(limit)
136+
137+
return self.get('rest/servicedeskapi/organization', params=params)

docs/Makefile

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
# Minimal makefile for Sphinx documentation
2+
#
3+
4+
# You can set these variables from the command line.
5+
SPHINXOPTS =
6+
SPHINXBUILD = sphinx-build
7+
SOURCEDIR = .
8+
BUILDDIR = _build
9+
10+
# Put it first so that "make" without argument is like "make help".
11+
help:
12+
@$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
13+
14+
.PHONY: help Makefile
15+
16+
# Catch-all target: route all unknown targets to Sphinx using the new
17+
# "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS).
18+
%: Makefile
19+
@$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)

docs/bitbucket.rst

Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
Bitbucket module
2+
================
3+
4+
Manage projects
5+
---------------
6+
7+
.. code-block:: python
8+
9+
# Project list
10+
bitbucket.project_list()
11+
12+
# Project info
13+
bitbucket.project(key)
14+
15+
# Get users who has permission in project
16+
bitbucket.project_users(key, limit=99999)
17+
18+
# Get project administrators for project
19+
butbucket.project_users_with_administrator_permissions(key)
20+
21+
# Get Project Groups
22+
bitbucket.project_groups(key, limit=99999)
23+
24+
# Get groups with admin permissions
25+
bitbucket.project_groups_with_administrator_permissions(key)
26+
27+
# Project summary
28+
butbucket.project_summary(key)
29+
30+
Groups and admins
31+
-----------------
32+
33+
.. code-block:: python
34+
35+
# Get group of members
36+
bitbucket.group_members(group, limit=99999)
37+
38+
# All project administrators
39+
bitbucket.all_project_administrators()
40+
41+
Manage code
42+
-----------
43+
44+
.. code-block:: python
45+
46+
# Get repositories list from project
47+
bitbucket.repo_list(project_key, limit=25)
48+
49+
# Get branches from repo
50+
bitbucket.get_branches(project, repository, filter='', limit=99999, details=True)
51+
52+
# Delete branch from related repo
53+
bitbucket.delete_branch(project, repository, name, end_point)
54+
55+
# Get pull requests
56+
bitbucket.get_pull_requests(project, repository, state='OPEN', order='newest', limit=100, start=0)
57+
58+
# Get tags for related repo
59+
bitbucket.get_tags(project, repository, filter='', limit=99999)
60+
61+
# Get project tags
62+
# The authenticated user must have REPO_READ permission for the context repository to call this resource
63+
bitbucket.get_project_tags(project, repository, tag_name)
64+
65+
# Set tag
66+
# The authenticated user must have REPO_WRITE permission for the context repository to call this resource
67+
bitbucket.set_tag(project, repository, tag_name, commit_revision, description=None)
68+
69+
# Delete tag
70+
# The authenticated user must have REPO_WRITE permission for the context repository to call this resource
71+
bitbucket.delete_tag(project, repository, tag_name)
72+
73+
# Get diff
74+
bitbucket.get_diff(project, repository, path, hash_oldest, hash_newest)
75+
76+
# Get commit list from repo
77+
bitbucket.get_commits(project, repository, hash_oldest, hash_newest, limit=99999)
78+
79+
# Get change log between 2 refs
80+
bitbucket.get_changelog(project, repository, ref_from, ref_to, limit=99999)
81+
82+
# Get raw content of the file from repo
83+
bitbucket.get_content_of_file(project, repository, filename)

0 commit comments

Comments
 (0)