def request(self, method="get"): """ Request REST API Call :return: HTTP status code """ assert (self.rest_url and self.rest_url != "") if self._is_network_initialized is False: raise ConnectionError("Not initialized yet.") self.log("HTTP Request URL : " + self.base_url + self.rest_url) self.log("HTTP Request headers :", self.http_headers) self.res_body = None self.res = requests.request(method=method, url=self.base_url + self.rest_url, headers=self.http_headers, auth=(self.username, self.password), params=self.http_args, data=self.post_body, proxies=self.proxies) try: self.res_body = util.VersatileDict(self.res.json()) except ValueError: # Not json format self.res_body = None self.log("HTTP Request URL: %s" % self.res.url) self.log("HTTP Response status : %d" % self.res.status_code) if self.res.status_code == requests.codes.unauthorized: self.log("Status Code: %d, Message: Unauthorized, URL: %s" % (self.res.status_code, self.res.url)) return self.res.status_code
def __init__(self, obj=None, mapping=DEFAULT_JIRA_FIELDS_MAP, server_url=None, username=None, password=None, permission=PERMISSION_READ, debug_level=0): """ :param obj: JIRA Issue data. VersatilaDict type or Dictionary :param mapping: JIRA Field and JSON Path mapping dictionary or JIRAFieldsMap :param server_url: :param username: :param password: :param debug_level: :return: """ if obj: if isinstance(obj, util.VersatileDict): self._data = obj else: self._data = util.VersatileDict(obj) if isinstance(mapping, JIRAFieldsMap): self.map = mapping else: self.map = JIRAFieldsMap(mapping) for field in mapping.keys(): # set key names to attributes try: v = self.map.value(field) d = self._data.value(v) setattr(self, field, d) except KeyError: # Some key is absent in some project. Skip it. pass if server_url is not None: # if don't want to initialize network super().__init__(server_url=server_url, username=username, password=password, permission=permission, debug_level=debug_level) # Constructor of RESTNetwork
def create_issue(self, project_id, summary, issuetype, assignee=None, priority=None, description="", args={}): """ Create JIRA Issue. :param project_id: :param summary: :param issuetype: :param assignee: :param priority: :param description: :return: """ if self.is_writable() is False: raise PermissionError("Not writable") req_body = util.VersatileDict() req_body.add("fields/project/key", project_id) req_body.add("fields/summary", summary) req_body.add("fields/description", description) req_body.add("fields/issuetype/name", issuetype) if len(args) > 0: arg_list = list(args.keys()) for arg in arg_list: if args[arg] is None: continue self.log("Create issue arg => %s : %s" % (arg, args[arg])) req_body.add(arg, args[arg]) self.log("Issue creation json data:\n", req_body) self.set_post_body(req_body.json()) self.http_headers["Content-Type"] = "application/json" self.set_resturl("/issue") status = self.request_post() if status != requests.codes.created: self.log("Fail to create issue. Status Code: %d, URL: %s" % (status, self.res.url)) self.log(self.res.text) return status return status
def _update_field(self, key, value): """ Update field data :param value: field API path. ex) /fields/custom_1104 :return: HTTP code """ if self.is_writable() is False: raise PermissionError("Not writable") self.set_resturl("/issue/%s" % self.key) self.http_headers["Content-Type"] = "application/json" req_body = util.VersatileDict() req_body.add(key, value) self.set_post_body(req_body.json()) return self.request("put")
def assign(self, user): """ Assign issue to specific user. :param user: :return: """ if self.is_writable() is False: raise PermissionError("Not writable") self.set_resturl("/issue/%s/assignee" % self.key) self.http_headers["Content-Type"] = "application/json" req_body = util.VersatileDict() req_body.add("name", user) self.set_post_body(req_body.json()) return self.request("put")
def update_status(self, value): """ Update issue status :param value: new issue status :return: HTTP code """ if self.is_writable() is False: raise PermissionError("Not writable") self.set_resturl("/issue/%s/transitions" % self.key) self.http_headers["Content-Type"] = "application/json" req_body = util.VersatileDict() req_body.add("update", {}) req_body.add("transition/id", value) self.set_post_body(req_body.json()) return self.request_post()
def issue_sync(source_factory, target_factory): """ :param source_factory: :param target_factory: :return: """ loop = True start_at = 0 changed_count = 0 print (" ####################") print (" #### POST WORKS ####") print (" ####################") print() print (" #### Processing issues not assigned to S-Core ####\n") # No. Inter-key SPIN-key Summary print("%7s %-10s %-10s %s" % ("No.", "Inter-key", "SPIN-key", "Action")) while loop: print("=" * 80) # Phase 1. Get issues from Target target_factory.retrieve_search(jql="project = SPIN and status = Closed", max_results=JQL_MAX_RESULTS, start_at=start_at) if target_factory.http_status != 200: print("Fail to get issues from Target") sys.exit(-1) data = util.VersatileDict(target_factory.value()) total_count = int(data.value("total")) data._data = data.value("issues") # Phase 2. Find existing issue for i in range(JQL_MAX_RESULTS): # Exit loop condition if i + start_at >= total_count: loop = False break # Make issue instance for convenience target_issue = target_factory._new_issue_object(data.value(str(i)), DataMap.TARGET_JIRA_ISSUE_MAP) print("%4d:%2d %-10s %-10s " % (i + start_at, i, target_issue.key, target_issue.spin_id), end="") if target_issue.spin_id is None: print("Invalid Issue. SPIN ID is none. Skip") continue try: found_issue = find_issue_in_source(source_factory, target_issue) except ConnectionError as err: print(err, end="") found_issue = None # Phase 3. Change assignee if found_issue is None: continue # Phase 4. Change issue status. In fact, this phase is not necessary work, but convenient work for viewing result = target_issue.update_spin_resolved(found_issue.resolutiondate) if result == 204: print("RSV: updated with %s " % found_issue.resolutiondate, end="") else: errmsg = target_issue.value() print("RSV: [%s] " % (errmsg['errors']), end="") print("") start_at += JQL_MAX_RESULTS print("") print("Total changed: %d" % (changed_count))
def update_existing_issues(source_connection, target_connection): """ Update issues of target connection :param source_connection: :param target_connection: :return: """ loop = True start_at = 0 changed_count = 0 # No. Inter-key SPIN-key Summary print("%7s %-10s %-10s %s" % ("No.", "Target-key", "Source-key", "Action")) while loop: print("=" * 80) # STEP 1. Get issues from Target target_connection.retrieve_search(jql=DataMap.get_target_assigned_issue_jql(), max_results=JQL_MAX_RESULTS, start_at=start_at) if target_connection.http_status != 200: print("Fail to get issues from Target") sys.exit(-1) data = util.VersatileDict(target_connection.value()) total_count = int(data.value("total")) data._data = data.value("issues") # STEP 2. Find existing issue for i in range(JQL_MAX_RESULTS): assign_flag = False status_flag = False new_assignee = "" new_status = "" # Exit loop condition if i + start_at >= total_count: loop = False break # Make issue instance for convenience target_issue = target_connection._new_issue_object(data.value(str(i)), DataMap.TARGET_JIRA_ISSUE_MAP) print("%4d:%2d %-10s %-10s " % (i + start_at, i, target_issue.key, target_issue.spin_id), end="") if target_issue.spin_id is None: # if the issue is not imported from source. print("Invalid Issue. SPIN ID is none. Skip.") continue # STEP 3. Find source issue try: found_issue = find_issue_in_source(source_connection, target_issue) except ConnectionError as err: print(str(err), end="") found_issue = None except LookupError as err: print(str(err), end="") # STEP 4. Compare issues if found_issue and DataMap.get_user(found_issue.assignee) != DataMap.get_user(target_issue.assignee): assign_flag = True new_assignee = DataMap.get_user(found_issue.assignee) else: assign_flag = False if found_issue and DataMap.get_issue_status(found_issue.issuestatus) != target_issue.issuestatus: status_flag = True new_status = DataMap.get_issue_status(found_issue.issuestatus) else: status_flag = False if found_issue and found_issue.key != target_issue.spin_id: # TODO pass if not assign_flag and not status_flag: # if not changed, go next. print("Skip") continue # STEP 4. Change assignee if assign_flag: reporter = target_issue.reporter if new_status in ("Resolved", "Closed") and reporter == new_assignee: print("USR: automatic assign by issue resolve. Reporter: %s, Current assignee: %s" % (reporter, target_issue.assignee)) else: r = issue_assign(target_issue, new_assignee, True, UNASSIGNED_USER) print("USR: %s -> %s : %s " % (target_issue.assignee, new_assignee, r["MESSAGE"]), end="") # STEP 5. Change status if status_flag: # if closed issue, set resolved date before status changing, because closed issue can't be modified. if new_status == "Closed": target_issue.update_spin_resolved(found_issue.resolutiondate) transition_id = DataMap.get_transition_id(new_status) r = issue_change_status(target_issue, transition_id) print("STAT: %s -> %s : %s " % (target_issue.issuestatus, new_status, r["MESSAGE"]), end="") if new_status == "Closed": print("with Resolved date '%s'" % found_issue.resolutiondate, end="") print("") changed_count += 1 start_at += JQL_MAX_RESULTS print("") print("Total changed: %d" % changed_count)
def issue_importing(source_connection, target_connection): """ Issue migration part. In this function, all issue of source jira are copied to target jira, and issue status and assignee are changed. :param source_connection: :param target_connection: :return: """ loop = True start_at = 0 source_issue = jira.Issue() created_count = 0 # No. SPIN-Key Exist Action New Key, Summary print("%7s %-10s %-5s %-8s %-10s %s" % ("No.", "SPIN-key", "Exist", "Action", "New-key", "Summary")) while loop: print("=" * 80) # Phase 1. Get created issues from SPIN source_connection.retrieve_search(jql=DataMap.get_new_issues_jql(), max_results=JQL_MAX_RESULTS, start_at=start_at) if source_connection.http_status != 200: print("Fail to get issues from SPIN") sys.exit(-1) data = util.VersatileDict(source_connection.value()) total_count = int(data.value("total")) data._data = data.value("issues") # Phase 2. Insert issues to target JIRA for i in range(JQL_MAX_RESULTS): # Exit loop condition if i + start_at >= total_count: loop = False break # Make issue instance for convenience. source_issue is not a connected object. source_issue.set_data(data.value(str(i))) print("%4d:%2d %-10s " % (i + start_at, i, source_issue.key), end="") try: existing_issue = find_issue_in_target(target_connection, source_issue) except LookupError as e: print(str(e)) if not existing_issue: # Phase 1. Create issue print("%5s " % "N", end="") created_count += 1 r = issue_create(target_connection, source_issue) if r["CODE"] == 0: print("Created %-10s %s" % (target_connection.value("key"), source_issue.summary), end="") else: print("CR: %-10s" % r["MESSAGE"], end="") else: print("%5s " % "Y", end="") print("") start_at += JQL_MAX_RESULTS print("") print("Total imported: %d" % created_count) return created_count