Beispiel #1
0
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)
Beispiel #2
0
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
Beispiel #3
0
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
Beispiel #4
0
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
Beispiel #5
0
        {
            "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 = {}
Beispiel #6
0
            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))
Beispiel #10
0
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))