Exemple #1
0
 def validate_tech_approval(self):
     """
     notify in channel if not tech approved
     :return: relevant response dict
     """
     if self.pr.is_merged:  # and self.head_branch in PushPayload.PROTECTED_BRANCH_LIST:  TO ENABLE
         is_bad_pr = self.is_bad_pr()
         bad_name_str = MSG_BAD_START + "@" + self.created_by
         if is_bad_pr:
             msg = MSG_NO_TECH_REVIEW.format(
                 name=bad_name_str,
                 pr=self.pr.link_pretty,
                 title=self.pr.title,
                 branch=self.pr.base_branch,
                 team=self.pr.config.cc_tech_team)
             LOG.debug(msg)
             self.slack.postToSlack(self.pr.config.alertChannelName, msg)
             LOG.info("Bad PR={msg} repo:{repo}".format(repo=self.pr.repo,
                                                        msg=is_bad_pr))
             return {
                 "msg":
                 "Bad PR={msg} repo:{repo}".format(repo=self.pr.repo,
                                                   msg=is_bad_pr)
             }
         return {"msg": "PR is approved so No Alerts"}
     return {"msg": "Skipped review because its not PR merge event"}
Exemple #2
0
 def send_to_slack(self):
     final_text = str(self.parsed_data.comment)
     for item in self.js_map_dict:
         final_text = final_text.replace(
             '[~{0}]'.format(item),
             '<@{0}>'.format(self.js_map_dict.get(item)))
     LOG.info('************ final comment ************ %s' % final_text)
     first_attach = JIRA_COMMENT.copy()  # shallow copy
     first_attach["pretext"] = first_attach.get("pretext").format(
         commenter=self.parsed_data.commenter,
         issue_key=self.parsed_data.issue_key)
     first_attach["title"] = first_attach.get("title").format(
         issue_key=self.parsed_data.issue_key,
         issue_title=self.parsed_data.issue_title)
     first_attach["title_link"] = first_attach.get("title_link").format(
         issue_url=self.parsed_data.issue_url)
     first_attach["text"] = first_attach.get("text").format(
         final_text=final_text)
     attachment = list()
     attachment.append(first_attach)
     slack = Slacker(self.slack_token)
     # resp = slack.chat.post_message(channel="@Nagaraj", text="", username="******", as_user=False, attachments=attachment)
     for item in self.js_map_dict:
         slack.chat.post_message(channel=self.js_map_dict.get(item),
                                 text="",
                                 username="******",
                                 as_user=True,
                                 attachments=attachment)
Exemple #3
0
 def notify_channel_on_merge(self):
     """
     pass entry in fixed channel for all code merge details (merged to any of sensitive branch)
     :return: relevant response dict
     """
     if self.pr.is_merged:
         LOG.debug(
             "**** Repo=%s, new merge came to=%s, setting trace to=%s channel"
             % (self.pr.repo, self.pr.base_branch,
                self.pr.config.codeChannelName))
         msg = MSG_CODE_CHANNEL.format(title=self.pr.title,
                                       desc=self.pr.description,
                                       pr=self.pr.link,
                                       head_branch=self.pr.head_branch,
                                       base_branch=self.pr.base_branch,
                                       pr_by=self.created_by,
                                       merge_by=self.merged_by)
         self.slack.postToSlack(self.pr.config.codeChannelName, msg)
         LOG.info(
             "informed %s because pr=%s is merged into sensitive branch=%s"
             % (self.pr.config.codeChannelName, self.pr.link_pretty,
                self.pr.base_branch))
         return {
             "msg":
             "informed %s because pr=%s is merged into sensitive branch=%s"
             % (self.pr.config.codeChannelName, self.pr.link_pretty,
                self.pr.base_branch)
         }
     return {
         "msg",
         "Skipped posting to code channel because '%s' is not merge event" %
         self.pr.action
     }
Exemple #4
0
    def is_bad_pr(self):
        """
        parse approval's content to identify if PR is actually approved or just random approval click
        :return: bad_pr (boolean)
        """
        reviews = self.github.get_reviews()
        if 200 != reviews.status_code:
            raise Exception(reviews.content)

        bad_pr = True
        LOG.info("***** Reading Reviews *****")
        for item in json.loads(reviews.content):
            if "APPROVED" == item["state"]:
                review_comment = item["body"]
                LOG.debug("review body= %s" + review_comment)
                thumbsUpIcon = THUMBS_UP_ICON in json.dumps(review_comment)
                LOG.debug("unicode thumbsUp icon present=%s" % (thumbsUpIcon))
                if self.pr.opened_by in self.pr.config.superMembers:  # FEW FOLKS TO ALLOW TO HAVE SUPER POWER
                    LOG.debug("PR is opened by %s who is the super user of repo %s, so NO alert'"
                              % (self.pr.opened_by_slack, self.pr.repo))
                    bad_pr = False
                    break
                print "***** review_comment", review_comment
                created_by = self.pr.config.getSlackName(self.pr.opened_by)
                if item["user"]["login"] != created_by and (review_comment.find("+1") != -1 or thumbsUpIcon):
                    LOG.debug("+1 is found from reviewer=%s marking No Alert " % item["user"]["login"])
                    bad_pr = False
                    break
        return bad_pr
Exemple #5
0
 def notify_if_sensitive_modified(self):
     """
     check & notify devOps team if any sensitive files are touched
     :return: relevant response dict
     """
     if self.pr.is_merged:
         if self.sensitive_file_touched.get("is_found"):
             msg = MSG_SENSITIVE_FILE_TOUCHED.format(
                 notify_folks=self.pr.config.devOpsTeamToBeNotified,
                 file=self.sensitive_file_touched["file_name"],
                 pr=self.pr.link_pretty,
                 pr_by=self.created_by,
                 pr_number=self.pr.number)
             self.slack.postToSlack(self.pr.config.alertChannelName, msg)
             LOG.info(
                 "informed %s because sensitive files are touched in pr=%s"
                 % (self.pr.config.devOpsTeamToBeNotified,
                    self.pr.link_pretty))
             return {
                 "msg":
                 "informed %s because sensitive files are touched" %
                 self.pr.config.devOpsTeamToBeNotified
             }
         return {
             "msg":
             "Skipped sensitive files alerts because no sensitive file being touched"
         }
     return {
         "msg":
         "Skipped sensitive files alerts because its not PR merge event %s"
         % self.pr.config.devOpsTeamToBeNotified
     }
Exemple #6
0
    def validate_product_approval(self):
        """
        notify in channel if not product approved (applicable only to files/dir which require product approval)
        :return: relevant response dict
        """
        if self.pr.is_merged:
            if self.pr.opened_by in self.pr.config.superMembers:
                LOG.debug('pr_opened_by is super user of {repo} so NO alert, super_members={super_members}'
                          .format(repo=self.pr.repo, super_members=self.pr.config.superMembers))
                return {"msg": "Skipped product review because the PR=%s is by a Super User" % self.pr.link_pretty}

            if self.change_requires_product_plus1:
                comments = self.github.get_comments()
                is_product_plus1 = self.is_plus_1_in_comments(comments, self.pr.config.productTeamGithub)
                if not is_product_plus1:
                    bad_name_str = MSG_BAD_START + "@" + self.created_by
                    msg = MSG_NO_PRODUCT_REVIEW.format(name=bad_name_str, pr=self.pr.link_pretty, title=self.pr.title,
                                                    branch=self.pr.base_branch, team="".join(self.pr.config.productTeamToBeNotified))
                    LOG.debug(msg)
                    self.slack.postToSlack(self.pr.config.alertChannelName, msg)
                    LOG.info("Bad PR={msg} repo:{repo}".format(repo=self.pr.repo, msg=self.is_bad_pr))
                    return {"msg": "Bad PR={msg} repo:{repo}".format(repo=self.pr.repo, msg=self.is_bad_pr)}
                return {"msg":"Product approved so no alert, pr=%s" %self.pr.link_pretty}
            return {"msg":"Skipped product review because no changes found which requires product +1 as well, PR=%s"
                          %self.pr.link_pretty}
        return {"msg": "Skipped product review because the PR=%s is not merged" %self.pr.link_pretty}
Exemple #7
0
 def __init__(self, repo=None):
     config_file = os.environ["config"]
     #LOG.info("********** config file=" + config_file)
     LOG.info("********** config file={config_file}".format(
         config_file=config_file))
     # absolute path to keep file anywhere
     self.config = get_dict_from_config_file(config_file)
     self.repo_name = repo
Exemple #8
0
 def remind_direct_release_guideline_on_merge(self):
     """
     remind individually to follow guidelines for QA process
     :return: relevant response dict
     """
     if self.pr.is_merged:
         if self.base_branch in self.pr.config.sensitiveBranches:
             msg = MSG_GUIDELINE_ON_MERGE.format(person=self.created_by, pr=self.pr.link_pretty,
                                                 base_branch=self.pr.base_branch, title=self.pr.title,
                                                 release_notes_link=self.pr.config.release_notes_link)
             self.slack.directSlack('@' + self.created_by, msg)
             LOG.info("slacked personally to %s" % self.created_by)
             return {"msg": "slacked personally to %s" % self.created_by}
         return {"msg": "skipped slack personally because not sensitive branch"}
     return {"msg": "skipped slack personally to %s because its not merge event" % self.created_by}
Exemple #9
0
 def directSlack(self, person, msg=None, as_user=False, *args, **kwargs):
     if self.config.is_debug:
         person = self.config.debug_folks
     LOG.info("\n************** NOTIFYING ******************\n"
              "**************  %s      *************\n"
              "Message= %s\n"
              "******************************************* " %
              (person, msg))
     self.slack.chat.post_message(channel=person,
                                  text=msg,
                                  icon_url=self.icon,
                                  username="******",
                                  as_user=as_user,
                                  *args,
                                  **kwargs)
Exemple #10
0
 def close_dangerous_pr(self):
     """
     close a Pull Request which is not supposed to be opened Ex. base=master head=feature
     :return: relevant response dict
     """
     if self.pr.is_opened or self.pr.is_reopened:
         master_branch = self.pr.config.mainBranch
         qa_branch = self.pr.config.testBranch
         if self.base_branch == master_branch and self.head_branch != qa_branch:
             msg = MSG_AUTO_CLOSE.format(tested_branch=qa_branch, main_branch=master_branch)
             self.github.modify_pr(msg, "closed")
             self.slack.postToSlack(self.pr.config.alertChannelName, "@" + self.created_by + ": " + msg)
             LOG.info("closed dangerous PR %s" % self.pr.link_pretty)
             return {"msg": "closed dangerous PR %s" % self.pr.link_pretty}
         return {"msg": "skipped closing PR=%s because not raised to mainBranch %s" %(self.pr.link_pretty, master_branch)}
     return {"msg": "skipped closing PR because not a opened PR"}
Exemple #11
0
 def notify_on_action(self):
     """
     notify respective folk(s) on particular action. Ex. on open notify to lead (or on merged, can configure that)
     :return: relevant response dict
     """
     desired_action = self.pr.config.actionToBeNotifiedFor
     if self.pr.action == desired_action:
         if self.pr.base_branch == self.pr.config.mainBranch:
             msg = MSG_OPENED_TO_MAIN_BRANCH.format(
                 repo=self.pr.repo,
                 pr_by=self.created_by,
                 main_branch=self.pr.config.mainBranch,
                 title=self.pr.title,
                 pr=self.pr.link_pretty,
                 action=self.pr.action)
             for person in self.pr.config.techLeadsToBeNotified:
                 self.slack.postToSlack(person,
                                        msg + MSG_RELEASE_PREPARATION)
             LOG.info(
                 "Notified to %s on action %s" %
                 (self.pr.config.techLeadsToBeNotified, self.pr.action))
             return {
                 "msg":
                 "Notified to %s on action %s" %
                 (self.pr.config.techLeadsToBeNotified, self.pr.action)
             }
         else:
             msg = MSG_OPENED_TO_PREVENTED_BRANCH.format(
                 repo=self.pr.repo,
                 pr_by=self.created_by,
                 base_branch=self.pr.base_branch,
                 title=self.pr.title,
                 pr=self.pr.link_pretty,
                 action=self.pr.action)
             self.slack.postToSlack(self.pr.config.personToBeNotified, msg)
             LOG.info("Notified to %s on action %s" %
                      (self.pr.config.personToBeNotified, self.pr.action))
             return {
                 "msg":
                 "Notified to %s on action %s" %
                 (self.pr.config.personToBeNotified, self.pr.action)
             }
     return {
         "msg":
         "Skipped notify because its (%s) not desired event '%s'" %
         (self.pr.action, desired_action)
     }
Exemple #12
0
 def comment_on_pr(self):
     """
     comment on pr
     :return: relevant response dict
     """
     if self.pr.is_opened:
         if not self.pr.config.is_debug:
             if self.pr.base_branch == self.pr.config.mainBranch:
                 guideline_comment = SPECIAL_COMMENT
                 self.slack.postToSlack(self.pr.opened_by)
             else:
                 guideline_comment = GENERAL_COMMENT
             self.github.comment_pr(self.pr.comments_section, guideline_comment)
             LOG.info("**** Added Comment of dev guidelines ***")
             return {"msg": "Added Comment of dev guidelines"}
         return {"msg": "Skipped commenting because DEBUG is on "}
     return {"msg": "Skipped commenting because its not PR opened"}
Exemple #13
0
 def postToSlack(self, channel, msg=None, as_user=True, *args, **kwargs):
     LOG.info("\n************** NOTIFYING ******************\n"
              "**************  %s      *************\n"
              "Message= %s\n"
              "******************************************* " %
              (channel, msg))
     try:
         self.slack.chat.post_message(channel=channel,
                                      text=msg,
                                      icon_url=self.icon,
                                      as_user=as_user,
                                      *args,
                                      **kwargs)
     except Exception as ex:
         LOG.error("Error while posting alert to slack, please check if: \n1. The provided slack/hubot token for alice is correct " \
               "and it has access to the channel=%s" \
               "\n2.The channel name is correct\n" %(channel))
         raise ex
Exemple #14
0
 def parse_files_and_set_flags(self):
     """
     Parse payload and keep important flags ready to be used in checks
     :return: sensitive_file_touched (dict of file name with boolean value)
     :return: change_requires_product_plus1 (boolean)
     """
     change_requires_product_plus1 = False
     sensitive_file_touched = {}
     try:
         files_contents = self.github.get_files()
         LOG.info("**** Reading files ****")
         for item in files_contents:
             file_path = item["filename"]
             if any(x in str(file_path) for x in self.pr.config.sensitiveFiles):
                 sensitive_file_touched["is_found"] = True
                 sensitive_file_touched["file_name"] = str(file_path)
             if item["filename"].find(self.pr.config.productPlusRequiredDirPattern) != -1:
                 LOG.info("product change found marking ui_change to True")
                 change_requires_product_plus1 = True
                 # break
     except PRFilesNotFoundException, e:
         LOG.exception(e)
Exemple #15
0
    def handle_issue_create(self):
        assignee_slack_channel_id = self.slack_dict.get(
            self.parsed_data.assignee_email)
        LOG.info(
            '*********** assigne slack channel id create handler ************ %s'
            % assignee_slack_channel_id)
        attachment = list()
        fields = list()
        for change in self.parsed_data.change_log:
            field_item = dict()
            field_list = ['assignee', 'description', 'priority', 'Status']
            if str(change.get("field")) in field_list:
                field_item["title"] = str(change.get("field"))
                field_item["value"] = str(change.get("toString"))
                fields.append(field_item)

        attach = JIRA_ISSUE_UPDATE.copy()
        attach[
            'pretext'] = '*{issue_reporter}* reported issue *{issue_key}*'.format(
                issue_reporter=self.parsed_data.issue_reporter,
                issue_key=self.parsed_data.issue_key)
        attach["title"] = attach.get("title").format(
            issue_key=self.parsed_data.issue_key,
            issue_title=self.parsed_data.issue_title)
        attach["title_link"] = attach.get("title_link").format(
            issue_url=self.parsed_data.issue_url)
        attach["text"] = ''
        attach["fields"] = fields
        attachment.append(attach)
        slack = Slacker(self.slack_token)
        # resp = slack.chat.post_message(channel="@Nagaraj", text="", username="******", as_user=True, attachments=attachment)
        slack.chat.post_message(channel=str(assignee_slack_channel_id),
                                text="",
                                username="******",
                                as_user=True,
                                attachments=attachment)
Exemple #16
0
class RunChecks(object):
    def execute_check(self, ci, check):
        LOG.debug("************* Starting check=%s *****************" % check)
        response = getattr(ci, check)()
        LOG.debug("for check= %s, response= %s" % (check, response))

    def run_checks(self, request, data):
        ci = CheckImpl(PushPayloadParser(request, payload=data))
        response = {}
        checks = ci.pr.config.checks
        if ci.pr.is_sensitive_branch:
            if len(checks) == 0:
                import inspect
                method_names = [
                    attr for attr in dir(ci)
                    if inspect.ismethod(getattr(ci, attr))
                ]
                for check in method_names:
                    if check != "__init__":
                        self.execute_check(ci, check)
            else:
                try:
                    for check in checks:
                        try:
                            self.execute_check(ci, check)
                        except AttributeError:
                            LOG.debug("Exception in Run Checks",
                                      exc_info=traceback)
                            raise CheckNotFoundException(check)
                except Exception, e:
                    LOG.debug("Exception in Run Checks", exc_info=traceback)
                    if 'invalid_auth' not in e:
                        raise Exception(
                            str(e) + ISSUE_FOUND.format(issue_link=ISSUE_LINK))
            return response
        LOG.info("skipped because '%s' is not sensitive branch" %
                 ci.base_branch)
        return {
            "msg":
            "skipped because '%s' is not sensitive branch" % ci.base_branch
        }
Exemple #17
0
 def __init__(self, repo):
     config_file = os.environ["config"]
     LOG.info("********** config file=" + config_file)
     # absolute path to keep file anywhere
     self.config = get_dict_from_config_file(config_file)
     self.repo_name = repo
Exemple #18
0
 def handle_issue_update(self):
     assignee_slack_channel_id = self.slack_dict.get(
         self.parsed_data.assignee_email)
     reporter_slack_channel_id = self.slack_dict.get(
         self.parsed_data.issue_reporter_email)
     issue_reporter_email_id = self.parsed_data.issue_reporter_email
     issue_updated_email_id = self.parsed_data.issue_updated_by_email
     assignee_email_id = self.parsed_data.assignee_email
     LOG.info(
         '*********** assigne slack channel id update handler ************ %s'
         % assignee_slack_channel_id)
     LOG.info(
         '*********** reporter slack channel id update handler ************ %s'
         % reporter_slack_channel_id)
     attachment = list()
     for change in self.parsed_data.change_log:
         attach = JIRA_ISSUE_UPDATE.copy()
         if change.get("field") == "description":
             attach[
                 'pretext'] = "*{issue_updated_by}* updated {issue_key} `{field}`".format(
                     issue_updated_by=self.parsed_data.issue_updated_by,
                     issue_key=self.parsed_data.issue_key,
                     field=change.get('field'),
                 )
         else:
             if change.get('fromString'):
                 attach['pretext'] = attach.get("pretext").format(
                     issue_updated_by=self.parsed_data.issue_updated_by,
                     issue_key=self.parsed_data.issue_key,
                     field=change.get('field'),
                     from_string=change.get('fromString'),
                     to_string=change.get('toString'))
             else:
                 attach[
                     'pretext'] = "*{issue_updated_by}* updated {issue_key} `{field}` to `{to_string}`".format(
                         issue_updated_by=self.parsed_data.issue_updated_by,
                         issue_key=self.parsed_data.issue_key,
                         field=change.get('field'),
                         to_string=change.get('toString'))
         attach["title"] = attach.get("title").format(
             issue_key=self.parsed_data.issue_key,
             issue_title=self.parsed_data.issue_title)
         attach["title_link"] = attach.get("title_link").format(
             issue_url=self.parsed_data.issue_url)
         attach["text"] = attach.get("text").format(
             issue_desc=self.description)
         attachment.append(attach)
     slack = Slacker(self.slack_token)
     # resp = slack.chat.post_message(channel="@Nagaraj", text="", username="******", as_user=True, attachments=attachment)
     if issue_updated_email_id == issue_reporter_email_id and issue_updated_email_id != assignee_email_id:
         slack.chat.post_message(channel=str(assignee_slack_channel_id),
                                 text="",
                                 username="******",
                                 as_user=True,
                                 attachments=attachment)
     elif issue_updated_email_id == assignee_email_id and issue_updated_email_id != issue_reporter_email_id:
         slack.chat.post_message(channel=str(reporter_slack_channel_id),
                                 text="",
                                 username="******",
                                 as_user=True,
                                 attachments=attachment)