Beispiel #1
0
    def authenticate(self, data, user_data, **kwargs):
        send_info(data["channel"], "🎟 @{}: Sending a Duo notification to your device. You must approve!"
                  .format(user_data["name"]), markdown=True)

        try:
            result = self._perform_auth(user_data)
        except InvalidDuoResponseError as idre:
            send_error(data["channel"], "💀 @{}: There was a problem communicating with Duo. Got this status: {}. "
                                        "Aborting..."
                       .format(user_data["name"], str(idre)), markdown=True)
            return False

        except CantDuoUserError as _:
            send_error(data["channel"], "💀 @{}: I can't Duo authenticate you. Please consult with IAE. Aborting..."
                       .format(user_data["name"]), markdown=True)
            return False

        except Exception as e:
            send_error(data["channel"], "💀 @{}: I encountered some issue with Duo... Here are the details: ```{}```"
                       .format(user_data["name"], str(e)), markdown=True)
            return False

        if not result:
            send_error(data["channel"], "💀 @{}: Your Duo request was rejected. Aborting..."
                       .format(user_data["name"]), markdown=True)
            return False

        # All Good:
        send_success(data["channel"], "🎸 @{}: Duo approved! Completing request..."
                     .format(user_data["name"]), markdown=True)
        return True
Beispiel #2
0
def print_help(data):
    text = "I support the following commands:\n"

    for txt in HELP_TEXT:
        text += txt

    text += "`!Help` - This command."
    send_info(data["channel"], text, markdown=True)
Beispiel #3
0
    def list_org_command(data):
        """
        The "!ListOrgs" command_plugins. Lists all organizations that this bot manages.
        :param data:
        :return:
        """
        headers = ["Alias", "Organization"]
        rows = []
        for org in ORGS.items():
            rows.append([org[0].lower(), org[0]])
            for alias in org[1]["aliases"]:
                rows.append([alias, org[0]])

        send_info(data["channel"],
                  "```{}```".format(tabulate(rows, headers=headers)),
                  markdown=True)
Beispiel #4
0
    def set_default_branch_command(self, data, user_data):
        """
        Sets the default branch of a repo.

        Command is as follows: !setdefaultbranch <organization> <repo> <branch>
        :param data:
        :return:
        """
        try:
            parser = argparse.ArgumentParser()
            parser.add_argument('org', type=str)
            parser.add_argument('repo', type=str)
            parser.add_argument('branch', type=str)

            args, unknown = parser.parse_known_args(
                args=preformat_args(data["text"]))
            if len(unknown) > 0:
                raise SystemExit()

            args = vars(args)

            # Check that we can use this org:
            real_org = self.org_lookup[args["org"]][0]
            reponame = extract_repo_name(args["repo"])
            branch = args["branch"]

        except KeyError as _:
            send_error(
                data["channel"],
                '@{}: Invalid orgname sent in.  Run `!ListOrgs` to see the valid orgs.'
                .format(user_data["name"]),
                markdown=True)
            return

        except SystemExit as _:
            send_info(
                data["channel"],
                "@{}: `!SetDefaultBranch` usage is:\n```!SetDefaultBranch <OrgThatHasRepo> "
                "<Repo> <NameOfBranch>```\n"
                "No special characters or spaces in the variables. \n"
                "Run `!ListOrgs` to see the list of GitHub Organizations that I manage. "
                "This will first check for the presence of the repo in the org before creating it."
                .format(user_data["name"]),
                markdown=True)
            return

        # Auth?
        if self.commands["!SetDefaultBranch"].get("auth"):
            if not self.commands["!SetDefaultBranch"]["auth"][
                    "plugin"].authenticate(
                        data, user_data, **
                        self.commands["!SetDefaultBranch"]["auth"]["kwargs"]):
                return

        # Output that we are doing work:
        send_info(data["channel"],
                  "@{}: Working, Please wait...".format(user_data["name"]))

        # Check that the repo exists:
        repo_data = self.check_gh_for_existing_repo(reponame, real_org)
        if not (repo_data):
            send_error(
                data["channel"],
                "@{}: This repository does not exist in {}.".format(
                    user_data["name"], real_org))
            return False

        # Check if the branch exists on that repo....
        if not (self.check_for_repo_branch(reponame, real_org, branch)):
            send_error(
                data["channel"],
                "@{}: This repository does not have the branch: `{}`.".format(
                    user_data["name"], branch),
                markdown=True)
            return False

        # Great, modify the description:
        if not (self.make_repo_edit(
                data, user_data, reponame, real_org, default_branch=branch)):
            return

        # Done:
        send_success(
            data["channel"],
            "@{}: The {}/{} repository's default branch has been set to: `{}`."
            .format(user_data["name"], real_org, reponame, branch),
            markdown=True)
Beispiel #5
0
    def create_repo_command(self, data, user_data):
        """
        Creates a new repository (default is private unless the org is public only).

        Command is as follows: !createrepo <newrepo> <organization>
        :param data:
        :return:
        """
        try:
            parser = argparse.ArgumentParser()
            parser.add_argument('new_repo', type=str)
            parser.add_argument('org', type=str)

            args, unknown = parser.parse_known_args(
                args=preformat_args(data["text"]))
            if len(unknown) > 0:
                raise SystemExit()

            args = vars(args)

            repo_to_add = args["new_repo"]

            # Check that we can use this org:
            real_org = self.org_lookup[args["org"]][0]

        except KeyError as _:
            send_error(
                data["channel"],
                '@{}: Invalid orgname sent in.  Run `!ListOrgs` to see the valid orgs.'
                .format(user_data["name"]),
                markdown=True)
            return

        except SystemExit as _:
            send_info(
                data["channel"],
                "@{}: `!CreateRepo` usage is:\n```!CreateRepo <NewRepoName> "
                "<GitHubOrgAliasToPutTheRepoInToHere>```\nNo special characters or spaces in the "
                "variables.  Run `!ListOrgs` to see the list of GitHub Organizations that I manage. "
                "This will first check for the presence of the repo in the org before creating it."
                .format(user_data["name"]),
                markdown=True)
            return

        # Auth?
        if self.commands["!CreateRepo"].get("auth"):
            if not self.commands["!CreateRepo"]["auth"]["plugin"].authenticate(
                    data, user_data, **
                    self.commands["!CreateRepo"]["auth"]["kwargs"]):
                return

        # Output that we are doing work:
        send_info(data["channel"],
                  "@{}: Working, Please wait...".format(user_data["name"]))

        # Check if the repo already exists:
        try:
            result = self.check_gh_for_existing_repo(repo_to_add, real_org)

            if result:
                send_error(
                    data["channel"],
                    "@{}: This repository already exists in {}!".format(
                        user_data["name"], real_org))
                return

        except Exception as e:
            send_error(
                data["channel"], "@{}: I encountered a problem:\n\n{}".format(
                    user_data["name"], e))

            return

        # Great!! Create the repository:
        try:
            visibility = True if not ORGS[real_org]["public_only"] else False
            self.create_new_repo(repo_to_add, real_org, visibility)
        except Exception as e:
            send_error(
                data["channel"], "@{}: I encountered a problem:\n\n{}".format(
                    user_data["name"], e))
            return

        # Grant the proper teams access to the repository:
        try:
            for perm_dict in ORGS[real_org]["new_repo_teams"]:
                self.set_repo_permissions(repo_to_add, real_org,
                                          perm_dict["id"], perm_dict["perm"])

        except Exception as e:
            send_error(
                data["channel"],
                "@{}: I encountered a problem setting repo permissions for team {team}: \n\n{exc}"
                .format(user_data["name"], team=perm_dict["name"], exc=e))
            return

        # All done!
        message = "@{}: The new repo: {} has been created in {}.\n\n".format(
            user_data["name"], repo_to_add, real_org)

        visibility = "PRIVATE" if visibility else "PUBLIC"

        message += "The repository is {visibility}.\n" \
                   "You are free to set up the repo as you like.\n".format(visibility=visibility)

        send_success(data["channel"], message)
Beispiel #6
0
    def add_outside_collab_command(self, data, user_data):
        """
        Adds an outside collaborator a repository with a specified permission.

        Command is as follows: !addcollab <organization> <repo> <permission>
        :param data:
        :return:
        """
        try:
            parser = argparse.ArgumentParser()
            parser.add_argument('outside_collab_id', type=str)
            parser.add_argument('org', type=str)
            parser.add_argument('repo', type=str)
            parser.add_argument('permission', type=str)

            args, unknown = parser.parse_known_args(
                args=preformat_args(data["text"]))
            if len(unknown) > 0:
                raise SystemExit()

            args = vars(args)

            outside_collab_id = args["outside_collab_id"]

            real_org = self.org_lookup[args["org"]][0]
            reponame = extract_repo_name(args["repo"])
            repo_access = args["permission"]

            # Check that the permissions and the org are correct:
            if repo_access not in self.commands["!AddCollab"][
                    "permitted_permissions"]:
                raise KeyError("Permissions")

        except KeyError as ke:
            if "Permissions" in str(ke):
                p_str = " or ".join([
                    "`{perm}`".format(perm=perm) for perm in
                    self.commands["!AddCollab"]["permitted_permissions"]
                ])
                send_error(
                    data["channel"],
                    '@{}: Invalid permission sent in.  Permissions must be {perms}.'
                    .format(user_data["name"], perms=p_str),
                    markdown=True)
            else:
                send_error(
                    data["channel"],
                    '@{}: Invalid orgname sent in.  Run `!ListOrgs` to see the valid orgs.'
                    .format(user_data["name"]),
                    markdown=True)
            return

        except SystemExit as _:
            send_info(
                data["channel"],
                "@{}: `!AddCollab` usage is:\n```!AddCollab <OutsideCollaboratorGitHubId> "
                "<OrgAliasThatContainsTheRepo> <RepoToAddAccessTo> "
                "<PermissionEitherPushOrPull>```"
                "\nNo special characters or spaces in the variables. "
                "Run `!ListOrgs` to see the list of GitHub Organizations that I manage. "
                .format(user_data["name"]),
                markdown=True)
            return

        # Auth?
        if self.commands["!AddCollab"].get("auth"):
            if not self.commands["!AddCollab"]["auth"]["plugin"].authenticate(
                    data, user_data, **
                    self.commands["!AddCollab"]["auth"]["kwargs"]):
                return

        # Output that we are doing work:
        send_info(data["channel"],
                  "@{}: Working, Please wait...".format(user_data["name"]))

        # Check that the repo exists:
        if not (self.check_if_repo_exists(data, user_data, reponame,
                                          real_org)):
            return

        # Check that the GitHub ID is actually real:
        try:
            found_user = self.get_github_user(outside_collab_id)

            if not found_user:
                send_error(
                    data["channel"],
                    "@{}: The GitHub user: {} does not exist.".format(
                        user_data["name"], outside_collab_id))
                return

        except Exception as e:
            send_error(
                data["channel"],
                "@{}: A problem was encountered communicating with GitHub to verify the user's GitHub "
                "id. Here are the details:\n{}".format(user_data["name"],
                                                       str(e)))
            return

        # So: GitHub ID is real - and the repo exists -- grant access:
        try:
            self.add_outside_collab_to_repo(outside_collab_id, reponame,
                                            real_org, repo_access)

        except ValueError as ve:
            send_error(
                data["channel"],
                "@{}: Problem encountered adding the user as an outside collaborator.\n"
                "The response code from GitHub was: {}".format(
                    user_data["name"], str(ve)))
            return

        except Exception as e:
            send_error(
                data["channel"],
                "@{}: Problem encountered adding the user as an outside collaborator.\n"
                "Here are the details: {}".format(user_data["name"], str(e)))
            return

        # Done:
        send_success(
            data["channel"],
            "@{}: The GitHub user: `{}` has been added as an outside collaborator with `{}` "
            "permissions to {}/{}.".format(user_data["name"],
                                           outside_collab_id, repo_access,
                                           real_org, reponame),
            markdown=True)
Beispiel #7
0
    def set_repo_homepage_command(self, data, user_data):
        """
        Changes a repository's homepage.

        Command is as follows: !sethomepage <organization> <repo> <homepage>
        :param data:
        :return:
        """
        try:
            parser = argparse.ArgumentParser()
            parser.add_argument('org', type=str)
            parser.add_argument('repo', type=str)
            parser.add_argument('homepage', type=str)

            args, unknown = parser.parse_known_args(
                args=preformat_args_with_spaces(data["text"], 1))
            if len(unknown) > 0:
                raise SystemExit()

            args = vars(args)

            # Check that we can use this org:
            real_org = self.org_lookup[args["org"]][0]
            reponame = extract_repo_name(args["repo"])

            # Remove the "<>" from the homepage url (Thanks Slack!)
            homepage = args["homepage"].replace("<", "").replace(">", "")

            if homepage != "":
                if not validators.url(homepage):
                    raise ValueError()

        except KeyError as _:
            send_error(
                data["channel"],
                '@{}: Invalid orgname sent in.  Run `!ListOrgs` to see the valid orgs.'
                .format(user_data["name"]),
                markdown=True)
            return

        except ValueError as _:
            send_error(
                data["channel"],
                '@{}: Invalid homepage url was sent in. It must be a well formed URL.'
                .format(user_data["name"]),
                markdown=True)
            return

        except SystemExit as _:
            send_info(
                data["channel"],
                "@{}: `!SetHomepage` usage is:\n```!SetHomepage <OrgThatHasRepo> "
                "<Repo> <\"http://theHomePageUrlInQuotes\" - OR - \"\" to remove>```\n"
                "No special characters or spaces in the variables. \n"
                "Run `!ListOrgs` to see the list of GitHub Organizations that I manage. "
                "This will first check for the presence of the repo in the org before creating it."
                .format(user_data["name"]),
                markdown=True)
            return

        # Auth?
        if self.commands["!SetHomepage"].get("auth"):
            if not self.commands["!SetHomepage"]["auth"]["plugin"].authenticate(
                    data, user_data, **
                    self.commands["!SetHomepage"]["auth"]["kwargs"]):
                return

        # Output that we are doing work:
        send_info(data["channel"],
                  "@{}: Working, Please wait...".format(user_data["name"]))

        # Check that the repo exists:
        if not (self.check_if_repo_exists(data, user_data, reponame,
                                          real_org)):
            return

        # Great, modify the homepage:
        if not (self.make_repo_edit(
                data, user_data, reponame, real_org, homepage=homepage)):
            return

        # Done:
        if homepage == "":
            send_success(
                data["channel"],
                "@{}: The {}/{} repository's homepage field has been cleared.".
                format(user_data["name"], real_org, reponame, homepage),
                markdown=True)
        else:
            send_success(
                data["channel"],
                "@{}: The {}/{} repository's homepage has been modified to:\n"
                "`{}`.".format(user_data["name"], real_org, reponame,
                               homepage),
                markdown=True)
Beispiel #8
0
    def set_description_command(self, data, user_data):
        """
        Changes a repository description.

        Command is as follows: !setdescription <organization> <repo> <description>
        :param data:
        :return:
        """
        try:
            parser = argparse.ArgumentParser()
            parser.add_argument('org', type=str)
            parser.add_argument('repo', type=str)
            parser.add_argument('description', type=str)

            args, unknown = parser.parse_known_args(
                args=preformat_args_with_spaces(data["text"], 1))
            if len(unknown) > 0:
                raise SystemExit()

            args = vars(args)

            # Check that we can use this org:
            real_org = self.org_lookup[args["org"]][0]
            reponame = extract_repo_name(args["repo"])
            description = args["description"].replace("<", "").replace(">", "")

        except KeyError as _:
            send_error(
                data["channel"],
                '@{}: Invalid orgname sent in.  Run `!ListOrgs` to see the valid orgs.'
                .format(user_data["name"]),
                markdown=True)
            return

        except SystemExit as _:
            send_info(
                data["channel"],
                "@{}: `!SetDescription` usage is:\n```!SetDescription <OrgThatHasRepo> "
                "<Repo> <\"The Description in quotes\">```\n"
                "No special characters or spaces in the variables. \n"
                "Run `!ListOrgs` to see the list of GitHub Organizations that I manage. "
                "This will first check for the presence of the repo in the org before creating it."
                .format(user_data["name"]),
                markdown=True)
            return

        # Auth?
        if self.commands["!SetDescription"].get("auth"):
            if not self.commands["!SetDescription"]["auth"][
                    "plugin"].authenticate(
                        data, user_data, **
                        self.commands["!SetDescription"]["auth"]["kwargs"]):
                return

        # Output that we are doing work:
        send_info(data["channel"],
                  "@{}: Working, Please wait...".format(user_data["name"]))

        # Check that the repo exists:
        if not (self.check_if_repo_exists(data, user_data, reponame,
                                          real_org)):
            return

        # Great, modify the description:
        if not (self.make_repo_edit(
                data, user_data, reponame, real_org, description=description)):
            return

        # Done:
        if description == "":
            send_success(
                data["channel"],
                "@{}: The {}/{} repository's description field has been cleared."
                .format(user_data["name"], real_org, reponame),
                markdown=True)
        else:
            send_success(
                data["channel"],
                "@{}: The {}/{} repository's description has been modified to:\n"
                "`{}`.".format(user_data["name"], real_org, reponame,
                               description),
                markdown=True)
Beispiel #9
0
    def enable_travis_command(self, data, user_data):
        """
        Enables Travis CI on a repository within the organization.

        Command is as follows: !enabletravis <organization> <repo>
        :param data:
        :return:
        """
        from command_plugins.enabled_plugins import GITHUB_PLUGIN
        try:
            parser = argparse.ArgumentParser()
            parser.add_argument('org', type=str)
            parser.add_argument('repo', type=str)

            args, unknown = parser.parse_known_args(
                args=preformat_args(data["text"]))
            if len(unknown) > 0:
                raise SystemExit()

            args = vars(args)

            repo_to_set = extract_repo_name(args["repo"])

            # Check that we can use this org:
            real_org = GITHUB_PLUGIN.org_lookup[args["org"]][0]

        except KeyError as _:
            send_error(
                data["channel"],
                '@{}: Invalid orgname sent in.  Run `!ListOrgs` to see the valid orgs.'
                .format(user_data["name"]),
                markdown=True)
            return

        except SystemExit as _:
            send_info(
                data["channel"],
                "@{}: `!EnableTravis` usage is:\n```!EnableTravis <Organization> <Repo>"
                "```\nNo special characters or spaces in the variables. "
                "Run `!ListOrgs` to see the list of GitHub Organizations that I manage."
                .format(user_data["name"]),
                markdown=True)
            return

        # Auth?
        if self.commands["!EnableTravis"].get("auth"):
            if not self.commands["!EnableTravis"]["auth"][
                    "plugin"].authenticate(
                        data, user_data, **
                        self.commands["!EnableTravis"]["auth"]["kwargs"]):
                return

        # Output that we are doing work:
        send_info(data["channel"],
                  "@{}: Working, Please wait...".format(user_data["name"]))

        # Get the repo information from GitHub:
        try:
            repo_result = GITHUB_PLUGIN.check_gh_for_existing_repo(
                repo_to_set, real_org)

            if not repo_result:
                send_error(
                    data["channel"],
                    "@{}: This repository does not exist in {}!".format(
                        user_data["name"], real_org))
                return

        except Exception as e:
            send_error(
                data["channel"], "@{}: I encountered a problem:\n\n{}".format(
                    user_data["name"], e))
            return

        which = "pro" if repo_result["private"] else "public"

        try:
            # Check that the repo even exists:
            send_info(
                data["channel"],
                ":skull: Need to sync Travis CI with GitHub. Please wait...")
            self.sync_with_travis(which)

            send_info(
                data["channel"],
                ":guitar: Synced! Going to enable Travis CI on the repo now..."
            )

            travis_data = self.look_for_repo(which, repo_result)
            if not travis_data:
                send_error(
                    data["channel"],
                    "@{}: Couldn't find the repo in Travis for some reason...:\n\n"
                    .format(user_data["name"]))
                return

            # Is it already enabled?
            if travis_data["active"]:
                send_success(
                    data["channel"],
                    "@{}: Travis CI is already enabled on {}/{}.\n\n".format(
                        user_data["name"], real_org, repo_to_set))
                return

            # Enable it:
            self.enable_travis_on_repo(which, repo_result)

        except Exception as e:
            send_error(
                data["channel"],
                "@{}: I encountered a problem communicating with Travis CI:\n\n{}"
                .format(user_data["name"], e))
            return

        message = "@{}: Travis CI has been enabled on {}/{}.\n\n".format(
            user_data["name"], real_org, repo_to_set)
        send_success(data["channel"], message)