5
5
import json
6
6
import webbrowser
7
7
import argparse
8
- from typing import Dict , List , Tuple
8
+ from typing import Dict , List , Tuple , Any
9
9
from abr_testing .data_collection import read_robot_logs , abr_google_drive , get_run_logs
10
10
11
+
11
12
def get_error_runs_from_robot (ip : str ) -> List [str ]:
12
13
"""Get runs that have errors from robot."""
13
14
error_run_ids = []
@@ -22,23 +23,28 @@ def get_error_runs_from_robot(ip: str) -> List[str]:
22
23
if not run ["current" ] and num_of_errors > 0 :
23
24
error_run_ids .append (run_id )
24
25
return error_run_ids
25
-
26
- def get_error_info_from_robot (ip : str , one_run : str , storage_directory : str )-> Tuple [str , str , str , List [str ], Dict [str , str ]] :
26
+
27
+
28
+ def get_error_info_from_robot (
29
+ ip : str , one_run : str , storage_directory : str
30
+ ) -> Tuple [str , str , str , List [str ], str , str ]:
27
31
"""Get error information from robot to fill out ticket."""
28
32
description = dict ()
29
33
# get run information
30
34
results = get_run_logs .get_run_data (one_run , ip )
31
35
# save run information to local directory as .json file
32
- saved_file_path = read_robot_logs .save_run_log_to_json (ip , results , storage_directory )
33
-
36
+ saved_file_path = read_robot_logs .save_run_log_to_json (
37
+ ip , results , storage_directory
38
+ )
39
+
34
40
# Error Printout
35
41
(
36
- num_of_errors ,
37
- error_type ,
38
- error_code ,
39
- error_instrument ,
40
- error_level ,
41
- ) = read_robot_logs .get_error_info (results )
42
+ num_of_errors ,
43
+ error_type ,
44
+ error_code ,
45
+ error_instrument ,
46
+ error_level ,
47
+ ) = read_robot_logs .get_error_info (results )
42
48
# JIRA Ticket Fields
43
49
failure_level = "Level " + str (error_level ) + " Failure"
44
50
components = [failure_level , "Flex-RABR" ]
@@ -47,35 +53,54 @@ def get_error_info_from_robot(ip: str, one_run: str, storage_directory: str)-> T
47
53
print (parent )
48
54
summary = parent + "_" + str (one_run ) + "_" + str (error_code ) + "_" + error_type
49
55
# Description of error
50
- description ["protocol_name" ] = results ["protocol" ]["metadata" ].get ("protocolName" , "" )
56
+ description ["protocol_name" ] = results ["protocol" ]["metadata" ].get (
57
+ "protocolName" , ""
58
+ )
51
59
description ["error" ] = " " .join ([error_code , error_type , error_instrument ])
52
60
description ["protocol_step" ] = list (results ["commands" ])[- 1 ]
53
61
description ["right_mount" ] = results .get ("right" , "No attachment" )
54
62
description ["left_mount" ] = results .get ("left" , "No attachment" )
55
63
description ["gripper" ] = results .get ("extension" , "No attachment" )
56
64
all_modules = abr_google_drive .get_modules (results )
57
65
whole_description = {** description , ** all_modules }
58
- whole_description_str = ("{" + "\n " .join ("{!r}: {!r}," .format (k , v ) for k , v in whole_description .items ()) + "}" )
59
-
60
- return summary , parent , affects_version , components , whole_description_str , saved_file_path
66
+ whole_description_str = (
67
+ "{"
68
+ + "\n " .join ("{!r}: {!r}," .format (k , v ) for k , v in whole_description .items ())
69
+ + "}"
70
+ )
71
+
72
+ return (
73
+ summary ,
74
+ parent ,
75
+ affects_version ,
76
+ components ,
77
+ whole_description_str ,
78
+ saved_file_path ,
79
+ )
80
+
61
81
62
82
class JiraTicket :
63
83
"""Connects to JIRA ticket site."""
84
+
64
85
def __init__ (self , url : str , api_token : str , email : str ) -> None :
65
86
"""Connect to jira."""
66
-
87
+
67
88
self .url = url
68
89
self .api_token = api_token
69
90
self .email = email
70
91
self .auth = HTTPBasicAuth (email , api_token )
71
92
self .headers = {
72
93
"Accept" : "application/json" ,
73
- "Content-Type" : "application/json"
74
- }
75
-
76
- def issues_on_board (self , board_id ) -> Dict [str , any ]:
94
+ "Content-Type" : "application/json" ,
95
+ }
96
+
97
+ def issues_on_board (self , board_id ) -> List [str ]:
77
98
"""Print Issues on board."""
78
- response = requests .get (f"{ self .url } /rest/agile/1.0/board/{ board_id } /issue" , headers = self .headers , auth = self .auth )
99
+ response = requests .get (
100
+ f"{ self .url } /rest/agile/1.0/board/{ board_id } /issue" ,
101
+ headers = self .headers ,
102
+ auth = self .auth ,
103
+ )
79
104
response .raise_for_status ()
80
105
try :
81
106
board_data = response .json ()
@@ -87,41 +112,47 @@ def issues_on_board(self, board_id) -> Dict[str, any]:
87
112
issue_id = i .get ("id" )
88
113
issue_ids .append (issue_id )
89
114
return issue_ids
90
-
91
- def open_issue (self , issue_key )-> None :
115
+
116
+ def open_issue (self , issue_key ) -> None :
92
117
"""Open issue on web browser."""
93
118
url = f"{ self .url } /browse/{ issue_key } "
94
119
webbrowser .open (url )
95
-
96
-
97
- def create_ticket (self , summary : str , description : str , project_key : str , issue_type : str , priority : str , components : list , affects_versions : str , robot : str ) -> str :
120
+
121
+ def create_ticket (
122
+ self ,
123
+ summary : str ,
124
+ description : str ,
125
+ project_key : str ,
126
+ issue_type : str ,
127
+ priority : str ,
128
+ components : list ,
129
+ affects_versions : str ,
130
+ robot : str ,
131
+ ) -> Tuple [str , str ]:
98
132
"""Create ticket."""
99
133
data = {
100
- "fields" : {
101
- "project" : {"id" : "10273" , "key" : project_key },
102
- "issuetype" : {"name" : issue_type },
103
- "summary" : summary ,
104
- "reporter" : {"accountId" : "712020:f32d03f8-f91a-465d-871b-45135b7b955f" },
105
- "parent " : { "key" : robot },
106
- "priority" : { "name" : priority },
107
- "components " : [{ "name " : component } for component in components ] ,
108
- "versions " : [ {"name" : affects_versions }] ,
109
- "description " : {
110
- "content " : [
111
- {
134
+ "fields" : {
135
+ "project" : {"id" : "10273" , "key" : project_key },
136
+ "issuetype" : {"name" : issue_type },
137
+ "summary" : summary ,
138
+ "reporter" : {
139
+ "accountId " : "712020:f32d03f8-f91a-465d-871b-45135b7b955f"
140
+ },
141
+ "parent " : { "key " : robot } ,
142
+ "priority " : {"name" : priority } ,
143
+ "components " : [{ "name" : component } for component in components ],
144
+ "versions " : [{ "name" : affects_versions }],
145
+ "description" : {
112
146
"content" : [
113
147
{
114
- " text" : description ,
115
- "type" : "text"
148
+ "content" : [{ " text" : description , "type" : "text" }] ,
149
+ "type" : "paragraph" ,
116
150
}
117
151
],
118
- "type" : "paragraph"
119
- }
120
- ],
121
- "type" : "doc" ,
122
- "version" : 1
152
+ "type" : "doc" ,
153
+ "version" : 1 ,
123
154
}
124
- # Include other required fields as needed
155
+ # Include other required fields as needed
125
156
}
126
157
}
127
158
try :
@@ -132,36 +163,35 @@ def create_ticket(self, summary: str, description: str, project_key: str, issue_
132
163
json = data ,
133
164
)
134
165
response .raise_for_status ()
166
+ response_str = str (response .content )
135
167
issue_url = response .json ().get ("self" )
136
168
issue_key = response .json ().get ("key" )
137
169
if issue_key is None :
138
170
print ("Error: Could not create issue. No key returned." )
139
- except requests .exceptions .HTTPError as e :
140
- print (f"HTTP error occurred: { e } " )
141
- print (f"Response content: { response .content } " )
142
- except json .JSONDecodeError as e :
143
- print (f"JSON decoding error occurred: { e } " )
144
- print (f"Response content: { response .content } " )
145
- except Exception as e :
146
- print (f"An unexpected error occurred: { e } " )
171
+ except requests .exceptions .HTTPError :
172
+ print (f"HTTP error occurred. Response content: { response_str } " )
173
+ except json .JSONDecodeError :
174
+ print (f"JSON decoding error occurred. Response content: { response_str } " )
147
175
return issue_url , issue_key
148
-
176
+
149
177
def post_attachment_to_ticket (self , issue_id : str , attachment_path : str ):
150
178
"""Adds attachments to ticket."""
151
- file = {"file" : open (attachment_path , 'rb' )}
179
+ # TODO: Ensure that file is actually uploaded.
180
+ file = {"file" : open (attachment_path , "rb" )}
152
181
JSON_headers = {"Accept" : "application/json" }
153
182
try :
154
183
response = requests .post (
155
184
f"{ self .url } /rest/api/3/issue/{ issue_id } /attachments" ,
156
- headers = JSON_headers ,
157
- auth = self .auth ,
158
- files = file
159
- )
185
+ headers = JSON_headers ,
186
+ auth = self .auth ,
187
+ files = file ,
188
+ )
160
189
print (response )
161
- except json .JSONDecodeError as e :
162
- print (f"JSON decoding error occurred: { e } " )
163
- print (f"Response content: { response .content } " )
164
-
190
+ except json .JSONDecodeError :
191
+ error_message = str (response .content )
192
+ print (f"JSON decoding error occurred. Response content: { error_message } ." )
193
+
194
+
165
195
if __name__ == "__main__" :
166
196
"""Create ticket for specified robot."""
167
197
parser = argparse .ArgumentParser (description = "Pulls run logs from ABR robots." )
@@ -173,11 +203,11 @@ def post_attachment_to_ticket(self, issue_id: str, attachment_path: str):
173
203
help = "Path to long term storage directory for run logs." ,
174
204
)
175
205
parser .add_argument (
176
- "robot_ip" ,
206
+ "robot_ip" ,
177
207
metavar = "ROBOT_IP" ,
178
- type = str ,
179
- nargs = 1 ,
180
- help = "IP address of robot as string."
208
+ type = str ,
209
+ nargs = 1 ,
210
+ help = "IP address of robot as string." ,
181
211
)
182
212
args = parser .parse_args ()
183
213
storage_directory = args .storage_directory [0 ]
@@ -186,14 +216,30 @@ def post_attachment_to_ticket(self, issue_id: str, attachment_path: str):
186
216
api_token = "ATATT3xFfGF0SZgHzGog6J_bTK3j6HFRnbUC-tE_gB5Sn_56d-NSdlRb5C-ywGxNgV4fHfSGbhgENlGKI1aSPc5dy8ql0EiVYW4dHifJhyKUueu5yq6BrL9Xcsfwz_p1W6xUmSsyecvZ0lGPFLb5sreqRg5kE3FRs6SqcKaQxH6_EGFGS0Obb5c=BA8756FE"
187
217
188
218
board_id = "217"
189
-
219
+
190
220
ticket = JiraTicket (url , api_token , email )
191
221
error_runs = get_error_runs_from_robot (ip )
192
222
one_run = error_runs [0 ]
193
223
print (one_run )
194
- summary , robot , affects_version , components , whole_description_str , saved_file_path = get_error_info_from_robot (ip , one_run , storage_directory )
224
+ (
225
+ summary ,
226
+ robot ,
227
+ affects_version ,
228
+ components ,
229
+ whole_description_str ,
230
+ saved_file_path ,
231
+ ) = get_error_info_from_robot (ip , one_run , storage_directory )
195
232
project_key = "RABR"
196
233
parent_key = project_key + "-" + robot [- 1 ]
197
- issue_url , issue_key = ticket .create_ticket (summary , whole_description_str , project_key , "Bug" , "Medium" , components , affects_version , parent_key )
234
+ issue_url , issue_key = ticket .create_ticket (
235
+ summary ,
236
+ whole_description_str ,
237
+ project_key ,
238
+ "Bug" ,
239
+ "Medium" ,
240
+ components ,
241
+ affects_version ,
242
+ parent_key ,
243
+ )
198
244
ticket .open_issue (issue_key )
199
245
ticket .post_attachment_to_ticket (issue_key , saved_file_path )
0 commit comments