Exemple #1
0
def get_error_list(r):
    error_list = []
    if r.status_code >= 400:
        if r.status_code == 403 and "x-authentication-denied-reason" in r.headers:
            error_list = [r.headers["x-authentication-denied-reason"]]
        elif r.text:
            try:
                response = json_loads(r)
                if 'message' in response:
                    # JIRA 5.1 errors
                    error_list = [response['message']]
                elif 'errorMessages' in response and len(response['errorMessages']) > 0:
                    # JIRA 5.0.x error messages sometimes come wrapped in this array
                    # Sometimes this is present but empty
                    errorMessages = response['errorMessages']
                    if isinstance(errorMessages, (list, tuple)):
                        error_list = errorMessages
                    else:
                        error_list = [errorMessages]
                elif 'errors' in response and len(response['errors']) > 0:
                    # JIRA 6.x error messages are found in this array.
                    error_list = response['errors'].values()
                else:
                    error_list = [r.text]
            except ValueError:
                error_list = [r.text]
    return error_list
Exemple #2
0
    def _load(
        self,
        url: str,
        headers=CaseInsensitiveDict(),
        params: Optional[Dict[str, str]] = None,
        path: Optional[str] = None,
    ):
        """Load a resource.

        Args:
            url (str): url
            headers (Optional[CaseInsensitiveDict]): headers. Defaults to CaseInsensitiveDict().
            params (Optional[Dict[str,str]]): params to get request. Defaults to None.
            path (Optional[str]): field to get. Defaults to None.

        Raises:
            ValueError: If json cannot be loaded
        """
        r = self._session.get(url, headers=headers, params=params)
        try:
            j = json_loads(r)
        except ValueError as e:
            logging.error(f"{e}:\n{r.text}")
            raise e
        if path:
            j = j[path]
        self._parse_raw(j)
    def get_project_templates(self):
        url = self.manager._options[
            'server'] + '/rest/project-templates/latest/templates'

        response = self.manager._session.get(url)
        json_data = json_loads(response)
        return _get_template_list(json_data)
Exemple #4
0
def request_types(manager,
                  service_desk,
                  project_key=None,
                  strange_setting=None):
    """We need to use this function because in the old Jira version issueTypeId field does not exist."""
    types = manager.request_types(service_desk)

    if len(types) and not hasattr(types[0], 'issueTypeId'):
        if hasattr(service_desk, 'id'):
            service_desk = service_desk.id

        url = manager._options[
            'server'] + '/rest/servicedesk/%s/servicedesk/%s/groups/%s/request-types' % (
                strange_setting,
                project_key.lower(),
                service_desk,
            )
        headers = {'X-ExperimentalApi': 'opt-in'}
        r_json = json_loads(manager._session.get(url, headers=headers))
        types = [
            RequestType(manager._options, manager._session, raw_type_json)
            for raw_type_json in r_json
        ]
        list(map(lambda t: setattr(t, 'issueTypeId', t.issueType), types))

    return types
Exemple #5
0
def _upload_file(manager, issue, upload_file, filename):
    # This method will fix original method jira.JIRA.add_attachment (jira/client.py line 591)
    url = manager._get_url('issue/' + str(issue) + '/attachments')
    files = {
        'file': (filename, upload_file),
    }
    headers = {
        'X-Atlassian-Token': 'no-check',
    }
    req = Request('POST',
                  url,
                  headers=headers,
                  files=files,
                  auth=manager._session.auth)
    prepped = req.prepare()
    prepped.body = re.sub(b'filename=.*',
                          b'filename="%s"\r' % filename.encode('utf-8'),
                          prepped.body)
    r = manager._session.send(prepped)

    js = utils.json_loads(r)

    if not js or not isinstance(js, collections.Iterable):
        raise JIRAError("Unable to parse JSON: %s" % js)

    attachment = Attachment(manager._options, manager._session, js[0])

    if attachment.size == 0:
        raise JIRAError("Added empty attachment?!: r: %s\nattachment: %s" %
                        (r, attachment))

    return attachment
Exemple #6
0
def download_worklogs(jira_connection, issue_ids):
    print('downloading jira worklogs... ', end='', flush=True)
    updated = []
    since = 0
    while True:
        worklog_ids_json = jira_connection._get_json('worklog/updated', params={'since': since})
        updated_worklog_ids = [v['worklogId'] for v in worklog_ids_json['values']]

        resp = jira_connection._session.post(
            url=jira_connection._get_url('worklog/list'),
            data=json.dumps({'ids': updated_worklog_ids}),
        )
        try:
            worklog_list_json = json_loads(resp)
        except ValueError:
            print("Couldn't parse JIRA response as JSON: %s", resp.text)
            raise

        updated.extend([wl for wl in worklog_list_json if int(wl['issueId']) in issue_ids])
        if worklog_ids_json['lastPage']:
            break
        since = worklog_ids_json['until']

    print('✓')

    return {'existing': updated, 'deleted': []}
Exemple #7
0
def get_error_list(r):
    error_list = []
    if r.status_code >= 400:
        if r.status_code == 403 and "x-authentication-denied-reason" in r.headers:
            error_list = [r.headers["x-authentication-denied-reason"]]
        elif r.text:
            try:
                response = json_loads(r)
                if 'message' in response:
                    # JIRA 5.1 errors
                    error_list = [response['message']]
                elif 'errorMessages' in response and len(
                        response['errorMessages']) > 0:
                    # JIRA 5.0.x error messages sometimes come wrapped in this array
                    # Sometimes this is present but empty
                    errorMessages = response['errorMessages']
                    if isinstance(errorMessages, (list, tuple)):
                        error_list = errorMessages
                    else:
                        error_list = [errorMessages]
                elif 'errors' in response and len(response['errors']) > 0:
                    # JIRA 6.x error messages are found in this array.
                    error_list = response['errors'].values()
                else:
                    error_list = [r.text]
            except ValueError:
                error_list = [r.text]
    return error_list
Exemple #8
0
def get_error_list(r: Response) -> List[str]:
    error_list = []
    if r.status_code >= 400:
        if r.status_code == 403 and "x-authentication-denied-reason" in r.headers:
            error_list = [r.headers["x-authentication-denied-reason"]]
        elif r.text:
            try:
                response: Dict[str, Any] = json_loads(r)
                if "message" in response:
                    # Jira 5.1 errors
                    error_list = [response["message"]]
                elif "errorMessages" in response and len(
                        response["errorMessages"]) > 0:
                    # Jira 5.0.x error messages sometimes come wrapped in this array
                    # Sometimes this is present but empty
                    errorMessages = response["errorMessages"]
                    if isinstance(errorMessages, (list, tuple)):
                        error_list = list(errorMessages)
                    else:
                        error_list = [errorMessages]
                elif "errors" in response and len(response["errors"]) > 0:
                    # Jira 6.x error messages are found in this array.
                    error_list = response["errors"].values()
                else:
                    error_list = [r.text]
            except ValueError:
                error_list = [r.text]
    return error_list
Exemple #9
0
 def _load(self, url, headers=CaseInsensitiveDict(), params=None, path=None):
     r = self._session.get(url, headers=headers, params=params)
     try:
         j = json_loads(r)
     except ValueError as e:
         logging.error("%s:\n%s" % (e, r.text))
         raise e
     if path:
         j = j[path]
     self._parse_raw(j)
Exemple #10
0
 def _load(self, url, headers=CaseInsensitiveDict(), params=None, path=None):
     r = self._session.get(url, headers=headers, params=params)
     try:
         j = json_loads(r)
     except ValueError as e:
         logging.error("%s:\n%s" % (e, r.text))
         raise e
     if path:
         j = j[path]
     self._parse_raw(j)
Exemple #11
0
def create_customer_request(self,
                            fields=None,
                            prefetch=True,
                            use_old_api=False,
                            **fieldargs):
    """The code for this function is almost completely copied from
    function create_customer_request of the JIRA library"""
    data = fields

    p = data['serviceDeskId']
    service_desk = None

    if isinstance(p, str) or isinstance(p, int):
        service_desk = self.service_desk(p)
    elif isinstance(p, ServiceDesk):
        service_desk = p

    data['serviceDeskId'] = service_desk.id

    p = data['requestTypeId']
    if isinstance(p, int):
        data['requestTypeId'] = p
    elif isinstance(p, str):
        data['requestTypeId'] = self.request_type_by_name(service_desk, p).id

    requestParticipants = data.pop('requestParticipants', None)

    url = self._options['server'] + '/rest/servicedeskapi/request'
    headers = {'X-ExperimentalApi': 'opt-in'}
    r = self._session.post(url, headers=headers, data=json.dumps(data))

    raw_issue_json = json_loads(r)
    if 'issueKey' not in raw_issue_json:
        raise JIRAError(r.status_code, request=r)

    if requestParticipants:
        url = (self._options['server'] +
               '/rest/servicedeskapi/request/%s/participant' %
               raw_issue_json['issueKey'])
        headers = {'X-ExperimentalApi': 'opt-in'}

        if use_old_api:
            data = {'usernames': requestParticipants}
        else:
            data = {'accountIds': requestParticipants}

        r = self._session.post(url, headers=headers, json=data)

    if r.status_code != status.HTTP_200_OK:
        raise JIRAError(r.status_code, request=r)

    if prefetch:
        return self.issue(raw_issue_json['issueKey'])
    else:
        return Issue(self._options, self._session, raw=raw_issue_json)
Exemple #12
0
    def _add_comment(self, issue, body, is_internal):
        data = {
            'body': body,
            'properties': [{'key': 'sd.public.comment', 'value': {'internal': is_internal}}, ]
        }

        url = self.manager._get_url('issue/{0}/comment'.format(issue))
        response = self.manager._session.post(url, data=json.dumps(data))

        comment = Comment(self.manager._options, self.manager._session, raw=json_loads(response))
        return comment
Exemple #13
0
 def create_webhook(self, name=None, url=None, events=None,
                    jql='', exclude_body=False):
     assert name and url and events
     data = {'name': name,
             'url': url,
             'events': events,
             'jqlFilter': jql,
             'excludeIssueDetails': exclude_body,
             }
     url = self.client._get_url('webhook', base=self.webhook_base_path)
     response = self.client._session.post(url, data=json.dumps(data))
     return json_loads(response)
Exemple #14
0
    def update_board_name(self, id, name):
        payload = {
            'id': id,
            'name': name,
        }

        url = self._get_url(
            'rapidviewconfig/name',
            base=self.AGILE_BASE_URL
        )
        response = self._session.put(
            url, data=json.dumps(payload)
        )

        return json_loads(response)
Exemple #15
0
def _download_jira_issues_page(
    jira_connection, jira_issue_ids_segment, field_spec, start_at, batch_size
):
    '''
    Returns a tuple: (issues_downloaded, num_issues_apparently_deleted)
    '''
    get_changelog = True

    while batch_size > 0:
        search_params = {
            'jql': f"id in ({','.join(str(iid) for iid in jira_issue_ids_segment)}) order by id asc",
            'fields': field_spec,
            'expand': ['renderedFields'],
            'startAt': start_at,
            'maxResults': batch_size,
        }
        if get_changelog:
            search_params['expand'].append('changelog')

        try:
            resp_json = json_loads(
                jira_connection._session.post(
                    url=jira_connection._get_url('search'), data=json.dumps(search_params)
                )
            )
            return _expand_changelog(resp_json['issues'], jira_connection), 0

        except (json.decoder.JSONDecodeError, JIRAError) as e:
            if hasattr(e, 'status_code') and e.status_code == 429:
                # This is rate limiting ("Too many requests")
                raise

            batch_size = int(batch_size / 2)
            agent_logging.log_and_print_error_or_warning(
                logger, logging.WARNING, msg_args=[e, batch_size], error_code=3052, exc_info=True,
            )
            if batch_size == 0:
                if re.match(r"A value with ID .* does not exist for the field 'id'", e.text):
                    return [], 1
                elif not get_changelog:
                    agent_logging.log_and_print_error_or_warning(
                        logger, logging.WARNING, msg_args=[search_params], error_code=3062,
                    )
                    return [], 0
                else:
                    get_changelog = False
                    batch_size = 1
Exemple #16
0
    def _load(self, url, headers=CaseInsensitiveDict(), params=None, path=None):
        """ Load a resource.

        :type url: str
        :type headers: CaseInsensitiveDict
        :type params: Optional[Dict[str,str]]
        :type path: Optional[str]

        """
        r = self._session.get(url, headers=headers, params=params)
        try:
            j = json_loads(r)
        except ValueError as e:
            logging.error("%s:\n%s" % (e, r.text))
            raise e
        if path:
            j = j[path]
        self._parse_raw(j)
Exemple #17
0
def create_customer(self, email, displayName):
    """Create a new customer and return an issue Resource for it."""
    url = self._options['server'] + '/rest/servicedeskapi/customer'
    headers = {'X-ExperimentalApi': 'opt-in'}
    r = self._session.post(
        url,
        headers=headers,
        data=json.dumps({
            'email': email,
            'fullName': displayName,  # different property for the server one
        }),
    )

    raw_customer_json = json_loads(r)

    if r.status_code != 201:
        raise JIRAError(r.status_code, request=r)
    return Customer(self._options, self._session, raw=raw_customer_json)
Exemple #18
0
    def create_shared(self, key=None, name=None, shared_key=None, lead=None):
        assert key and name and shared_key
        # There is no public method for creating a shared project:
        # https://jira.atlassian.com/browse/JRA-45929
        # People found a private method for doing so, which is explained on:
        # https://jira.atlassian.com/browse/JRA-27256?src=confmacro&_ga=1.162710906.750569280.1479368101

        try:
            project = self.read(shared_key)
            project_id = project['id']
        except JIRAError as err:
            if err.status_code == 404:
                raise exceptions.UserError(
                    _('Project template with key "%s" not found.') %
                    shared_key)
            else:
                raise

        url = (self.client._options['server'] +
               '/rest/project-templates/1.0/createshared/%s' % project_id)
        payload = {
            'name': name,
            'key': key,
            'lead': lead,
        }

        r = self.client._session.post(url, data=json.dumps(payload))
        if r.status_code == 200:
            r_json = json_loads(r)
            return r_json

        f = tempfile.NamedTemporaryFile(
            suffix='.html',
            prefix='python-jira-error-create-shared-project-',
            delete=False)
        f.write(r.text)

        if self.logging:
            logging.error(
                "Unexpected result while running create shared project."
                "Server response saved in %s for further investigation "
                "[HTTP response=%s]." % (f.name, r.status_code))
        return False
def download_worklogs(jira_connection):
    print(f'downloading worklogs... ', end='', flush=True)
    updated = []
    while True:
        worklog_ids_json = jira_connection._get_json('worklog/updated',
                                                     params={'since': 0})
        updated_worklog_ids = [
            v['worklogId'] for v in worklog_ids_json['values']
        ]

        resp = jira_connection._session.post(
            url=jira_connection._get_url('worklog/list'),
            data=json.dumps({'ids': updated_worklog_ids}))
        try:
            worklog_list_json = json_loads(resp)
        except ValueError as e:
            logger.exception("Couldn't parse JIRA response as JSON: %s",
                             resp.text)
            raise e

        updated.extend(worklog_list_json)
        if worklog_ids_json['lastPage']:
            break
    print('✓')

    print(f'Finding old worklogs that have been deleted... ',
          end='',
          flush=True)
    deleted = []
    while True:
        worklog_ids_json = jira_connection._get_json('worklog/deleted',
                                                     params={'since': 0})
        deleted.extend(worklog_ids_json['values'])
        if worklog_ids_json['lastPage']:
            break

    print('✓')

    return {
        'existing': updated,
        'deleted': deleted,
    }
Exemple #20
0
    def create_poker_session(
        self,
        board_id: int,
        name: str,
        issues: list[str],
        participants: list[str],
        scrum_masters: list[str],
        send_invitations: bool = True,
    ) -> Poker:
        """
        Create a new agile poker session.

        :param board_id: The board to get sessions from.
        :param name: Name of the session.
        :param scrum_masters: A list of participants with scrum masters permissions.
        :param participants: A list of standard participants of the session.
        :param issues: A list of issues to be estimated in a session.
        :param send_invitations: Whether or not to notify participants about the update via email. (Default: True).
        :return: A new session.
        """
        response = self._session.post(
            url=self._get_url(f'session/async?boardId={board_id}',
                              self.AGILE_POKER_URL),
            headers={'content-type': 'application/json'},
            data=json.dumps({
                'estimationFieldId':
                self.issue_fields[settings.JIRA_FIELDS_STORY_POINTS],
                'invitationMessage':
                settings.SPRINT_ASYNC_POKER_NEW_SESSION_MESSAGE,
                'name':
                name,
                'issueIds':
                issues,
                'participantsUserKeys':
                participants,
                'scrumMastersUserKeys':
                scrum_masters,
                'sendInvitations':
                send_invitations,
            }),
        )
        return Poker(self._options, self._session, json_loads(response))
Exemple #21
0
    def close_poker_session(self,
                            session_id: int,
                            send_notifications: bool = True) -> Poker:
        """
        Close an agile poker session.

        :param session_id: The ID of the session to close.
        :param send_notifications: Whether or not to notify participants about the update via email. (Default: True).
        :return: A closed session.
        """
        response = self._session.put(
            url=self._get_url(f'session/async/{session_id}/rounds/latest',
                              self.AGILE_POKER_URL),
            headers={'content-type': 'application/json'},
            data=json.dumps({
                'closeRound': True,
                'sendCloseNotifications': send_notifications,
            }),
        )
        return Poker(self._options, self._session, json_loads(response))
Exemple #22
0
    def update_swimlane(self, board_id, swimlane_id, name=None, query=None, description=None, is_default=None):
        payload = {
            'id': swimlane_id,
        }

        if name:
            payload['name'] = name
        if query:
            payload['query'] = query
        if description:
            payload['description'] = description
        if is_default is not None:
            payload['isDefault'] = is_default

        url = self._get_url(
            'swimlanes/{}/{}'.format(board_id, swimlane_id),
            base=self.AGILE_BASE_URL
        )
        response = self._session.put(
            url, data=json.dumps(payload)
        )

        return json_loads(response)
Exemple #23
0
    def createIssue(self, content, data, client):
        """
        JIRA create issue API  is not working, use the below code to replace
        """
        url = 'https://jiradc.ext.net.nokia.com/secure/QuickCreateIssue.jspa?decorator=none'
        pid = client.project(data.get('project')).id
        issuetype_id = client.issue_type_by_name(data.get('issuetype')).id
        token = client._session.cookies.values()[1]
        content['pid'] = pid
        content['issuetype'] = issuetype_id
        content['atl_token'] = token

        headers = {
            'Origin':
            'https://jiradc.ext.net.nokia.com',
            'X-AUSERNAME':
            '******',
            'Connection':
            'keep-alive',
            'Accept-Language':
            'zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2',
            'Referer':
            'https://jiradc.ext.net.nokia.com/secure/RapidBoard.jspa?rapidView=13285',
            'X-Requested-With':
            'XMLHttpRequest',
            'Content-Type':
            'application/x-www-form-urlencoded; charset=UTF-8',
            'Accept':
            '*/*',
            'User-Agent':
            'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:79.0) Gecko/20100101 Firefox/79.0'
        }
        url_labels = self.combine_url_labels(url, data)
        response = client._session.post(url_labels,
                                        data=content,
                                        headers=headers)
        return json_loads(response)['issueKey']
Exemple #24
0
 def delete_webhook(self, id_):
     url = self.client._get_url('webhook/%s' % id_,
                                base=self.webhook_base_path)
     return json_loads(self.client._session.delete(url))