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
def check_if_repo_exists(self, data, user_data, reponame, real_org): try: result = self.check_gh_for_existing_repo(reponame, real_org) if not result: send_error( data["channel"], "@{}: This repository does not exist in {}.".format( user_data["name"], real_org)) return False return True except Exception as e: send_error( data["channel"], "@{}: I encountered a problem:\n\n{}".format( user_data["name"], e)) return False
def process_the_command(data, command_prefix): """ Will perform all command_plugins duties if a command_plugins arrived. :param data: :param command_prefix: :return: """ # Reach out to slack to get the user's information: user_data, error = get_user_data(data) if error: send_error(data["channel"], "ERROR: Unable to communicate with the Slack API. Error:\n{}".format(error)) return # Execute the message: if COMMANDS[command_prefix]["user_data_required"]: COMMANDS[command_prefix]["func"](data, user_data) else: COMMANDS[command_prefix]["func"](data)
def make_repo_edit(self, data, user_data, reponame, real_org, **kwargs): try: self.modify_repo(reponame, real_org, **kwargs) except requests.exceptions.RequestException as re: send_error( data["channel"], "@{}: Problem encountered modifying the repository.\n" "The response code from GitHub was: {}".format( user_data["name"], str(re))) return False except Exception as e: send_error( data["channel"], "@{}: Problem encountered setting the {} field.\n" "Here are the details: {}".format(kwargs.keys()[0], user_data["name"], str(e))) return False return True
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)
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)
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)
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)
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)
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)