예제 #1
0
 def __init__(self, root_id):
     self.root_id = root_id
     self.api_jira = API_Jira()
     self.wmap = Wardley_Map()
     self.link_type = 'needs'
     self.api_jira._jira = JIRA(
         server='https://ubuntu-policy.atlassian.net/')
예제 #2
0
 def __init__(self, issue_id=None, channel=None, team_id=None, event=None):
     self.issue_id = issue_id
     self.channel = channel
     self.team_id = team_id
     self.event = event
     self.api_issues = API_Issues()
     self.api_jira = API_Jira()
     self.issue = None
     self.action_id = 'Jira_View_Issue'
     self.slack_blocks = API_Slack_Blocks()
    def jira_create_issue(self):
        #project     = self.submission.get('project')
        issue_type = self.submission.get('issue_type')
        project = issue_type.upper()
        summary = self.submission.get('summary')
        description = self.submission.get('description')
        if summary: summary = summary.replace('+', ' ')
        if description: description = description.replace('+', ' ')
        else: description = ''

        if project and issue_type and summary:
            self.send_message(
                'Creating new `{0}` issue on project `{1}` with summary `{2}` and description `{3}`'
                .format(issue_type, project, summary, description))

            from osbot_jira.api.jira_server.API_Jira import API_Jira
            try:
                result = API_Jira().issue_create(project, summary, description,
                                                 issue_type)
                new_issue_id = "{0}".format(result)
                self.submission['issue_id'] = new_issue_id
                self.show_issue()
                #self.show_issue_screnshot()
                jira_link = "https://glasswall.atlassian.net/browse/{0}".format(
                    new_issue_id)
                return 'Created issue: <{0}|{1}>'.format(
                    jira_link, new_issue_id)
            except Exception as error:
                return ':red_circle: Error creating issue: {0}'.format(error)
        return ':red_circle: Error in Slack_Dialog_Submissions.jira_create_issue. Missing required values from submission data: `{0}`'.format(
            self.submission)
예제 #4
0
class Jira_Map:
    def __init__(self, root_id):
        self.root_id = root_id
        self.api_jira = API_Jira()
        self.wmap = Wardley_Map()
        self.link_type = 'needs'
        self.api_jira._jira = JIRA(
            server='https://ubuntu-policy.atlassian.net/')

    def add_node(self, issue_id, depth_delta=0):
        issue = self.api_jira.issue(issue_id)
        summary = issue['Summary']
        self.wmap.add_node(issue['Summary'], issue['Status'], depth_delta)

        issue.get('Issue Links')
        summary = issue.get('Summary')
        issue_links = issue.get('Issue Links')
        for link_id in issue_links:
            for issue_link in issue_links[link_id]:
                if issue_link['Link Type'] == self.link_type:
                    self.add_node(link_id, depth_delta + 1.5)
                    self.wmap.add_link(summary, issue_link.get('Summary'))

    def create(self):
        self.add_node(self.root_id)
        return self

    def show(self, height=300):
        self.create()
        self.wmap.show_map(height)
예제 #5
0
    def issue(team_id=None, channel=None, params=None):
        (text, attachments) = Jira_Commands._check_params(params, ['Issue Id'])
        if text: return text  #, attachments

        issue_id, = params
        project = issue_id.split('-').pop(0)
        projects = Jira_Commands.gsbot_projects
        if project not in projects:
            return {
                "error":
                ":rec_circle: project `{0}` is currently not available. The projects currently supported are: `{1}`"
                .format(project, projects)
            }

        return API_Jira().issue(issue_id)
예제 #6
0
    def cmd_create(self, params, team_id=None, channel=None):
        try:
            if len(params) < 3:
                text = ":exclamation: To create an issue you need to provide the `issue type` and `summary`. For example `jira create task abc"
                return {"text": text, "attachments": []}
            else:
                params.pop(0)  # the create command
                issue_type = params.pop(
                    0)  #.title() # todo: find a better solution for this
                project = issue_type.upper(
                )  # todo: and to address the mapping of issue types to projects
                summary = ' '.join(params)
                slack_message(
                    ':point_right: Going to create an `{0}` issue, in project `{1}` with summary `{2}`'
                    .format(issue_type, project,
                            summary), [], channel, team_id)

                #to do, move this feature to a separate lambda (which can be called to create issues
                from osbot_aws.Dependencies import load_dependency
                load_dependency('jira')
                from osbot_jira.api.jira_server.API_Jira import API_Jira

                # create issue
                result = API_Jira().issue_create(project, summary, '',
                                                 issue_type)
                issue_id = "{0}".format(result)

                # show issue screenshot
                # payload = {'issue_id': issue_id,'channel': channel,'team_id': team_id, }
                # Lambda('osbot_browser.lambdas.jira_web').invoke_async(payload)

                # show issue UI
                payload = {'params': ['issue', issue_id], "channel": channel}
                Lambda('osbot_jira.lambdas.jira').invoke_async(payload)

                # show link of new issue to user
                jira_link = "https://glasswall.atlassian.net/browse/{0}".format(
                    issue_id)
                text = ':point_right: New issue created with id <{0}|{1}>'.format(
                    jira_link, issue_id)
            return {"text": text, "attachments": []}
        except Exception as error:
            log_to_elk('jira create error', f'{error}')
            return {
                'text':
                f':red_circle: Issue could not be created, please make sure that: \n - issue type exists\n - issue type = project type\n - Issue type CamelCase is correctly entered (you want `Task` and not `task`)',
                "attachments": []
            }
예제 #7
0
    def cmd_add_link(self, params, team_id=None, channel=None):
        if len(params) < 4:
            text = ":exclamation: Hi, to add a link, You must provide 3 params: `{from ID}` `{to ID}` `{link type}`"
            return {"text": text, "attachments": []}
        else:
            params.pop(0)  # position 0 is the 'issue' command
            from_key = params.pop(0)
            to_key = params.pop(0)
            link_type = " ".join(params)

            try:
                from osbot_jira.api.jira_server.API_Jira import API_Jira
                API_Jira().issue_add_link(from_key, link_type, to_key)
                text = ':point_right: Added link: *{0}* `{1}` *{2}*'.format(
                    from_key, link_type, to_key)
            except Exception as error:
                text = ':red_circle: Error in `add_link`:  {0}'.format(error)
            return {"text": text, "attachments": []}
예제 #8
0
    def update(team_id=None, channel=None, params=None):
        try:

            issue_data = json.loads(" ".join(params))
            issue_id = issue_data.get('Key')
            project = issue_id.split('-').pop(0)
            projects = Jira_Commands.gsbot_projects
            if project not in projects:
                return ":rec_circle: project `{0}` is currently not available. The projects currently supported are: `{1}`".format(
                    project, projects)

            API_Jira().issue_update(issue_data)
            return {"status": "ok"}
        except Exception as error:
            return {
                "error",
                ":rec_circle: error in `Jira_Commands.update` command: `{0}`".
                format(error)
            }
예제 #9
0
from flask_restplus import Namespace, Resource
from osbot_jira.api.jira_server.API_Jira import API_Jira

api = Namespace('jira-sync', description='JIRA issues related operations')
jira_api = API_Jira()


@api.route('/load-jira/<file_id>')
class load_jira(Resource):
    def get(self, file_id):
        try:
            from pbx_gs_python_utils.api_jira.API_Jira_Sheets_Sync import API_Jira_Sheets_Sync
            api_sync = API_Jira_Sheets_Sync(file_id)
            result = api_sync.load_data_from_jira()
            return {'status': result}
        except Exception as error:
            return {'error': "{0}".format(error)}


@api.route('/diff-sheet/<file_id>')
class diff_sheet(Resource):
    def get(self, file_id):
        try:
            from pbx_gs_python_utils.api_jira.API_Jira_Sheets_Sync import API_Jira_Sheets_Sync
            api_sync = API_Jira_Sheets_Sync(file_id)
            result = api_sync.diff_sheet()
            return {'status': result}
        except Exception as error:
            return {'error': "{0}".format(error)}

예제 #10
0
class GW_Elastic_Jira:
    def __init__(self, index_id = 'jira', projects = None):
        self.secrets_id     = 'gw-elastic-server-1'
        self.index_id       = index_id
        self.elastic        = None
        self.api_Jira       = API_Jira()
        self.projects       = projects #'IA, TM,GDPR'

    def reload_all_data_from_jira_project(self): # todo: find better location to do this (reloading of elastic data)
        self.re_create_index()
        self.send_data_from_project()

    def re_create_index(self):         # note that this will delete the index and recreate it
        self.elastic.delete_index()               \
                    .create_index()
        # self.elastic.delete_index()             \
        #             .delete_index_pattern()     \
        #             .create_index()             \
        #             .create_index_pattern(add_time_field=False)
        return self

    def setup(self):
        if self.elastic is None:
            self.elastic = Elastic_Search(self.index_id,self.secrets_id)
        return self

    def fix_issues_for_elk(self,issues):
        return [self.fix_issue_for_elk(issue) for issue in issues]

    def fix_issue_for_elk(self,issue):
        items = {} #{'_all': [] }                                  # fix issue links
        for key, issue_links in issue['Issue Links'].items():
            #items['_all'].append(key)                          # capture a list of all ids
            for issue_link in issue_links:
                link_type = issue_link['Link Type']
                if items.get(link_type) is None:                   # and index them by link_type
                    items[link_type] = []
                items[link_type].append(key)
        issue['Issue Links'] = items

        if issue['Rating'] ==  'To be determined':
            issue['Rating']= 'TBD'
        if issue['Project'] == 'VULN (Vulnerability)':
            issue['Project'] = 'VULN'

        #Dev.pprint(issue)

        return issue

    def send_data_from_project(self, project=None):
        if project:
            jql = 'project={0}'.format(project)
        else:
            jql = ''                                                        # todo: find a better way to get all results from Jira

        api_jira_rest = API_Jira_Rest()
        issues = api_jira_rest.search(jql)

        return self.elastic.add_bulk(issues, "Key")

    def issue_get(self,issue_id):
        try:
            data = self.elastic.get_data(issue_id)
            return data['_source']
        except Exception as error:
            log_error(str(error),'API_Elastic_Jira.issue_get')
            return {}

    def issue_update(self, issue):
        return self.elastic.add(issue, "Key")

    def reset_update_index_value(self):
        update_key = '_update_details'
        self.elastic.delete_data_by_id(update_key)
        return self

    def update_index_from_jira_changes(self):
        if self.projects is None:
            log_error("Cannot update ELK since self.projects value is not configured")
            return
        update_key = '_update_details'              # code to store last updated time in the index (move this to a dedicated location)
        data       = self.elastic.get_data(update_key)
        if data is None:
            update_key_data = {
                                  "Key": update_key,
                                  "last_updated_at": None
                              }
            epoch = (datetime.datetime.now() - datetime.timedelta(0, 60 * 1440)).timestamp()         # if the value is not set , go back 24 h
            when            = strftime("%Y/%m/%d %H:%M", localtime(epoch))
        else:
            update_key_data = data['_source']
            when            = update_key_data['last_updated_at']

        now_epoch = time() - 120 # due to the current issue with the sync server, remove 2 minutes from the time() value (which is the current time in seconds since the Epoch)

        now    = strftime("%Y/%m/%d %H:%M", localtime(now_epoch))                      # capture this value here (as soon as possible)

        now_server = strftime("%Y/%m/%d %H:%M",localtime(time()))
        print(" > using {0}  , localtime: {1}".format(now,now_server))

        query  = 'project in ({0}) AND updated >= "{1}"'.format(self.projects,when)
        changes = self.api_Jira.search_no_cache(query)
        if len(changes) == 0:
            log_info("No issues updated since: {0}".format(when),"API_Elastic_Jira.update_index_from_jira_changes")
            return



        log_info(Dev.pprint("Since {0}, there where {1} issues updated: {2}".format(when, len(set(changes)),set(changes))),
                            "API_Elastic_Jira.update_index_from_jira_changes")

        issues = self.fix_issues_for_elk(changes.values())

        result = self.elastic.add_bulk(issues, "Key")
        log_info(Dev.pprint("sent {0} issues to elk instance: {1}".format(result, self.secrets_id)),
                            "API_Elastic_Jira.update_index_from_jira_changes")

        update_key_data['last_updated_at'] = now
        self.elastic.add(update_key_data, "Key")


    def add_changed_log_status(self, project, start_at=0, max =-1):
        jql = "Project={0}".format(project)
        statuses = self.api_Jira.issue_changes_log_only_status(jql, start_at, max)
        data = []
        for key,items in statuses.items():
            for entry in items:
                entry['Key'    ] = key
                entry['Project'] = project
                data.append(entry)

        self.elastic.add_bulk(data, "Entry_Id")
        return data
예제 #11
0
 def __init__(self, index_id = 'jira', projects = None):
     self.secrets_id     = 'gw-elastic-server-1'
     self.index_id       = index_id
     self.elastic        = None
     self.api_Jira       = API_Jira()
     self.projects       = projects #'IA, TM,GDPR'
예제 #12
0
 def __init__(self, grid):
     self.grid = grid
     self.api_jira = API_Jira()
     self.api_jira_rest = API_Jira_Rest()
예제 #13
0
class Jira_View_Issue():
    def __init__(self, issue_id=None, channel=None, team_id=None, event=None):
        self.issue_id = issue_id
        self.channel = channel
        self.team_id = team_id
        self.event = event
        self.api_issues = API_Issues()
        self.api_jira = API_Jira()
        self.issue = None
        self.action_id = 'Jira_View_Issue'
        self.slack_blocks = API_Slack_Blocks()

    # refactor this to base class
    def message_not_supported_action(self, action=''):
        return {
            "text":
            ':red_circle: Sorry, action not recognized : {0}'.format(action),
            "attachments": [],
            'replace_original':
            False
        }

    def message_execution_error(self, error):
        return {
            "text":
            ':red_circle: Sorry, there was an error executing the requested action: {0}'
            .format(error),
            "attachments": [],
            'replace_original':
            False
        }

    def handle_action(self, event):
        self.send_message('aaaa')
        action = Misc.array_pop(event.get('actions'), 0)
        action_value = Misc.get_value(action, 'value')
        try:
            target = getattr(self, action_value)
        except:
            channel = event.get('channel').get('id')
            team_id = event.get('team').get('id')
            # temp code (refactor when adding full support for blocks)
            text = ':point_right: message not recognised: {0}'.format(action)
            API_Slack_Blocks().set_text(text).send_message(channel, team_id)

            return self.message_not_supported_action(
                action)  # event.get('original_message'))

        try:
            return target(event)
        except Exception as error:
            return self.message_execution_error(error)

    def load_issue(self, issue_id=None):
        if issue_id:
            self.issue_id = issue_id
        self.issue = self.api_issues.issue(self.issue_id)
        return self

    def create(self):
        self.load_issue()
        if self.issue:
            key = self.issue.get('Key')
            summary = self.issue.get('Summary')
            latest_info = self.issue.get('Latest_Information')
            description = self.issue.get('Description')
            issue_type = self.issue.get('Issue Type')
            jira_link = "https://glasswall.atlassian.net/browse/{0}".format(
                key)  # todo: put the glasswall jira url in a site config value
            #key_link    = "{0}/browse/{1}".format(self.api_issues.server_url(), key)

            add_layout = self.slack_blocks.add_layout_section

            #text = "*{0}*:\n<{1}|{2} - {3}>".format(issue_type,key_link,key, summary)
            text = ":point_right: *Issue*: <{1}|{2} - {3}>".format(
                issue_type, jira_link, key, summary)

            add_layout(self.issue_id).add_text(text).render()
            if latest_info:
                add_layout().add_text(
                    '*Latest Info:* \n{0}'.format(latest_info)).render()
            if description:
                add_layout().add_text(
                    '*Description:* \n{0}'.format(description)).render()

            actions_section = self.slack_blocks.add_layout_actions(
                self.action_id)
            footer_section = self.slack_blocks.add_layout_context()

            #actions_section.add_button('Edit Issue Field', self.issue_id) \
            actions_section.add_button('View Links'      , self.issue_id) \
                           .add_button('Screenshot'      , self.issue_id) \
                           .add_button('Reload Issue'    , self.issue_id) \
                           .add_button('Raw Issue Data'  , self.issue_id)
            # .add_button('Change Status', self.issue_id)

            self.add_block_actions_with_transitions(self.slack_blocks)

            self.add_select_with_issue_links()

            self.add_block_edit_issue_field(self.slack_blocks)

            self.slack_blocks.add_text('*Actions*')
            actions_section.render()

            self.slack_blocks.add_divider()
            footer_items = [
                'Status: *{0}*'.format(self.issue.get('Status')),
                'Rating: *{0}*'.format(self.issue.get('Rating')),
                'Priority: *{0}*'.format(self.issue.get('Priority')),
                'Issue Type: *{0}*'.format(self.issue.get('Issue Type')),
                'Assignee: *{0}*'.format(self.issue.get('Assignee')),
                'Labels: *{0}*'.format(self.issue.get('Labels')),
                'Creator: *{0}*'.format(self.issue.get('Creator')),
                'Created: *{0}*'.format(
                    self.issue.get('Created').split('T').pop(0)),
                'Updated: *{0}*'.format(
                    self.issue.get('Updated').split('T').pop(0))
            ]
            footer_section.add_texts(footer_items).render()

            #issue_data = "```{0}```".format(json.dumps(self.issue,indent=4))
            #self.slack_blocks.add_layout_section().add_text(issue_data).render()

            #self.slack_ui.text = "<{0}|{1} - {2}>".format(key_link,key, summary)
            #self.add_overflow('abc', 'chose one' ,[('aaaa','aaaa_1'),('bbbb','bbbb_2')])
            #self.add_button('Edit Issue')
            #self.add_button('An Replay')

            self.slack_blocks.add_attachment({
                'text':
                'Issue *{0}* Status: `{1}`'.format(self.issue_id,
                                                   self.issue.get('Status')),
                'color':
                'good'
            })
            return True
        else:
            self.slack_blocks.add_layout_section().add_text(
                ':red_circle: Issue not found: `{0}`'.format(
                    self.issue_id)).render()
            return False

    def send(self):
        if self.channel:
            result = self.slack_blocks.send_message(self.channel, self.team_id)
            if type(result) == dict and result.get('ok') is False:
                error_messages = result.get('response_metadata').get(
                    'messages')
                self.send_message(
                    ':red_circle: Error in `Jira_View_Issue.send`; ```{0}```'.
                    format(error_messages))
            return result

    def create_and_send(self):
        if self.create():
            self.send_message(
                ':point_right: *Loading data for issue: `{0}`* :point_left:'.
                format(self.issue_id))
        return self.send()

    # def an_replay(self, event):
    #     original_message = event.get('original_message')
    #     return {
    #         'text'            : "{0}".format(event), #original_message.get('text'),
    #         'attachments'     : original_message.get('attachments'),
    #         'replace_original': True
    #     }

    def add_select_with_issue_links(self):
        issue_links = self.issue.get('Issue Links')
        if issue_links:
            actions = self.slack_blocks.add_layout_actions(
                action_id='Jira_View_Issue')
            option_groups = []
            size = 0
            for issue_type, links in issue_links.items():
                options = {}
                for link_issue_id in links:
                    link_issue = self.api_issues.issue(link_issue_id)
                    if link_issue:
                        link_summary = link_issue.get('Summary')
                        link_issue_type = link_issue.get('Issue Type')
                        text = "{0} - {1}".format(link_issue_type,
                                                  link_summary)[0:75]
                        if options.get(link_issue_type) is None:
                            options[link_issue_type] = [
                            ]  # use this to sort by link_issue_type
                        options[link_issue_type].append((text, link_issue_id))
                        #options.append((text , link_issue_id))

                options_sorted = []
                for key, values in options.items():
                    for value in values:
                        options_sorted.append(value)
                        size += 1
                option_groups.append((issue_type, options_sorted))

            self.slack_blocks.add_text(
                '*{0} Linked issues* (select to view)'.format(size))
            actions.add_select(
                'Issue Links',
                option_groups=option_groups)  #, action_id='view_issue')

            return actions.render()

    def create_ui_actions_with_transitions(self,
                                           issue_id=None,
                                           current_status=None,
                                           show_intro=True):
        if issue_id:
            self.issue_id = issue_id
        view = API_Slack_Blocks()
        self.add_block_actions_with_transitions(view, current_status,
                                                show_intro)
        return view.send_message(self.channel, self.team_id)

    def add_block_actions_with_transitions(self,
                                           view,
                                           current_status=None,
                                           show_intro=True):
        if self.issue is None:
            self.issue = self.api_issues.issue(self.issue_id)
        if current_status is None:  # this helps with the situation when the issue has just been updated but the data has not reached out to ELK
            current_status = self.issue.get('Status')
        transitions = self.api_jira.issue_next_transitions(self.issue_id)
        if show_intro:
            view.add_text("*Change issue status to*: (click to change)")
        if len(transitions) > 0:
            actions = view.add_layout_actions(action_id='Jira_View_Issue')
            for key, value in transitions.items():
                if key != current_status:
                    action_id = "transition_to::{0}".format(value)
                    value = "{0}::{1}::{2}".format(self.issue_id, value, key)
                    actions.add_button(key, value=value, action_id=action_id)

            return actions.render()
        view.add_text('...no Transitions available...')

    def create_ui_edit_issue_field(self):
        view = API_Slack_Blocks()
        self.add_block_edit_issue_field(view)
        return view.send_message(self.channel, self.team_id)

    def add_block_edit_issue_field(self, view):
        view.add_text("*Edit Issue Field:* (select to edit)".format(
            self.issue_id))
        self.issue = self.api_issues.issue(self.issue_id)
        if self.issue:
            #fields = set(self.issue)
            fields = [
                'Summary', 'Description', 'Labels'
                #'Assignee','Description', 'Labels', 'Latest Information','Summary',
                #'Priority','Rating','Email', 'Slack ID','Image_Url'
            ]
            action_id = 'Jira_View_Issue::edit_field::{0}'.format(
                self.issue_id)
            view.add_select(action_id, 'Field to edit', fields)

    # callback methods

    def send_message(self, message):
        if self.channel:
            return slack_message(message, [], self.channel, self.team_id)
        else:
            return message

    def edit_field(self, action):
        try:
            selected_option = action.get('selected_option')
            field = selected_option.get('text').get('text')
            issue_id = action.get('action_id').split('::').pop(3)
            trigger_id = self.event.get('trigger_id')
            slack_dialog = Jira_Edit_Issue(issue_id, field).setup().render()
            from gw_bot.api.API_Slack import API_Slack
            API_Slack(self.channel,
                      self.team_id).slack.dialog_open(trigger_id=trigger_id,
                                                      dialog=slack_dialog)
        except Exception as error:
            self.send_message(
                ':red_circle: Error in edit_field: {0}'.format(error))

    def issue_links(self, action):
        self.view_issue(action)

    def reload_issue(self, action):
        self.view_issue(action)

    def screenshot(self, action):
        issue_id = action.get('value')
        payload = {
            'params': ['screenshot', issue_id],
            'channel': self.channel,
            'team_id': self.team_id
        }
        Lambda('osbot_jira.lambdas.jira').invoke_async(payload)

    def raw_issue_data(self, action):
        issue_id = action.get('value')
        issue = API_Issues().issue(issue_id)
        if issue:
            issue_data = "```{0}```".format(json.dumps(issue, indent=4))
            return self.send_message(issue_data)

    def view_issue(self, action):
        issue_id = action.get('value')
        if issue_id is None:
            selected_option = action.get('selected_option')
            if selected_option:
                issue_id = selected_option.get('value')
        if issue_id:
            payload = {
                'params': ['issue', issue_id],
                'channel': self.channel,
                'team_id': self.team_id
            }
            Lambda('osbot_jira.lambdas.jira').invoke_async(payload)
        else:
            self.send_message(
                ':red_circle: Error in View Issue, no issue id found in action :{0}'
                .format(action))

    def view_links(self, action):
        try:
            issue_id = action.get('value')
            self.send_message(
                ':point_right: Viewing all links for issue: `{0}`'.format(
                    issue_id))
            payload = {
                'params': ['links', issue_id, 'all', '1'],
                'channel': self.channel,
                'team_id': self.team_id
            }
            Lambda('osbot_jira.lambdas.jira').invoke_async(payload)
        except Exception as error:
            self.send_message(
                ':red_circle: Error in View Links for issue with id `{0}`: {1}'
                .format(issue_id, error))

    def change_status(self, action):
        try:
            self.issue_id = action.get('value')
            self.create_ui_actions_with_transitions()
        except Exception as error:
            self.send_message(
                ':red_circle: Error in change_status: {0}'.format(error))

    def edit_issue_field(self, action):
        try:
            self.issue_id = action.get('value')
            self.create_ui_edit_issue_field()
        except Exception as error:
            self.send_message(
                ':red_circle: Error in change_status: {0}'.format(error))

    def transition_to(self, action):
        value_split = action.get('value').split('::')
        issue_id = Misc.array_pop(value_split, 0)
        transition_to = Misc.array_pop(value_split, 0)
        transition_name = Misc.array_pop(value_split, 0)
        try:
            self.api_jira.issue_transition_to_id(issue_id, transition_to)
            self.send_message(
                ':white_check_mark: Changed `{0}` status to: *{1}*. Here are the new transitions available '
                .format(issue_id, transition_name))
            self.create_ui_actions_with_transitions(issue_id,
                                                    transition_name,
                                                    show_intro=False)
        except Exception as error:
            self.send_message(
                ':red_circle: Error in transition_to: {0}'.format(error))
예제 #14
0
class QGrid_To_Jira:
    def __init__(self, grid):
        self.grid = grid
        self.api_jira = API_Jira()
        self.api_jira_rest = API_Jira_Rest()

    def jira_update_issue_status(self, key, value):
        transitions = self.api_jira.issue_next_transitions(key)
        transitions_id = transitions.get(value)
        if transitions_id is None:
            return {
                'status': 'error',
                'data': 'transition not available: {0}'.format(value)
            }
        result = self.api_jira.jira().transition_issue(key, transitions_id)

        return {'status': 'ok', 'data': result}

    def jira_remove_links_to_target(self, from_id, link_type, to_id):
        all_issue_links = self.api_jira.issue_links(from_id)
        issue_links = all_issue_links.get(link_type)
        if issue_links:
            for issue_link in issue_links:
                if to_id == issue_link.get('Key'):
                    link_id = issue_link.get('Id')
                    print('deleting link', from_id, link_type, link_id)
                    self.api_jira.issue_delete_link(link_id)
                    return True
        return False
        #return True  # to handle cases when a mistaske is made on the new issue link type

    def jira_update_issue_link(self, issue_id, to_id, old_link_issue,
                               new_link_issue):
        removed_ok = self.jira_remove_links_to_target(issue_id, old_link_issue,
                                                      to_id)
        if new_link_issue is '':
            if removed_ok:
                return {'status': 'ok', 'data': 'issue link removed'}
            else:
                return {'status': 'error', 'data': 'failed to remove link'}
        try:
            self.api_jira.issue_add_link(issue_id, new_link_issue, to_id)
            print('added link', issue_id, new_link_issue, to_id)
            if removed_ok:
                return {'status': 'ok', 'data': 'issue link edited'}
            else:
                print('Removing link failed', issue_id, old_link_issue, to_id)
                return {
                    'status': 'error',
                    'data': 'removing link failed BUT, adding new link worked'
                }
        except Exception as error:
            print('Failed to add link', issue_id, new_link_issue, to_id)
            print(error.text)
            if removed_ok:
                return {
                    'status': 'error',
                    'data': 'adding link failed (after removing link)'
                }
            else:
                return {
                    'status': 'error',
                    'data': 'adding and removing links failed'
                }

    def jira_update_field(self, key, field, value):
        if not value:
            result = {'status': 'error', 'data': 'empty values not supported'}
        else:
            value = value.strip()
            if field == 'Latest_Information': field = 'Latest Information'
            if field == 'Status':
                result = self.jira_update_issue_status(key, value)
            else:
                data = self.api_jira_rest.issue_update_field(key, field, value)
                if data is False:
                    result = {'status': 'error', 'data': data}
                else:
                    result = {'status': 'ok', 'data': data}
            result['key'] = key
            result['field'] = field
            result['value'] = value

        return result

    def setup(self):
        def on_value_change(event, qgrid_widget):
            key = event.get('index')
            field = event.get('column')
            value = event.get('new')
            print("updating field `{0}` with value `{1}` on issue `{2}".format(
                field, value, key))
            result = self.jira_update_field(key, field, value)
            print(result)

        self.grid.on('cell_edited', on_value_change)
        return self
예제 #15
0
 def setUp(self):
     self.api = API_Jira()
예제 #16
0
class Test_API_Jira(unittest.TestCase):
    def setUp(self):
        self.api = API_Jira()

    # check connection

    def test_jira_server_info(self):
        jira = self.api.jira()
        assert jira.server_info().get('version') == '7.5.0'

    def test_jira(self):
        jira = self.api.jira()
        assert jira.__class__.__name__ == 'JIRA'
        assert jira.current_user() == 'gsbot'

    # methods

    def test_covert_issue(self):
        raw_issue = self.api.jira().issue('TASK-502')  # 'FACT-10') #
        issue = self.api.convert_issue(raw_issue)
        Dev.pprint(issue)
        # raw_issue = self.api.jira().issue('SEC-9195')# 'FACT-10') #
        # issue     = self.api.convert_issue(raw_issue)
        # self.api.convert_issue(self.api.jira().issue('SEC-9195'))
        # assert issue['Labels'   ] == ['SEC-9195', 'SEC-9195-CFO']       # check the fields added recently
        # assert issue['Priority' ] == 'Minor'
        #
        # raw_issue = self.api.jira().issue('GSOKR-900')                  # check epic link
        # issue = self.api.convert_issue(raw_issue)
        # assert issue['Epic Link'] == 'GSOKR-924'
        #
        # raw_issue = self.api.jira().issue('GSOKR-872')                  # check parent (for sub taks)
        # issue = self.api.convert_issue(raw_issue)
        # assert issue['Parent'] == 'GSOKR-279'
        # #Dev.pprint(issue)

    def test_fields(self):
        fields = self.api.fields()
        assert len(fields) > 10
        # data   = {}
        # for field in fields:
        #     data[field['name']] = field
        # print()
        # print('|--------------------------------------------------------------------------------------------------|')
        # print('|    name                                                 |             id            |   custom   |')
        # print('|--------------------------------------------------------------------------------------------------|')
        # for name in sorted(set(data.keys())):
        #     field = data[name]
        #     print('| {0:55} | {1:25} | {2:10} |'.format(field['name'], field['id'], str(field['custom'])))

    def test_fields_by_name(self):
        fields_by_name = self.api.fields_by_name()
        assert len(set(fields_by_name)) > 300

    @unittest.skip('this needs to be fixed top reflect the latest added fields'
                   )
    def test_issue(self):
        issue = self.api.issue('RISK-1083')

        assert issue == {
            'Components': [],
            'Issue Type': 'Risk',
            'Issue Links': [],
            'Key': 'RISK-1083',
            'Issue Links': {
                'RISK-1060': {
                    'Direction': 'Inward',
                    'Issue Type': 'Risk',
                    'Link Type': 'is blocked by',
                    'Priority': 'Minor',
                    'Status': 'Fixed',
                    'Summary': 'Test Risk'
                },
                'RISK-45': {
                    'Direction': 'Outward',
                    'Issue Type': 'Risk',
                    'Link Type': 'is child of',
                    'Priority': 'High',
                    'Status': 'Fixed',
                    'Summary': 'Test issue creation'
                },
                'RISK-32': {
                    'Direction': 'Outward',
                    'Issue Type': 'Risk',
                    'Link Type': 'relates to',
                    'Priority': 'Medium',
                    'Status': 'Fixed',
                    'Summary': 'TEST'
                }
            },
            'Rating': 'To be determined',
            'Risk Description': 'This is an description',
            'Risk Owner': 'Dinis Cruz',
            'Status': 'Fixed',
            'Summary': 'Test risk to GS-Bot'
        }

    def test_issue_add_link__error(self):
        try:
            Dev.pprint(self.api.issue_add_link('from', 'link_type', 'to'))
        except Exception as error:
            assert error.text == "No issue link type with name 'link_type' found."

    @unittest.skip(
        'needs to be refactored (this method will get the change log for the issues'
    )
    def _test_issue_change_log_only_status(self):
        statuses = self.api.issue_changes_log_only_status("Project=VULN", 300)

        Dev.pprint(statuses)
        #Dev.pprint(list(set(types)))

    def test_issue_update(self):
        issue_data = {
            "Key": "RISK-12",
            "Summary": "new summary value",
            "Risk Description": "el risk description",
            "Description": "the description"
        }
        #"Risk Rating"     : "Low"                }
        #"Status"          : "Blocked"            ,}

        result = self.api.issue_update(issue_data)
        Dev.pprint(result)

    # def test_issues_updated_in_last_hour(self):
    #     results    = self.api.issues_updated_in_last_hour()
    #     assert len(results) > 0
    #     #
    # results_1h = self.api.issues_updated_in_last_hour(1)
    # results_10h = self.api.issues_updated_in_last_hour(10)
    # assert results               ==  results_1h
    # assert set(results_1h)       == {'FACT-13', 'RISK-1597'}
    # assert len(set(results_10h)) == 19

    # def test_issues_updated_in_last_day(self):
    #     results = self.api.issues_updated_in_last_day()
    #     assert len(set(results)) > 1
    #     #Dev.pprint(len(set(results)))

    def test_projects(self):
        results = self.api.jira().projects()
        assert len(results) > 100

    def test_search(self):
        issues = self.api.search('labels=R1')
        assert issues['RISK-1592']['Summary'] == '6 - Risk to Brand'
        assert len(set(issues)) == 6

    def test_search_just_return_keys(self):
        keys = self.api.search_just_return_keys('labels=R1')
        assert keys == [
            'RISK-1592', 'RISK-1534', 'RISK-1498', 'RISK-1496', 'RISK-1495',
            'RISK-1494'
        ]
        #keys = self.api.search_just_return_keys('project=RISK')
        #assert len(set(keys)) > 100

    def test_covert_issue_vuln_priority(self):
        assert self.api.issue('VULN-1205').get('VULN Priority') == 'P3'
        assert self.api.issue('VULN-1624').get('VULN Priority') is None
예제 #17
0
def api_jira():
    return API_Jira()
예제 #18
0
def api_jira_qa_server():
    api_jira = API_Jira()
    api_jira.secrets_id = 'GS_BOT_GS_JIRA_QA'
    return api_jira