Skip to content

Commit 83db73b

Browse files
authored
Merge pull request #1 from atlassian-api/master
Fetch
2 parents 4b020c7 + 12301e5 commit 83db73b

File tree

12 files changed

+197
-37
lines changed

12 files changed

+197
-37
lines changed

.whitesource

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
{
2+
"checkRunSettings": {
3+
"vulnerableCheckRunConclusionLevel": "failure"
4+
},
5+
"issueSettings": {
6+
"minSeverityLevel": "LOW"
7+
}
8+
}

atlassian/VERSION

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
1.13.29
1+
1.14.0

atlassian/bamboo.py

Lines changed: 11 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -365,10 +365,11 @@ def create_branch(self, plan_key, branch_name, vcs_branch=None, enabled=False, c
365365
:return: PUT request
366366
"""
367367
resource = 'plan/{plan_key}/branch/{branch_name}'.format(plan_key=plan_key, branch_name=branch_name)
368+
params = {}
368369
if vcs_branch:
369-
params = {'vcsBranch':vcs_branch}
370-
params['enabled'] = 'true' if enabled else 'false'
371-
params['cleanupEnabled'] = 'true' if cleanup_enabled else 'false'
370+
params = dict(vcsBranch=vcs_branch,
371+
enabled='true' if enabled else 'false',
372+
cleanupEnabled='true' if cleanup_enabled else 'false')
372373
return self.put(self.resource_url(resource), params=params)
373374

374375
def enable_plan(self, plan_key):
@@ -380,26 +381,26 @@ def enable_plan(self, plan_key):
380381
resource = 'plan/{plan_key}/enable'.format(plan_key=plan_key)
381382
return self.post(self.resource_url(resource))
382383

383-
def execute_build(self, plan_key, stage=None, executeAllStages=True, customRevision=None, **bamboo_variables):
384+
def execute_build(self, plan_key, stage=None, execute_all_stages=True, custom_revision=None, **bamboo_variables):
384385
"""
385386
Fire build execution for specified plan.
386387
!IMPORTANT! NOTE: for some reason, this method always execute all stages
387388
:param plan_key: str TST-BLD
388389
:param stage: str stage-name
389-
:param executeAllStages: bool
390-
:param customRevision: str revisionName
390+
:param execute_all_stages: bool
391+
:param custom_revision: str revisionName
391392
:param bamboo_variables: dict {variable=value}
392393
:return: POST request
393394
"""
394395
headers = self.form_token_headers
395396
resource = 'queue/{plan_key}'.format(plan_key=plan_key)
396397
params = {}
397398
if stage:
398-
executeAllStages = False
399+
execute_all_stages = False
399400
params['stage'] = stage
400-
if customRevision:
401-
params['customRevision'] = customRevision
402-
params['executeAllStages'] = 'true' if executeAllStages else 'false'
401+
if custom_revision:
402+
params['customRevision'] = custom_revision
403+
params['executeAllStages'] = 'true' if execute_all_stages else 'false'
403404
if bamboo_variables:
404405
for key, value in bamboo_variables.items():
405406
params['bamboo.variable.{}'.format(key)] = value

atlassian/bitbucket.py

Lines changed: 77 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66

77

88
class Bitbucket(AtlassianRestAPI):
9+
910
def project_list(self, limit=None):
1011
"""
1112
Provide the project list
@@ -17,14 +18,24 @@ def project_list(self, limit=None):
1718
params['limit'] = limit
1819
return (self.get('rest/api/1.0/projects', params=params) or {}).get('values')
1920

21+
def repo_list(self, project_key):
22+
"""
23+
Provide the repository list in a specific BB project
24+
:param project_key: The Project Key ID you need to list
25+
return:
26+
"""
27+
url = 'rest/api/1.0/projects/{projectKey}/repos?limit=1000'.format(
28+
projectKey=project_key)
29+
return self.get(url)
30+
2031
def project(self, key):
2132
"""
2233
Provide project info
2334
:param key:
2435
:return:
2536
"""
2637
url = 'rest/api/1.0/projects/{0}'.format(key)
27-
return (self.get(url) or {})
38+
return self.get(url) or {}
2839

2940
def create_project(self, key, name, description=""):
3041
"""
@@ -41,6 +52,48 @@ def create_project(self, key, name, description=""):
4152
}
4253
return self.post(url, data=data)
4354

55+
def update_project(self, key, **params):
56+
"""
57+
Update project
58+
:param key:
59+
:param **params:
60+
:return:
61+
"""
62+
data = self.project(key)
63+
if not 'errors' in data:
64+
data.update(params)
65+
url = 'rest/api/1.0/projects/{0}'.format(key)
66+
return self.put(url, data=data)
67+
else:
68+
log.debug('Failed to update project: {0}: Unable to read project'.format(key))
69+
return None
70+
71+
def project_avatar(self, key, content_type='image/png'):
72+
"""
73+
Get project avatar
74+
75+
:param key:
76+
:return:
77+
"""
78+
url = 'rest/api/1.0/projects/{0}/avatar.png'.format(key)
79+
headers = dict(self.default_headers)
80+
headers['Accept'] = content_type
81+
headers['X-Atlassian-Token'] = 'no-check'
82+
83+
return self.get(url, not_json_response=True, headers=headers) or {}
84+
85+
def set_project_avatar(self, key, icon, content_type='image/png'):
86+
"""
87+
Set project avatar
88+
89+
:param key:
90+
:return:
91+
"""
92+
headers = {'X-Atlassian-Token': 'no-check'}
93+
files = {'avatar': ("avatar.png", icon, content_type)}
94+
url = 'rest/api/1.0/projects/{0}/avatar.png'.format(key)
95+
return self.post(url, files=files, headers=headers) or {}
96+
4497
def project_users(self, key, limit=99999, filter_str=None):
4598
"""
4699
Get users who has permission in project
@@ -273,7 +326,8 @@ def project_summary(self, key):
273326
'key': key,
274327
'data': self.project(key),
275328
'users': self.project_users(key),
276-
'groups': self.project_groups(key)}
329+
'groups': self.project_groups(key),
330+
'avatar': self.project_avatar(key)}
277331

278332
def group_members(self, group, limit=99999):
279333
"""
@@ -726,25 +780,25 @@ def get_pullrequest(self, project, repository, pull_request_id):
726780
pullRequestId=pull_request_id)
727781
return self.get(url)
728782

729-
def change_reviewed_status(self, projectKey, repositorySlug, pullRequestId, status, userSlug):
783+
def change_reviewed_status(self, project_key, repository_slug, pull_request_id, status, user_slug):
730784
"""
731785
Change the current user's status for a pull request.
732786
Implicitly adds the user as a participant if they are not already.
733787
If the current user is the author, this method will fail.
734-
:param projectKey:
735-
:param repositorySlug:
736-
:param pullRequestId:
788+
:param project_key:
789+
:param repository_slug:
790+
:param pull_request_id:
737791
:param status:
738-
:param userSlug:
792+
:param user_slug:
739793
:return:
740794
"""
741-
url = "/rest/api/1.0/projects/{projectKey}/repos/{repositorySlug}/pull-requests/{pullRequestId}/participants/{userSlug}".format(
742-
projectKey=projectKey, repositorySlug=repositorySlug, pullRequestId=pullRequestId, userSlug=userSlug,
795+
url = "rest/api/1.0/projects/{projectKey}/repos/{repositorySlug}/pull-requests/{pullRequestId}/participants/{userSlug}".format(
796+
projectKey=project_key, repositorySlug=repository_slug, pullRequestId=pull_request_id, userSlug=user_slug,
743797
)
744798
approved = True if status == "APPROVED" else False
745799
data = {
746800
"user": {
747-
"name": userSlug
801+
"name": user_slug
748802
},
749803
"approved": approved,
750804
"status": status
@@ -1207,7 +1261,7 @@ def upload_file(self, project, repository, content, message, branch, filename):
12071261
filename=filename)
12081262
return self.put(url, files=data)
12091263

1210-
def update_file(self, project, repository, content, message, branch, filename, sourceCommitId):
1264+
def update_file(self, project, repository, content, message, branch, filename, source_commit_id):
12111265
"""
12121266
Update existing file for given branch.
12131267
:param project:
@@ -1216,14 +1270,14 @@ def update_file(self, project, repository, content, message, branch, filename, s
12161270
:param message:
12171271
:param branch:
12181272
:param filename:
1219-
:param sourceCommitId:
1273+
:param source_commit_id:
12201274
:return:
12211275
"""
12221276
data = {
12231277
"content": content,
12241278
"message": message,
12251279
"branch": branch,
1226-
"sourceCommitId": sourceCommitId
1280+
"sourceCommitId": source_commit_id
12271281
}
12281282

12291283
url = 'rest/api/1.0/projects/{project}/repos/{repository}/browse/{filename}'.format(
@@ -1232,33 +1286,34 @@ def update_file(self, project, repository, content, message, branch, filename, s
12321286
filename=filename)
12331287
return self.put(url, files=data)
12341288

1235-
def get_code_insights_report(self, projectKey, repositorySlug, commitId, report_key):
1289+
def get_code_insights_report(self, project_key, repository_slug, commit_id, report_key):
12361290
"""
12371291
Retrieve the specified code-insights report.
12381292
:projectKey: str
12391293
:repositorySlug: str
12401294
:commitId: str
12411295
:report_key: str
12421296
"""
1243-
url = "/rest/insights/1.0/projects/{projectKey}/repos/{repositorySlug}/commits/{commitId}/reports/{key}".format(
1244-
projectKey=projectKey, repositorySlug=repositorySlug, commitId=commitId, key=report_key
1297+
url = "rest/insights/1.0/projects/{projectKey}/repos/{repositorySlug}/commits/{commitId}/reports/{key}".format(
1298+
projectKey=project_key, repositorySlug=repository_slug, commitId=commit_id, key=report_key
12451299
)
12461300
return self.get(url)
12471301

1248-
def delete_code_insights_report(self, projectKey, repositorySlug, commitId, report_key):
1302+
def delete_code_insights_report(self, project_key, repository_slug, commit_id, report_key):
12491303
"""
12501304
Delete a report for the given commit. Also deletes any annotations associated with this report.
12511305
:projectKey: str
12521306
:repositorySlug: str
12531307
:commitId: str
12541308
:report_key: str
12551309
"""
1256-
url = "/rest/insights/1.0/projects/{projectKey}/repos/{repositorySlug}/commits/{commitId}/reports/{key}".format(
1257-
projectKey=projectKey, repositorySlug=repositorySlug, commitId=commitId, key=report_key
1310+
url = "rest/insights/1.0/projects/{projectKey}/repos/{repositorySlug}/commits/{commitId}/reports/{key}".format(
1311+
projectKey=project_key, repositorySlug=repository_slug, commitId=commit_id, key=report_key
12581312
)
12591313
return self.delete(url)
12601314

1261-
def create_code_insights_report(self, projectKey, repositorySlug, commitId, report_key, report_title, **report_params):
1315+
def create_code_insights_report(self, project_key, repository_slug, commit_id, report_key, report_title,
1316+
**report_params):
12621317
"""
12631318
Create a new insight report, or replace the existing one if a report already exists for the given repository, commit, and report key.
12641319
A request to replace an existing report will be rejected if the authenticated user was not the creator of the specified report.
@@ -1270,8 +1325,8 @@ def create_code_insights_report(self, projectKey, repositorySlug, commitId, repo
12701325
:report_title: str
12711326
:report_params:
12721327
"""
1273-
url = "/rest/insights/1.0/projects/{projectKey}/repos/{repositorySlug}/commits/{commitId}/reports/{key}".format(
1274-
projectKey=projectKey, repositorySlug=repositorySlug, commitId=commitId, key=report_key
1328+
url = "rest/insights/1.0/projects/{projectKey}/repos/{repositorySlug}/commits/{commitId}/reports/{key}".format(
1329+
projectKey=project_key, repositorySlug=repository_slug, commitId=commit_id, key=report_key
12751330
)
12761331
data = {"title": report_title}
12771332
data.update(report_params)

atlassian/jira.py

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -205,6 +205,19 @@ def user_delete_property(self, username, key_property):
205205
params = {'username': username}
206206
return self.delete(url, params=params)
207207

208+
def user_update_or_create_property_through_rest_point(self, username, key, value):
209+
"""
210+
ATTENTION!
211+
This method used after configuration of rest endpoint on Jira side
212+
:param username:
213+
:param key:
214+
:param value:
215+
:return:
216+
"""
217+
url = 'rest/scriptrunner/latest/custom/updateUserProperty'
218+
params = {'username': username, 'property': key, 'value': value}
219+
return self.get(url, params=params)
220+
208221
def user_update_email(self, username, email):
209222
"""
210223
Update user email for new domain changes
@@ -363,6 +376,19 @@ def get_project_versions_paginated(self, key, start=None, limit=None, order_by=N
363376
params['expand'] = expand
364377
return self.get('rest/api/2/project/{}/version'.format(key), params)
365378

379+
def add_version(self, project_key, project_id, version, is_archived=False, is_released=False):
380+
"""
381+
Add missing version to project
382+
:param project_key: the project key
383+
:param project_id: the project id
384+
:param version: the new project version to add
385+
:is_archived:
386+
:is_released:
387+
:return:
388+
"""
389+
payload = {'name': version, 'archived': is_archived, 'released': is_released, 'project': project_key, 'projectId': project_id}
390+
return self.post("rest/api/2/version", data = payload)
391+
366392
def get_project_roles(self, project_key):
367393
"""
368394
Provide associated project roles

atlassian/rest_client.py

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ class AtlassianRestAPI(object):
2020
response = None
2121

2222
def __init__(self, url, username=None, password=None, timeout=60, api_root='rest/api', api_version='latest',
23-
verify_ssl=True, session=None, oauth=None, cookies=None, advanced_mode=None):
23+
verify_ssl=True, session=None, oauth=None, cookies=None, advanced_mode=None, kerberos=None):
2424
if ('atlassian.net' in url or 'jira.com' in url) \
2525
and '/wiki' not in url \
2626
and self.__class__.__name__ in 'Confluence':
@@ -42,10 +42,29 @@ def __init__(self, url, username=None, password=None, timeout=60, api_root='rest
4242
self._create_basic_session(username, password)
4343
elif oauth is not None:
4444
self._create_oauth_session(oauth)
45+
elif kerberos is not None:
46+
self._create_kerberos_session(kerberos)
4547

4648
def _create_basic_session(self, username, password):
4749
self._session.auth = (username, password)
4850

51+
def _create_kerberos_session(self, kerberos_service):
52+
try:
53+
import kerberos as kerb
54+
except ImportError as e:
55+
log.error(e)
56+
try:
57+
import kerberos_sspi as kerb
58+
except ImportError:
59+
log.info("Please, fix issue with dependency of kerberos")
60+
return
61+
__, krb_context = kerb.authGSSClientInit(kerberos_service)
62+
kerb.authGSSClientStep(krb_context, "")
63+
auth_header = ("Negotiate " + kerb.authGSSClientResponse(krb_context))
64+
self._update_header("Authorization", auth_header)
65+
response = self._session.get(self.url, verify=self.verify_ssl)
66+
response.raise_for_status()
67+
4968
def _create_oauth_session(self, oauth_dict):
5069
oauth = OAuth1(oauth_dict['consumer_key'],
5170
rsa_key=oauth_dict['key_cert'], signature_method=SIGNATURE_RSA,

docs/bitbucket.rst

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,9 @@ Manage projects
99
# Project list
1010
bitbucket.project_list()
1111
12+
# Repo list
13+
bitbucket.repo_list(project_key)
14+
1215
# Project info
1316
bitbucket.project(key)
1417

docs/index.rst

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,29 @@ Alternatively OAuth can be used:
6969
url='http://localhost:8080',
7070
oauth=oauth_dict)
7171
72+
Or Kerberos:
73+
74+
.. code-block:: python
75+
76+
kerberos_service = 'HTTP/[email protected]'
77+
78+
jira = Jira(
79+
url='http://localhost:8080',
80+
kerberos=kerberos_service)
81+
82+
confluence = Confluence(
83+
url='http://localhost:8090',
84+
kerberos=kerberos_service)
85+
86+
bitbucket = Bitbucket(
87+
url='http://localhost:7990',
88+
kerberos=kerberos_service)
89+
90+
service_desk = ServiceDesk(
91+
url='http://localhost:8080',
92+
kerberos=kerberos_service)
93+
94+
7295
.. toctree::
7396
:maxdept:2
7497

@@ -93,4 +116,4 @@ Alternatively OAuth can be used:
93116
:alt: PyPI - Downloads
94117
.. |Docs| image:: https://readthedocs.org/projects/atlassian-python-api/badge/?version=latest
95118
:target: https://atlassian-python-api.readthedocs.io/en/latest/?badge=latest
96-
:alt: Documentation Status
119+
:alt: Documentation Status

0 commit comments

Comments
 (0)