def run_status(self, ticket_id, status=None): """Updates the status of a ticket. usage: cm status ticket_id [new_status] """ ticket_id = text.validate_id(ticket_id) self.login() # Get all the available actions for this ticket r = self.get("/ticket/%d" % ticket_id) timestamp = text.extract_timestamp(r.content) statuses = text.extract_statuses(r.content) # A ``status`` was provided, try to find the exact match, else just # display the current status for this ticket, and the available ones. if status: status = text.fuzzy_find(status, statuses) if not status: raise exceptions.FatalError("bad status (for this ticket: %s)" % \ ", ".join(statuses)) else: status = text.extract_status_from_ticket_page(r.content) print("Current status: %s" % status) print("Available statuses: %s" % ", ".join(statuses)) return if self.message: comment = self.message elif self.add_comment: comment = self._read_comment() else: comment = "" r = self.post("/ticket/%d" % ticket_id, { "ts": timestamp, "action": status, "comment": comment, }) if "system-message" in r.content or r.status_code != 200: raise exceptions.FatalError("unable to set status")
def run_new(self, owner=None): """Create a new ticket and return its id if successful. usage: cm new [owner] """ owner = owner or self.username self.login() valid = False headers = { "Subject": "", "To": owner, "Cc": "", "Milestone": "", "Component": "", "Priority": "2", "Type": "defect", "Keywords": "", "Version": "", } body = "\n" while not valid: # Get the properties at each iteration, in case an admin updated # the list in the mean time, especially because of this new ticket. properties = self._get_properties() # Assume the user will produce a valid ticket valid = True # Load the current values in a temp file for editing (fd, filename) = tempfile.mkstemp(suffix=".cm.ticket") fp = os.fdopen(fd, "w") fp.write(self._format_headers(headers)) fp.write("\n\n") fp.write(body) fp.close() self._editor(filename) # Use the email parser to get the headers. ep = email.parser.Parser() with open(filename, "r") as fp: em = ep.parse(fp) os.unlink(filename) body = em.get_payload() headers.update(em) errors = [] fuzzy_match_fields = ("Milestone", "Component", "Type", "Version", "Priority") # Ensures all the required fields are filled-in for key in self.required_fields: if key in fuzzy_match_fields: continue if not headers[key] or "**ERROR**" in headers[key]: errors.append("Invalid '%s': cannot be blank" % key) # Some fields are tolerant to incomplete values, this is where we # try to complete them. for key in fuzzy_match_fields: valid_options = properties[key.lower()]["options"] if headers[key] not in valid_options: m = text.fuzzy_find(headers[key], valid_options) if m: headers[key] = m else: if key in self.required_fields: errors.append("Invalid '%s': expected: %s" % \ (key, ", ".join(valid_options))) else: headers[key] = "" if errors: valid = False print("\nFound the following errors:") for error in errors: print(" - %s" % error) try: self._input("\n-- Hit Enter to return to editor, "\ "^C to abort --\n") except KeyboardInterrupt: raise exceptions.FatalError("ticket creation interrupted") r = self.post("/newticket", { "field_summary": headers["Subject"], "field_type": headers["Type"], "field_version": headers["Version"], "field_description": body, "field_milestone": headers["Milestone"], "field_component": headers["Component"], "field_owner": headers["To"], "field_keywords": headers["Keywords"], "field_cc": headers["Cc"], "field_attachment": "", }) if r.status_code != 200: raise exceptions.RequestException("unable to create new ticket.") try: ticket_id = int(r.url.split("/")[-1]) except: raise exceptions.RequestException("returned ticket_id is invalid.") self.open_in_browser_on_request(ticket_id) print("ticket #%d created" % ticket_id)