class JiraService: jira: JIRA host: str def connect(self, host: str, user: UserCredentials) -> bool: try: self.host = host self.jira = JIRA(server=self.host, basic_auth=(user.username, user.password)) return True except Exception: return False def get_jira_name(self) -> str: return self.jira.myself()['displayName'] def get_jira_email(self) -> str: return self.jira.myself()['emailAddress'] def generate_issues_by_issue_keys(self, issue_keys): for issue_key in issue_keys: jira_issue = self.jira.issue(id=issue_key) jira_issue_browser_url = self.host + '/browse/' + issue_key jira_issue_summary = jira_issue.raw['fields']['summary'] yield SimpleJiraIssue(issue_key, jira_issue_summary, jira_issue_browser_url)
class JIRAClient(object): # pylint:disable=too-few-public-methods """A client for JIRA API.""" _ISSUE_JQL = 'project = {project_key} AND updated >= "{0}" ORDER BY key ASC' """JQL query format for listing all issues with worklogs to read.""" def __init__(self, config): # type: (dict) -> None """Initialize with credentials from the *config* dict.""" self._jira = JIRA(config['url'], basic_auth=(config['email'], config['jira_token'])) self._project_key = config.get('project_key') self.account_id = self._jira.myself()['accountId'] # type: str def _issues(self, query): # type: (str) -> Iterator[jira.Issue] """Issues iterator.""" issue_index = 1 while True: search_results = self._jira.search_issues(jql_str=query, startAt=issue_index, maxResults=50) for issue in search_results: yield issue issue_index += 51 if len(search_results) < 50: return def get_worklogs(self, from_date, single_user=True): # type: (date, bool) -> Iterator[Worklog] """ Return all recent worklogs for the specified user. :rtype: iterator :returns: yields Worklog instances """ for issue in self._issues( self._ISSUE_JQL.format(from_date, project_key=self._project_key)): for jira_worklog in self._jira.worklogs(issue): worklog = Worklog( id=int(jira_worklog.id), tempo_id=None, author=jira_worklog.author.accountId, time_spent_seconds=int(jira_worklog.timeSpentSeconds), issue=issue.key, started=arrow.get(jira_worklog.started), description=getattr(jira_worklog, 'comment', u''), ) if single_user and worklog.author != self.account_id: continue yield worklog
class JIRAClient: def __init__(self, server, consumer_key, key_cert_data, access_token, access_token_secret): oauth_dict = { 'access_token': access_token, 'access_token_secret': access_token_secret, 'consumer_key': consumer_key, 'key_cert': key_cert_data, } self.jira = JIRA(server, oauth=oauth_dict) def emailAddress(self): return self.jira.myself()['emailAddress'] def issues(self, pkey): try: return self.jira.search_issues('project = "{}"'.format(pkey)) except JIRAError: return None
class JIRAClass: def __init__(self, jira_server, jira_user, jira_password): try: # log.info("Connecting to JIRA: %s" % jira_server) jira_options = {'server': jira_server} self.jira_obj = JIRA( options=jira_options, # Note the tuple basic_auth=(jira_user, jira_password)) except Exception as e: print("Failed to connect to JIRA: %s" % e) def create_issue(self, project, summary, description, issue_name): issue_type = {} if issue_name: issue_type['name'] = issue_name return self.jira_obj.create_issue(project=project, summary=summary, description=description, issuetype=issue_type) def find_issue(self, id): try: issue = self.jira_obj.issue(id) issue_json = {} issue_json['id'] = issue.id issue_json['fields'] = { 'project': issue.fields.project.name, 'description': issue.fields.description, 'status': issue.fields.status.name, 'summary': issue.fields.summary, 'votes': issue.fields.votes.votes, 'labels': issue.fields.labels } issue_json['fields']['comments'] = [] for comment in issue.fields.comment.comments: issue_json['fields']['comments'].append(comment.body) if issue.fields.reporter: issue_json['fields'][ 'reporter'] = issue.fields.reporter.displayName if issue.fields.assignee: issue_json['fields'][ 'assignee'] = issue.fields.assignee.displayName issue_json['watchers'] = [] issue_watchers = self.jira_obj.watchers(issue.id) for watcher in issue_watchers.watchers: issue_json['watchers'].append(watcher.displayName) # print(issue.fields.worklog.) return issue_json except JIRAError as e: # print(e) return {'message': e.text} def find_projects(self): projects = self.jira_obj.projects() project_a = [] for project in projects: project_j = {} project_j['name'] = project.name # if project.lead: # project_j['lead'] = project.lead.displayName project_a.append(project_j) return project_a def my_issues(self): all_proj_issues = self.jira_obj.search_issues('project=SOMEKEY') my_issue_list = [] for issue in all_proj_issues: if issue.fields.assignee is not None and issue.fields.assignee.key == self.jira_obj.myself( )['key']: my_issue_list.append(self.find_issue(issue.id)) return my_issue_list
{ "jira_email": jira_email, "jira_server": jira_server, "jira_api_token": jira_api_token, "toggl_api_token": toggl_api_token, }, f, indent=4, ) del config jira = JIRA(jira_server, basic_auth=(jira_email, jira_api_token), max_retries=0) jira_account_id = jira.myself()["accountId"] toggl = requests.Session() toggl.auth = (toggl_api_token, "api_token") toggl.params["user_agent"] = jira_email def load_timestamp(s): try: ts = datetime.datetime.strptime(s, "%Y-%m-%dT%H:%M:%S.%f%z") except ValueError: ts = datetime.datetime.strptime(s, "%Y-%m-%dT%H:%M:%S%z") return ts.replace(tzinfo=datetime.timezone.utc) + ts.utcoffset() jira_key_time_entries = {}
else: valid_token_name = True self.token_name = token_name def save_token_info(self): with open(self.token_info_path, 'w') as f: json.dump({'token_name': self.token_name}, f) tMan = tokenManager() # Some Authentication Methods jira = JIRA( server="https://jira.berkeleyse.org", token_auth=tMan.token # Self-Hosted Jira (e.g. Server): the PAT token # basic_auth=("admin", "admin"), # a username/password tuple [Not recommended] # basic_auth=("email", "API token"), # Jira Cloud: a username/token tuple # auth=("admin", "admin"), # a username/password tuple for cookie auth [Not recommended] ) # Who has authenticated myself = jira.myself() test_issue = jira.issue('AVI-235') # jira.add_attachment(issue=test_issue, attachment='ship24.png') # new_description = test_issue.fields.description + '\n!ship24.png|thumbnail!' # # test_issue.update(description = new_description)
virlistName = "VIR_list_" + myselfData['emailAddress'][0].upper( ) + myselfData['emailAddress'].split(".")[1][:2].upper() + ".xml" with open("VIR_list.xml", "w") as f: f.write(xmlstr) with open(virlistName, "w") as f: f.write(xmlstr) if len(sys.argv) > 2: netID = str(sys.argv[1]) passwd = str(sys.argv[2]) else: print('\nYou need to pass netID and password to login to JIRA.\n') netID = input("NetID: ") passwd = getPwd() sysTRpathList = getTRpath() failedTClist = findFailedTCs(sysTRpathList) if failedTClist == []: print("No failed TCs\n") else: jira = JIRA(basic_auth=(netID, passwd), options={'server': 'http://jiraprod1.delphiauto.net:8080'}) myselfData = jira.myself() bugData = getBugData(failedTClist, jira) createVIRlist(bugData) input("\nDone! Press enter to finish.")
def oauth_user(request): response_data = { 'message': "Success" } status_code = status.HTTP_400_BAD_REQUEST try: try: oauth_token = request.data['oauth_token'] oauth_token_secret = request.data['oauth_token_secret'] except: oauth_token = request.query_params['oauth_token'] oauth_token_secret = request.query_params['oauth_token_secret'] jira_options = connect_2(oauth_token, oauth_token_secret) jac = JIRA( options={'server': JIRA_SERVER}, oauth=jira_options ) jac_username = jac.myself().get('displayName') jac_email = jac.myself().get('emailAddress') access_tokens = { 'access_token': jira_options['access_token'], 'secret_access_token': jira_options['access_token_secret'] } user = get_user_object(jac_email) if user is None: # Signup with ACC # convert the user data to a byte stream serializer = UserSerializerWithToken(data={ 'email': jac_email, 'username': jac_username, }) # if it is possible to deserialize the data then success if serializer.is_valid(): serializer.save() response_data = ({ 'message': "Successfully logged in user for the first time" }) response_data = {**response_data, ** serializer.data, **access_tokens} status_code = status.HTTP_201_CREATED # otherwise get the errors else: response_data = ({ 'message': "There was a problem creating the details for this user" }) response_data = {**response_data, **serializer.errors} status_code = status.HTTP_400_BAD_REQUEST else: # generate a token for the session if the credentials were valid token = generate_new_token(user) user_data = ({ 'token': token, 'email': user.email, 'username': user.username }) response_data = ({ 'message': "Successfully logged in", }) response_data = {**response_data, **user_data, **access_tokens} status_code = status.HTTP_200_OK return Response(data=response_data, status=status.HTTP_200_OK) except: response_data = { 'message': "Error" } return Response(response_data, status=status.HTTP_400_BAD_REQUEST)
class JiraClient(): jira_con = None board_details = None def __init__(self): self._get_jira_board_details() secrets = _get_secrets_from_netrc() if not secrets: err_msg = 'Unable to locate or load suitable `.netrc` file for JIRA integration' logger.error(err_msg) raise ValueError(err_msg) try: username, account, apikey = secrets.authenticators( self.jira_hostname) except TypeError: err_msg = 'JIRA Connection. Unable to find details for machine "{}" `.netrc` file.'.format( self.jira_hostname) logger.error(err_msg) raise ValueError(err_msg) self.jira_con = JIRA(options={'server': account}, basic_auth=(username, apikey)) _check_jira_con(self.jira_con, username) logger.debug('JIRA Connection. Details = {}'.format( self.jira_con.myself())) def _get_jira_board_details(self): # TODO read these in from a config file self.jira_hostname = 'mapaction.atlassian.net' self.project_key = 'PIPET' # The target column should be were the column where new issues are created self.target_column = '10110' self.common_task_fields = { 'project': self.project_key, 'issuetype': { 'id': '10235' } } def __del__(self): try: self.jira_con.kill_session() except (TypeError, AttributeError): pass def task_handler(self, fail_threshold, msg, task_referal=None): logger.debug( 'JiraClient.task_handler called with status="{}", and msg="{}"'. format(fail_threshold, msg)) assured_referal = self.ensure_task_referal_type( task_referal, msg, fail_threshold) if not assured_referal: logger.debug( 'JiraClient.task_handler; `None` value passed for task_referal parameter. Nothing to handle.' ) return unique_summary = assured_referal.get_task_unique_summary() task_desc = assured_referal.get_task_description() op_id = assured_referal.get_operation_id() j_issue = self.search_issue_by_unique_summary(unique_summary, op_id) if j_issue: # Update existing card and maybe move it back into "Doing" column self.update_jira_issue(j_issue, task_desc, fail_threshold) else: if fail_threshold > logging.INFO: # Create a new task self.create_new_jira_issue(unique_summary, task_desc, op_id) def ensure_task_referal_type(self, task_referal, msg, fail_threshold): """ Check whether or not the `task_referal` is an instance of TaskReferralBase object. If it is the object is then it is returned unchanged. If not then an generic TaskReferralBase will be created and returned. The value of `str(task_referal)` will be used. @param task_referal: An object that may or may not be a TaskReferralBase object. @returns: If the `task_referal` param is an instance of TaskReferralBase object, then `task_referal` is returned. If `task_referal` param is NOT an instance of TaskReferralBase AND fail_threshold is logging.ERROR then a new TaskReferralBase object is created (using `msg` and `str(task_referal)` for context). Else `None` is returned. """ if isinstance(task_referal, TaskReferralBase): logger.debug( 'JiraClient.ensure_task_referal_type found a TaskReferralBase object' ) return task_referal if task_referal and (fail_threshold > logging.WARNING): logger.debug( 'JiraClient.ensure_task_referal_type created a new TaskReferralBase object' ) return TaskReferralBase(None, msg=msg, other=str(task_referal)) logger.debug( 'JiraClient.ensure_task_referal_type passed "{}" but returned `None`' .format(str(task_referal))) return None def search_issue_by_unique_summary(self, search_summary, op_id): # Default if `op_id` is None jql_op_id = 'operational_id is EMPTY' if op_id: jql_op_id = 'operational_id ~ "{}"'.format(op_id) jql_str = 'project={} AND {} AND summary ~ "{}"'.format( self.project_key, jql_op_id, search_summary) found_issues = self.jira_con.search_issues(jql_str, maxResults=2) if found_issues: if len(found_issues) > 1: raise ValueError( 'More than one JIRA Issue found with the summary "{}". This suggests that additional' ' issues have been raised manualy on the board "{}". Please ensure that there is exactly' ' one issues with this summary, by deleting those which have not been created by the' ' user "{}"'.format( search_summary, self.project_key, self.jira_con.myself()['emailAddress'])) else: return found_issues[0] else: return None def create_new_jira_issue(self, unique_summary, task_desc, op_id): flds = self.common_task_fields.copy() flds['summary'] = unique_summary flds['description'] = task_desc # This is the JIRA API's field ID for operational_id. To work this out execute: # ``` # a = j.jira_con.createmeta(projectKeys=['PIPET'], issuetypeIds=[10235], expand='projects.issuetypes.fields') # print(a) # ``` # Then search the output for your custom field name. Doubtless there is a programmatic way to do this. flds['customfield_10234'] = op_id new_task = self.jira_con.create_issue(fields=flds) # new_task.update(fields={'operational_id':op_id}) # new_task.update(operational_id=op_id) print(new_task) # print('desc', new_task.fields.description) # print('opid', new_task.fields.operational_id) # for f in new_task.fields: # print('field itr', f) def update_jira_issue(self, j_issue, task_desc, fail_threshold): now_utc = pytz.utc.localize(datetime.now()) time_stamp = now_utc.strftime('%Y-%m-%d %H:%M:%S %Z%z') # prev_desc = if task_desc != j_issue.fields.description: j_issue.update(description=task_desc) if fail_threshold > logging.INFO: self.jira_con.add_comment( j_issue.id, 'This Issue was still current when MapChef was run at {}'. format(time_stamp))
class JiraAction(): open_statuses = [] homedir = expanduser("~") jira = None userdata = UserData() def setup(self): if self.jira == None: with open(homedir + "/.jirator/config") as fh: data = json.load(fh) options = {"server": data["server"]} self.jira = JIRA(options=options, basic_auth=(data["username"], data["password"])) for s in data["status"]: app = '\"' + s + '\"' self.open_statuses.append(app) def fetch_open_issues(self): statuses = ",".join(self.open_statuses) my_issues = self.jira.search_issues( 'assignee=currentUser() and status in (' + statuses + ')') return my_issues def save_or_return_dtid(self, issuekey): sdtid = self.userdata.default_transition_id() if sdtid is not None: return sdtid print( "Could not find any default transition id for this issue; please select one to use as the default 'in progress' transition:\n" ) trs = self.jira.transitions(issuekey) for idx, t in enumerate(trs): tch = t["to"] d = "no description" if not tch["description"] else tch[ "description"] print("\t%d) %s (%s)" % (idx + 1, tch["name"], d)) selected = 0 while True: try: sel = int( input( "\nPlease specify the number of the transition you want to use as default: " )) if (sel >= 1) and (sel <= len(trs)): selected = sel break print("Please enter a number between %d and %d" % (1, len(trs))) except: print("Please enter a number between %d and %d" % (1, len(trs))) tid = trs[selected - 1] self.userdata.save_default_tid(tid["id"]) return tid["id"] def assign_issue_to_self(self, issuekey): logging.debug("assigning %s to self" % (issuekey)) dtid = self.userdata.default_transition_id() if dtid == None: logging.debug("could not find any default tid") else: logging.debug("using '%s' as tid" % (dtid)) try: myself = self.jira.myself() issue = self.jira.issue(issuekey) tid = self.save_or_return_dtid(issuekey) issue.update(assignee={'name': myself["name"]}) subprocess.call(["git", "checkout", "-b", issuekey]) except JIRAError as e: logging.error("could not assign issue '%s' to self: '%s'" % (issuekey, e.text))