__init__.py (5934B)
1 #Embedded file name: C:\BuildAgent\work\20d73f1b24eed06e\eve\release\V24.01\packages\bugreporter\__init__.py 2 from __future__ import print_function 3 import requests 4 from bugreporter.util import GuessMimeType 5 import json 6 import mimetools 7 import logging 8 from cStringIO import StringIO 9 import uthread2 10 11 class BugReporter(object): 12 13 def __init__(self, serverUrl, cacheFolder = None): 14 if cacheFolder is None: 15 cacheFolder = '.cache' 16 self.cacheFolder = cacheFolder 17 self.logger = logging.getLogger('bugreporter') 18 self.baseUrl = serverUrl 19 20 def GetCategories(self): 21 ret = [] 22 for each in self._HttpGet('eve/issue/categories')['categories']: 23 ret.append((each['value'], each['id'])) 24 25 return ret 26 27 def SendBugReport(self, categoryName, title, description, reproSteps, sessionInfo, computerInfo, userID, labels, server, build, files): 28 data = self._GetData(categoryName, title, description, reproSteps, sessionInfo, computerInfo, userID, labels, server, build) 29 response = self._HttpPost('eve/issue/new', data) 30 issueID = response['id'] 31 self._SendAttachments(issueID, files) 32 return response 33 34 def IsBugsServiceOnline(self): 35 try: 36 return self._HttpGet('status/health')['isOnline'] 37 except KeyError: 38 return False 39 except Exception: 40 self.logger.exception('Bugs service not answering IsOnline') 41 return False 42 43 def _SendAttachments(self, issueID, files): 44 try: 45 for fileName, fileData in files: 46 self._SendAttachment(issueID, fileName, fileData) 47 48 except Exception as e: 49 self.logger.exception(e) 50 raise SendAttachmentError() 51 52 def _SendAttachment(self, issueID, fileName, fileData, retries = 5): 53 contentType, buffer = self._MultipartEncode(fileName, fileData) 54 urlAddition = 'eve/issue/{}/attachments/add'.format(issueID) 55 exception = None 56 while retries > 0 or exception is None: 57 try: 58 self._Request(urlAddition, 'POST', body=buffer, contentType=contentType) 59 return 60 except requests.ConnectionError as exception: 61 self.logger.info(exception) 62 uthread2.Sleep(2.0 / 2 ** retries) 63 retries -= 1 64 65 raise exception 66 67 def _MultipartEncode(self, fileName, fileData): 68 boundary = mimetools.choose_boundary() 69 buf = self._GetBufferForFile(boundary, fileData, fileName) 70 contentType = self._GetContentTypeForFile(boundary) 71 return (contentType, buf) 72 73 def _GetContentTypeForFile(self, boundary): 74 contentType = 'multipart/form-data; boundary={}'.format(boundary) 75 return contentType 76 77 def _GetBufferForFile(self, boundary, fileData, fileName): 78 buf = StringIO() 79 buf.write('--%s\r\n' % boundary) 80 buf.write('Content-Disposition: form-data; name="File"; filename="%s"\r\n' % (fileName,)) 81 buf.write('Content-Type: %s\r\n' % GuessMimeType(fileName)) 82 buf.write('\r\n' + fileData + '\r\n') 83 buf.write('--{}--\r\n'.format(boundary)) 84 buf = buf.getvalue() 85 return buf 86 87 def _GetData(self, categoryID, title, description, reproSteps, sessionInfo, computerInfo, userID, labels, server, build): 88 description = '{} \n\nSession Info:\n{}'.format(description, sessionInfo) 89 return {'categoryID': str(categoryID), 90 'summary': title, 91 'description': description, 92 'reproductionSteps': reproSteps, 93 'computerInfo': computerInfo, 94 'originalReporterId': '{}'.format(userID), 95 'Server': server, 96 'Build': build, 97 'labels': labels} 98 99 def _HttpGet(self, urlAddition): 100 return json.loads(self._Request(urlAddition, 'GET')) 101 102 def _HttpPost(self, urlAddition, data): 103 return json.loads(self._Request(urlAddition, 'POST', json.dumps(data))) 104 105 def _Request(self, urlAddition, method, body = None, contentType = None): 106 self.logger.info("making a '%s' call to the bugs service '%s'", method, urlAddition) 107 url = '{}/{}'.format(self.baseUrl, urlAddition) 108 self.logger.info('url: {}'.format(url)) 109 if contentType is None: 110 contentType = 'application/json' 111 headers = {} 112 token = sm.GetService('connection').GetAccessToken() 113 if token is not None: 114 headers['Authorization'] = 'Bearer {}'.format(token) 115 if contentType is not None: 116 headers['Content-Type'] = contentType 117 if method == 'GET': 118 resp = requests.get(url, headers=headers) 119 elif method == 'POST': 120 resp = requests.post(url, data=body, headers=headers) 121 else: 122 raise RuntimeError('BugService unsupported method %s' % method) 123 self.logger.info('response: {}'.format(resp)) 124 content = resp.content 125 self.CheckResponse(resp, method) 126 return content 127 128 def CheckResponse(self, resp, method): 129 status_code = resp.status_code 130 if method == 'POST' and status_code not in (200, 201): 131 self.logger.error('Bug Service Error Code: %s', status_code, extra={'response': resp, 132 'fingerprint': ['bugservice', status_code]}) 133 raise RuntimeError('Unexpected error from the bugs service') 134 135 136 class SendAttachmentError(Exception): 137 pass 138 139 140 def SendTestBugReport(serverUrl): 141 bugReporter = BugReporter(serverUrl, '.cache') 142 categoryName, categoryID = bugReporter.GetCategories()[0] 143 response = bugReporter.SendBugReport(categoryID, 'title', 'description', 'repro steps', 'sessionInfo', 'computerInfo', 'charID', ['UI'], []) 144 print("Bug Report successfully created '{}'".format(response['self'])) 145 146 147 if __name__ == '__main__': 148 import sys 149 if len(sys.argv) > 1: 150 SendTestBugReport(sys.argv[1])