def _create_issuetracker_info(assessment, issue_tracker_info): """Creates an entry for IssueTracker model.""" if not issue_tracker_info.get('title'): issue_tracker_info['title'] = assessment.title if not issue_tracker_info.get('due_date'): issue_tracker_info['due_date'] = assessment.start_date issue_tracker_info['status'] = ASSESSMENT_STATUSES_MAPPING.get( assessment.status ) if (issue_tracker_info.get('enabled') and _is_issue_tracker_enabled(audit=assessment.audit)): try: issue_id = _create_issuetracker_issue(assessment, issue_tracker_info) except integrations_errors.Error as error: logger.error( 'Unable to create a ticket while creating assessment ID=%d: %s', assessment.id, error) issue_tracker_info = { 'enabled': False, } assessment.add_warning('Unable to create a ticket.') else: issue_url = integration_utils.build_issue_tracker_url(issue_id) issue_tracker_info['issue_id'] = issue_id issue_tracker_info['issue_url'] = issue_url else: issue_tracker_info = { 'enabled': False, } all_models.IssuetrackerIssue.create_or_update_from_dict( assessment, issue_tracker_info)
def create_ticket_for_new_issue(obj, issue_tracker_info): """Create new IssueTracker ticket for issue""" builder = issue_tracker_params_builder.IssueParamsBuilder() issue_tracker_params = builder.build_create_issue_tracker_params( obj, issue_tracker_info ) if issue_tracker_params.is_empty(): return # Query to IssueTracker. issue_tracker_query = issue_tracker_params.get_issue_tracker_params() # Parameters for creation IssuetrackerIssue object in GGRC. issuetracker_issue_params = issue_tracker_params.get_params_for_ggrc_object() try: res = issues.Client().create_issue(issue_tracker_query) issue_url = integration_utils.build_issue_tracker_url(res["issueId"]) issuetracker_issue_params["issue_url"] = issue_url issuetracker_issue_params["issue_id"] = res["issueId"] except integrations_errors.Error as error: logger.error( "Unable to create a ticket while creating object ID=%d: %s", obj.id, error ) obj.add_warning("Unable to create a ticket in issue tracker.") issuetracker_issue_params["enabled"] = False # Create object in GGRC with info about issue tracker integration. all_models.IssuetrackerIssue.create_or_update_from_dict( obj, issuetracker_issue_params )
def create_ticket_for_new_issue(obj, issue_tracker_info): """Create new IssueTracker ticket for issue""" builder = issue_tracker_params_builder.IssueParamsBuilder() issue_tracker_params = builder.build_create_issue_tracker_params( obj, issue_tracker_info) if issue_tracker_params.is_empty(): return # Query to IssueTracker. issue_tracker_query = issue_tracker_params.get_issue_tracker_params() # Parameters for creation IssuetrackerIssue object in GGRC. issuetracker_issue_params = issue_tracker_params.get_params_for_ggrc_object( ) try: res = issues.Client().create_issue(issue_tracker_query) issue_url = integration_utils.build_issue_tracker_url(res["issueId"]) issuetracker_issue_params["issue_url"] = issue_url issuetracker_issue_params["issue_id"] = res["issueId"] except integrations_errors.Error as error: logger.error( "Unable to create a ticket while creating object ID=%d: %s", obj.id, error) obj.add_warning("Unable to create a ticket in issue tracker.") issuetracker_issue_params["enabled"] = False # Create object in GGRC with info about issue tracker integration. all_models.IssuetrackerIssue.create_or_update_from_dict( obj, issuetracker_issue_params)
def _process_result(result, issue_json): """Process result of issuetracker synchronization.""" if result and not issue_json.get("issue_id"): issue_json["enabled"] = True issue_json["issue_id"] = result.get("issueId") issue_json[ "issue_url"] = integration_utils.build_issue_tracker_url( result.get("issueId")) elif not result and not issue_json.get("issue_id"): raise integrations_errors.Error("Unknown error")
def link_issue(obj, ticket_id, issue_tracker_info): """Link issue to existing IssueTracker ticket""" if _is_already_linked(ticket_id): logger.error( "Unable to link a ticket while creating object ID=%d: %s ticket ID is " "already linked to another GGRC object", obj.id, ticket_id, ) obj.add_warning( "This ticket was already linked to another GGRC issue, assessment " "or review object. Linking the same ticket to multiple objects is not " "allowed due to potential for conflicting updates." ) return builder = issue_tracker_params_builder.IssueParamsBuilder() issue_tracker_container = builder.build_params_for_issue_link( obj, ticket_id, issue_tracker_info, ) if issue_tracker_container.is_empty(): return # Query to IssueTracker. issue_tracker_query = issue_tracker_container.get_issue_tracker_params() # Parameters for creation IssuetrackerIssue object in GGRC. issuetracker_issue_params = \ issue_tracker_container.get_params_for_ggrc_object() try: issues.Client().update_issue(ticket_id, issue_tracker_query) ticket_url = integration_utils.build_issue_tracker_url(ticket_id) issuetracker_issue_params["issue_url"] = ticket_url issuetracker_issue_params["issue_id"] = ticket_id update_initial_issue(obj, issue_tracker_container) except integrations_errors.Error as error: logger.error("Unable to update a ticket ID=%s while deleting" " issue ID=%d: %s", ticket_id, obj.id, error) obj.add_warning("Unable to update a ticket in issue tracker.") issuetracker_issue_params["enabled"] = False return if issuetracker_issue_params: all_models.IssuetrackerIssue.create_or_update_from_dict( obj, issuetracker_issue_params )
def link_issue(obj, ticket_id, issue_tracker_info): """Link issue to existing IssueTracker ticket""" if _is_already_linked(ticket_id): logger.error( "Unable to link a ticket while creating object ID=%d: %s ticket ID is " "already linked to another GGRC object", obj.id, ticket_id, ) obj.add_warning( "This ticket was already linked to another GGRC issue, assessment " "or review object. Linking the same ticket to multiple objects is not " "allowed due to potential for conflicting updates." ) return builder = issue_tracker_params_builder.IssueParamsBuilder() issue_tracker_container = builder.build_params_for_issue_link( obj, ticket_id, issue_tracker_info, ) if issue_tracker_container.is_empty(): return # Query to IssueTracker. issue_tracker_query = issue_tracker_container.get_issue_tracker_params() # Parameters for creation IssuetrackerIssue object in GGRC. issuetracker_issue_params = \ issue_tracker_container.get_params_for_ggrc_object() try: issues.Client().update_issue(ticket_id, issue_tracker_query) ticket_url = integration_utils.build_issue_tracker_url(ticket_id) issuetracker_issue_params["issue_url"] = ticket_url issuetracker_issue_params["issue_id"] = ticket_id update_initial_issue(obj, issue_tracker_container) except integrations_errors.Error as error: logger.error("Unable to update a ticket ID=%s while deleting" " issue ID=%d: %s", ticket_id, obj.id, error) obj.add_warning("Unable to update a ticket in issue tracker.") issuetracker_issue_params["enabled"] = False return if issuetracker_issue_params: all_models.IssuetrackerIssue.create_or_update_from_dict( obj, issuetracker_issue_params )
def _process_result(result, issue_json): """Process result of issuetracker synchronization.""" if result and not issue_json.get("issue_id"): issue_json["enabled"] = True issue_json["issue_id"] = result.get("issueId") issue_json["issue_url"] = integration_utils.build_issue_tracker_url( result.get("issueId") ) elif not result and not issue_json.get("issue_id"): raise integrations_errors.Error("Unknown error") if not issue_json.get("assignee") and result: issue_json["assignee"] = result.get("issueState", {}).get("assignee") if not issue_json.get("reporter") and result: issue_json["reporter"] = result.get("issueState", {}).get("reporter")
def _link_assessment(assessment, issue_tracker_info): """Link Assessment to existing IssueTracker ticket""" ticket_id = issue_tracker_info['issue_id'] if integration_utils.is_already_linked(ticket_id): logger.error( "Unable to link a ticket while creating object ID=%d: %s ticket ID is " "already linked to another GGRC object", assessment.id, ticket_id, ) assessment.add_warning( "This ticket was already linked to another GGRC issue, assessment or " "review object. Linking the same ticket to multiple objects is not " "allowed due to potential for conflicting updates.") return try: response = issues.Client().get_issue(ticket_id) except integrations_errors.Error as error: logger.error( "Unable to link a ticket while creating object ID=%d: %s", assessment.id, error, ) assessment.add_warning( "Ticket tracker ID does not exist or you do not have access to it." ) return issue_params = prepare_issue_json(assessment, issue_tracker_info, True) issuetracker_ccs = response.get("issueState", {}).get("ccs", []) grouped_ccs = group_cc_emails(object_ccs=issue_params.get("ccs", []), additional_ccs=issuetracker_ccs) issue_params["ccs"] = grouped_ccs try: issues.Client().update_issue(ticket_id, issue_params) except integrations_errors.Error as error: logger.error( 'Unable to link a ticket while creating assessment ID=%d: %s', assessment.id, error) issue_tracker_info['enabled'] = False assessment.add_warning('Unable to link a ticket.') else: issue_url = integration_utils.build_issue_tracker_url(ticket_id) issue_tracker_info['issue_url'] = issue_url all_models.IssuetrackerIssue.create_or_update_from_dict( assessment, issue_tracker_info)
def test_update_issuetracker_title(self, mocked_update_issue): """Test title sync in case it has been updated.""" with mock.patch.object( assessment_integration.AssessmentTrackerHandler, '_is_tracker_enabled', return_value=True ): iti_issue_id = [] iti = factories.IssueTrackerIssueFactory( enabled=True, component_id='123123', issue_severity='S2', issue_priority='P2' ) iti_issue_id.append(iti.issue_id) asmt = iti.issue_tracked_obj new_title = "New Title" self.api.put( asmt, { "issue_tracker": { "component_id": iti.component_id, "enabled": True, "issue_priority": iti.issue_priority, "issue_severity": iti.issue_severity, "issue_type": constants.DEFAULT_ISSUETRACKER_VALUES[ "issue_type" ], "title": new_title, "issue_id": iti.issue_id, "issue_url": integration_utils.build_issue_tracker_url( iti.issue_id ) } }) kwargs = {'status': 'ASSIGNED', 'component_id': int(iti.component_id), 'severity': iti.issue_severity, 'title': new_title, 'hotlist_ids': [], 'priority': iti.issue_priority} mocked_update_issue.assert_called_once_with(iti_issue_id[0], kwargs) issue = db.session.query(models.IssuetrackerIssue).get(iti.id) self.assertEqual(issue.title, new_title)
def _create_new_issuetracker_ticket(assessment, issue_tracker_info): """Create new IssueTracker ticket for assessment""" issue_tracker_request = prepare_issue_json(assessment, issue_tracker_info, create_issuetracker=True) try: res = issues.Client().create_issue(issue_tracker_request) except integrations_errors.Error as error: logger.error( 'Unable to create a ticket while creating assessment ID=%d: %s', assessment.id, error) issue_tracker_info['enabled'] = False assessment.add_warning('Unable to create a ticket.') else: issue_id = res['issueId'] issue_url = integration_utils.build_issue_tracker_url(issue_id) issue_tracker_info['issue_id'] = issue_id issue_tracker_info['issue_url'] = issue_url
def create_issue_handler(obj, issue_tracker_info): """Event handler for issue object creation.""" if not issue_tracker_info or not issue_tracker_info.get("enabled"): return # We need in flush here because we need object id for URL generation. db.session.flush() builder = issue_tracker_params_builder.IssueParamsBuilder() issue_tracker_params = builder.build_create_issue_tracker_params( obj, issue_tracker_info ) if issue_tracker_params.is_empty(): return # Query to IssueTracker. issue_tracker_query = issue_tracker_params.get_issue_tracker_params() # Parameters for creation IssuetrackerIssue object in GGRC. issuetracker_issue_params = issue_tracker_params.get_params_for_ggrc_object() try: res = issues.Client().create_issue(issue_tracker_query) issue_url = integration_utils.build_issue_tracker_url(res["issueId"]) issuetracker_issue_params["issue_url"] = issue_url issuetracker_issue_params["issue_id"] = res["issueId"] except integrations_errors.Error as error: logger.error( "Unable to create a ticket while creating object ID=%d: %s", obj.id, error ) obj.add_warning("Unable to create a ticket in issue tracker.") issuetracker_issue_params["enabled"] = False # Create object in GGRC with info about issue tracker integration. all_models.IssuetrackerIssue.create_or_update_from_dict( obj, issuetracker_issue_params )
def test_issue_tracker_error(self, issue_tracker_enabled, issue_id, issue_enabled): """Test that issue tracker does not change state in case receiving an error.""" del issue_enabled # Unused with mock.patch.object( sync_utils, 'update_issue' ) as update_issue_mock: error_data = integrations_errors.Error('data') update_issue_mock.side_effect = error_data issue = factories.IssueTrackerIssueFactory( enabled=issue_tracker_enabled, issue_id=issue_id ) src = { 'issue_tracker': { 'enabled': issue_tracker_enabled, 'issue_id': issue_id, 'issue_url': integration_utils.build_issue_tracker_url( issue_id ), 'component_id': '1111', 'issue_type': 'PROCESS', 'issue_priority': 'P2', 'issue_severity': 'S2', 'title': 'Title' } } assessment_integration._hook_assmt_issue_update( sender=None, obj=issue.issue_tracked_obj, src=src, initial_state=issue.issue_tracked_obj ) update_issue_mock.assert_called_once() issue_obj = models.IssuetrackerIssue.get_issue( "Assessment", issue.issue_tracked_obj.id ) self.assertEqual(issue_obj.enabled, issue_tracker_enabled)
def create_issue_handler(obj, issue_tracker_info): """Event handler for issue object creation.""" if not issue_tracker_info or not issue_tracker_info.get("enabled"): return # We need in flush here because we need object id for URL generation. db.session.flush() builder = issue_tracker_params_builder.IssueParamsBuilder() issue_tracker_params = builder.build_create_issue_tracker_params( obj, issue_tracker_info) if issue_tracker_params.is_empty(): return # Query to IssueTracker. issue_tracker_query = issue_tracker_params.get_issue_tracker_params() # Parameters for creation IssuetrackerIssue object in GGRC. issuetracker_issue_params = issue_tracker_params.get_params_for_ggrc_object( ) try: res = issues.Client().create_issue(issue_tracker_query) issue_url = integration_utils.build_issue_tracker_url(res["issueId"]) issuetracker_issue_params["issue_url"] = issue_url issuetracker_issue_params["issue_id"] = res["issueId"] except integrations_errors.Error as error: logger.error( "Unable to create a ticket while creating object ID=%d: %s", obj.id, error) obj.add_warning("Unable to create a ticket in issue tracker.") issuetracker_issue_params["enabled"] = False # Create object in GGRC with info about issue tracker integration. all_models.IssuetrackerIssue.create_or_update_from_dict( obj, issuetracker_issue_params)
def test_update_issuetracker_info(self): """Test that Issue Tracker issues are updated by the utility.""" cli_patch = mock.patch.object(sync_utils.issues, 'Client') hook_patch = mock.patch.object( assessment_integration.AssessmentTrackerHandler, '_is_tracker_enabled', return_value=True ) with cli_patch, hook_patch: iti_issue_id = [] for _ in xrange(2): iti = factories.IssueTrackerIssueFactory() iti_issue_id.append(iti.issue_id) asmt = iti.issue_tracked_obj asmt_id = asmt.id audit = asmt.audit self.api.modify_object(audit, { 'issue_tracker': { 'enabled': True, 'component_id': '11111', 'hotlist_id': '222222', }, }) asmt = db.session.query(models.Assessment).get(asmt_id) self.api.modify_object(asmt, { 'issue_tracker': { 'enabled': True, 'component_id': '11111', 'hotlist_id': '222222', 'issue_type': 'PROCESS', 'issue_priority': 'P2', 'issue_severity': 'S2', 'title': 'Default Title', 'issue_id': iti.issue_id, 'issue_url': integration_utils.build_issue_tracker_url( iti.issue_id ) }, }) asmt = db.session.query(models.Assessment).get(asmt_id) self.api.modify_object(asmt, { 'issue_tracker': { 'enabled': True, 'component_id': '11111', 'hotlist_id': '222222', 'issue_priority': 'P4', 'issue_type': 'PROCESS', 'issue_severity': 'S3', 'title': 'Default Title', 'issue_id': iti.issue_id, 'issue_url': integration_utils.build_issue_tracker_url( iti.issue_id ) }, }) self.api.delete(asmt) cli_mock = mock.MagicMock() cli_mock.update_issue.return_value = None cli_mock.search.return_value = { 'issues': [ { 'issueId': iti_issue_id[0], 'issueState': { 'status': 'FIXED', 'type': 'bug2', 'priority': 'P2', 'severity': 'S2', }, }, ], 'next_page_token': None, } with mock.patch.object(sync_utils.issues, 'Client', return_value=cli_mock): synchronization_jobs.sync_assessment_attributes() cli_mock.update_issue.assert_called_once_with( iti_issue_id[0], { 'status': 'ASSIGNED', 'priority': u'P4', 'type': constants.DEFAULT_ISSUETRACKER_VALUES['issue_type'], 'severity': u'S3', 'assignee': '', 'verifier': '', 'reporter': '', 'ccs': [], 'component_id': 11111 })
def test_update_ccs_many_audit_captains(self, mock_update_issue): """CCS shouldn't be calculated on update, only synchronization""" del mock_update_issue # Unused with mock.patch.object( assessment_integration.AssessmentTrackerHandler, '_is_tracker_enabled', return_value=True ): audit = factories.AuditFactory() audit_captains = factories.PersonFactory.create_batch(2) audit_captain_role = all_models.AccessControlRole.query.filter_by( name="Audit Captains", object_type="Audit" ).one() self.api.put( audit, { "access_control_list": [ { "ac_role_id": audit_captain_role.id, "person": { "id": audit_captain.id, "type": "Person" } } for audit_captain in audit_captains] } ) assessment = factories.AssessmentFactory( audit=audit ) assessment_issue = factories.IssueTrackerIssueFactory( enabled=True, issue_tracked_obj=assessment, component_id="11111", hotlist_id="222222", ) assessment_persons = factories.PersonFactory.create_batch(3) assignee_role = all_models.AccessControlRole.query.filter_by( name="Assignees", object_type="Assessment" ).one() creator_role = all_models.AccessControlRole.query.filter_by( name="Creators", object_type="Assessment" ).one() response_assessment = self.api.put( assessment, { "issue_tracker": { "component_id": "11111", "enabled": True, "hotlist_id": "222222", "issue_priority": "P2", "issue_severity": "S2", "title": "Assessment Title", "issue_type": "PROCESS", "issue_id": assessment_issue.issue_id, "issue_url": integration_utils.build_issue_tracker_url( assessment_issue.issue_id ) }, "access_control_list": [ { "ac_role_id": creator_role.id if not index else assignee_role.id, "id": index + 1, "person": { "context_id": None, "href": "/api/people/{}".format( person.id ), "id": person.id, "type": "Person" }, "person_email": person.email, "person_id": person.id, "person_name": person.name, "type": "AccessControlList" } for index, person in enumerate(assessment_persons)] } ) self.assert200(response_assessment) issue_tracker_assessment = all_models.IssuetrackerIssue.query.filter_by( object_id=assessment.id, object_type=assessment.type ).one() issue_tracker_cc = issue_tracker_assessment.cc_list.split(',')[0] self.assertIn(issue_tracker_cc, "")