From af6bd7fe1d3849a1d4568da4c9e9d618930b1364 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jarek=20=C5=9Amiejczak?= Date: Wed, 2 Sep 2015 22:04:43 +0200 Subject: [PATCH 1/2] Initial bamboo support --- atlassian/__init__.py | 24 +++++++++++++++----- atlassian/bamboo.py | 52 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 71 insertions(+), 5 deletions(-) create mode 100644 atlassian/bamboo.py diff --git a/atlassian/__init__.py b/atlassian/__init__.py index c6dd219e4..321276a9e 100644 --- a/atlassian/__init__.py +++ b/atlassian/__init__.py @@ -1,7 +1,9 @@ import json import logging +from urllib.parse import urlencode, urljoin import requests + log = logging.getLogger("atlassian") @@ -22,12 +24,23 @@ def log_curl_debug(self, method, path, data=None, headers={}, level=logging.DEBU url='{0}{1}'.format(self.url, path)) log.log(level=level, msg=message) - def request(self, method='GET', path='/', data=None, + def resource_url(self, resource, version='latest'): + return urljoin('rest', version, resource) + + def request(self, method='GET', path='/', data=None, args=None, kwargs=None, headers={'Content-Type': 'application/json', 'Accept': 'application/json'}): self.log_curl_debug(method=method, path=path, headers=headers, data=data) + url = urljoin(self.url, path) + if data or args: + url += '?' + if data: + url += urlencode(params or {}) + if args: + url += ('&' if data else '') + '&'.join(args or []) + response = requests.request( method=method, - url='{0}{1}'.format(self.url, path), + url=url, headers=headers, data=json.dumps(data), auth=(self.username, self.password), @@ -42,8 +55,8 @@ def request(self, method='GET', path='/', data=None, response.raise_for_status() return response - def get(self, path, data=None, headers={'Content-Type': 'application/json', 'Accept': 'application/json'}): - return self.request('GET', path=path, data=data, headers=headers).json() + def get(self, path, data=None, args=None, kwargs=None, headers={'Content-Type': 'application/json', 'Accept': 'application/json'}): + return self.request('GET', path=path, args=args, kwargs=kwargs, data=data, headers=headers).json() def post(self, path, data=None, headers={'Content-Type': 'application/json', 'Accept': 'application/json'}): try: @@ -67,5 +80,6 @@ def delete(self, path, data=None, headers={'Content-Type': 'application/json', ' from .jira import Jira from .stash import Stash from .portfolio import Portfolio +from .bamboo import Bamboo -__all__ = ['Confluence', 'Jira', 'Stash', 'Portfolio'] +__all__ = ['Confluence', 'Jira', 'Stash', 'Portfolio', 'Bamboo'] diff --git a/atlassian/bamboo.py b/atlassian/bamboo.py new file mode 100644 index 000000000..fb56cd7d3 --- /dev/null +++ b/atlassian/bamboo.py @@ -0,0 +1,52 @@ +import logging +from atlassian import AtlassianRestAPI + + +log = logging.getLogger('atlassian.stash') + + +class Stash(AtlassianRestAPI): + + def projects_list(self, expand=None, favourite=False, cloverEnabled=False, start=0, limit=25): + args = () + kwargs = {} + return self.get(self.resource_url('project'), args=args, kwargs=kwargs) + + def plans_list(self, expand=None, favourite=False, cloverEnabled=False, start=0, limit=25): + pass + + def result_list(self, project_key=None, plan_key=None, build_number=None, + expand=None, favourite=False, cloverEnabled=False, label=None, + start=0, limit=25): + pass + + def get_project_latest_results(self, project, expand=None, favourite=False, cloverEnabled=False, label=None, + start=0, limit=25): + return self.result_list(project_key, expand=expand, favourite=favourite, cloverEnabled=cloverEnabled, + label=label, start=start, limit=limit) + + def get_plan_results(self, project_key, plan_key, expand=None, favourite=False, cloverEnabled=False, label=None, + start=0, limit=25): + return self.result_list(project_key, plan_key, expand=expand, favourite=favourite, cloverEnabled=cloverEnabled, + label=label, start=start, limit=limit) + + def get_result(self, project_key, plan_key, build_key, expand=None, favourite=False, cloverEnabled=False, label=None, + start=0, limit=25): + return self.result_list(project_key, plan_key, expand=expand, favourite=favourite, cloverEnabled=cloverEnabled, + label=label, start=start, limit=limit) + + def chart_list(self, reportKey, buildKeys, groupByPeriod, dateFrom=None, dateTo=None, + width=None, height=None): + return self.result_list() + + def reports_list(self, expand=None, start=0, limit=25): + pass + + def get_comments(self, project_key, plan_key, build_number): + pass + + def get_labels(self, project_key, plan_key, build_number): + pass + + def get_server_info(self): + pass \ No newline at end of file From 09a93873810ddb12bec4f82c366ea0a92d02d387 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jarek=20=C5=9Amiejczak?= Date: Sun, 6 Sep 2015 02:44:28 +0200 Subject: [PATCH 2/2] Implemented bamboo class --- atlassian/__init__.py | 23 +++++--- atlassian/bamboo.py | 126 ++++++++++++++++++++++++++++++------------ 2 files changed, 105 insertions(+), 44 deletions(-) diff --git a/atlassian/__init__.py b/atlassian/__init__.py index 321276a9e..00a40ad47 100644 --- a/atlassian/__init__.py +++ b/atlassian/__init__.py @@ -25,18 +25,18 @@ def log_curl_debug(self, method, path, data=None, headers={}, level=logging.DEBU log.log(level=level, msg=message) def resource_url(self, resource, version='latest'): - return urljoin('rest', version, resource) + return '/'.join(['rest', 'api', version, resource]) - def request(self, method='GET', path='/', data=None, args=None, kwargs=None, + def request(self, method='GET', path='/', data=None, flags=None, params=None, headers={'Content-Type': 'application/json', 'Accept': 'application/json'}): self.log_curl_debug(method=method, path=path, headers=headers, data=data) url = urljoin(self.url, path) - if data or args: + if params or flags: url += '?' - if data: + if params: url += urlencode(params or {}) - if args: - url += ('&' if data else '') + '&'.join(args or []) + if flags: + url += ('&' if params else '') + '&'.join(flags or []) response = requests.request( method=method, @@ -55,8 +55,8 @@ def request(self, method='GET', path='/', data=None, args=None, kwargs=None, response.raise_for_status() return response - def get(self, path, data=None, args=None, kwargs=None, headers={'Content-Type': 'application/json', 'Accept': 'application/json'}): - return self.request('GET', path=path, args=args, kwargs=kwargs, data=data, headers=headers).json() + def get(self, path, data=None, flags=None, params=None, headers={'Content-Type': 'application/json', 'Accept': 'application/json'}): + return self.request('GET', path=path, flags=flags, params=params, data=data, headers=headers).json() def post(self, path, data=None, headers={'Content-Type': 'application/json', 'Accept': 'application/json'}): try: @@ -73,7 +73,12 @@ def put(self, path, data=None, headers={'Content-Type': 'application/json', 'Acc return None def delete(self, path, data=None, headers={'Content-Type': 'application/json', 'Accept': 'application/json'}): - return self.request('DELETE', path=path, data=data, headers=headers).json() + """ + Deletes resources at given paths. + :rtype: dict + :return: Empty dictionary to have consistent interface. Some of Atlassian rest resources don't return any content. + """ + self.request('DELETE', path=path, data=data, headers=headers) from .confluence import Confluence diff --git a/atlassian/bamboo.py b/atlassian/bamboo.py index fb56cd7d3..7c08667ff 100644 --- a/atlassian/bamboo.py +++ b/atlassian/bamboo.py @@ -1,52 +1,108 @@ import logging from atlassian import AtlassianRestAPI - log = logging.getLogger('atlassian.stash') -class Stash(AtlassianRestAPI): +class Bamboo(AtlassianRestAPI): + + def base_list_call(self, resource, expand, favourite, cloverEnabled, start_index, max_results, **kwargs): + flags = [] + params = {'start-index': start_index, 'max-results': max_results} + if expand: + params['expand'] = expand + if favourite: + flags.append('favourite') + if cloverEnabled: + flags.append('cloverEnabled') + params.update(kwargs) + return self.get(self.resource_url(resource), flags=flags, params=params) + + def projects(self, expand=None, favourite=False, cloverEnabled=False, start_index=0, max_results=25): + return self.base_list_call('project', expand, favourite, cloverEnabled, start_index, max_results) + + def plans(self, expand=None, favourite=False, cloverEnabled=False, start_index=0, max_results=25): + return self.base_list_call("plan", expand, favourite, cloverEnabled, start_index, max_results) + + def results(self, project_key=None, plan_key=None, build_number=None, expand=None, favourite=False, + cloverEnabled=False, label=None, issueKey=None, start_index=0, max_results=25): + resource = "result" + if project_key and plan_key and build_number: + resource += "/{}-{}/{}".format(project_key, plan_key, build_number) + elif project_key and plan_key: + resource += "/{}-{}".format(project_key, plan_key) + elif project_key: + resource += '/' + project_key + + params = {} + if issueKey: + params['issueKey'] = issueKey + return self.base_list_call(resource, expand, favourite, cloverEnabled, start_index, max_results, **params) + + def latest_results(self, expand=None, favourite=False, cloverEnabled=False, label=None, issueKey=None, + start_index=0, max_results=25): + return self.results(expand=expand, favourite=favourite, cloverEnabled=cloverEnabled, + label=label, issueKey=issueKey, start_index=start_index, max_results=max_results) + + def project_latest_results(self, project_key, expand=None, favourite=False, cloverEnabled=False, label=None, issueKey=None, + start_index=0, max_results=25): + return self.results(project_key, expand=expand, favourite=favourite, cloverEnabled=cloverEnabled, + label=label, issueKey=issueKey, start_index=start_index, max_results=max_results) - def projects_list(self, expand=None, favourite=False, cloverEnabled=False, start=0, limit=25): - args = () - kwargs = {} - return self.get(self.resource_url('project'), args=args, kwargs=kwargs) + def plan_results(self, project_key, plan_key, expand=None, favourite=False, cloverEnabled=False, label=None, issueKey=None, + start_index=0, max_results=25): + return self.results(project_key, plan_key, expand=expand, favourite=favourite, cloverEnabled=cloverEnabled, + label=label, issueKey=issueKey, start_index=start_index, max_results=max_results) - def plans_list(self, expand=None, favourite=False, cloverEnabled=False, start=0, limit=25): - pass + def build_result(self, project_key, plan_key, build_key, expand=None, favourite=False, cloverEnabled=False, label=None, issueKey=None, + start_index=0, max_results=25): + return self.results(project_key, plan_key, expand=expand, favourite=favourite, cloverEnabled=cloverEnabled, + label=label, issueKey=issueKey, start_index=start_index, max_results=max_results) - def result_list(self, project_key=None, plan_key=None, build_number=None, - expand=None, favourite=False, cloverEnabled=False, label=None, - start=0, limit=25): - pass + def reports(self, expand=None, start_index=0, max_results=25): + params = {'start-index': start_index, 'max-results': max_results} + if expand: + params['expand'] = expand - def get_project_latest_results(self, project, expand=None, favourite=False, cloverEnabled=False, label=None, - start=0, limit=25): - return self.result_list(project_key, expand=expand, favourite=favourite, cloverEnabled=cloverEnabled, - label=label, start=start, limit=limit) + return self.get(self.resource_url('chart/reports'), params=params) - def get_plan_results(self, project_key, plan_key, expand=None, favourite=False, cloverEnabled=False, label=None, - start=0, limit=25): - return self.result_list(project_key, plan_key, expand=expand, favourite=favourite, cloverEnabled=cloverEnabled, - label=label, start=start, limit=limit) + def chart(self, reportKey, buildKeys, groupByPeriod, dateFilter=None, dateFrom=None, dateTo=None, + width=None, height=None, start_index=9, max_results=25): + params = {'reportKey': reportKey, 'buildKeys': buildKeys, 'groupByPeriod': groupByPeriod, + 'start-index': start_index, 'max-results': max_results} + if dateFilter: + params['dateFilter'] = dateFilter + if dateFilter == 'RANGE': + params['dateFrom'] = dateFrom + params['dateTo'] = dateTo + if width: + params['width'] = width + if height: + params['height'] = height + return self.get(self.resource_url('chart'), params=params) - def get_result(self, project_key, plan_key, build_key, expand=None, favourite=False, cloverEnabled=False, label=None, - start=0, limit=25): - return self.result_list(project_key, plan_key, expand=expand, favourite=favourite, cloverEnabled=cloverEnabled, - label=label, start=start, limit=limit) + def comments(self, project_key, plan_key, build_number, start_index=0, max_results=25): + resource = "result/{}-{}-{}/comment".format(project_key, plan_key, build_number) + params = {'start-index': start_index, 'max-results': max_results} + return self.get(self.resource_url(resource), params=params) - def chart_list(self, reportKey, buildKeys, groupByPeriod, dateFrom=None, dateTo=None, - width=None, height=None): - return self.result_list() + def create_comment(self, project_key, plan_key, build_number, comment, author=None): + resource = "result/{}-{}-{}/comment".format(project_key, plan_key, build_number) + comment_data = {'author': author if author else self.username, 'content': comment} + return self.post(self.resource_url(resource), data=comment_data) - def reports_list(self, expand=None, start=0, limit=25): - pass + def labels(self, project_key, plan_key, build_number, start_index=0, max_results=25): + resource = "result/{}-{}-{}/label".format(project_key, plan_key, build_number) + params = {'start-index': start_index, 'max-results': max_results} + return self.get(self.resource_url(resource), params=params) - def get_comments(self, project_key, plan_key, build_number): - pass + def create_label(self, project_key, plan_key, build_number, label): + resource = "result/{}-{}-{}/label".format(project_key, plan_key, build_number) + return self.post(self.resource_url(resource), data={'name': label}) - def get_labels(self, project_key, plan_key, build_number): - pass + def delete_label(self, project_key, plan_key, build_number, label): + resource = "result/{}-{}-{}/label/{}".format(project_key, plan_key, build_number, label) + return self.delete(self.resource_url(resource)) - def get_server_info(self): - pass \ No newline at end of file + def server_info(self): + return self.get(self.resource_url('info'))