aboutsummaryrefslogtreecommitdiff
path: root/modules
diff options
context:
space:
mode:
authorGravatar jesopo2019-06-24 14:52:37 +0100
committerGravatar jesopo2019-06-24 14:52:37 +0100
commit14f2fd6a03002f410125ec5cce1e6150b3178887 (patch)
treeb5ee4ff43495304f8784c714de4478c01c6799b7 /modules
parentWind speed is given to us in metres per second. convert to kph (diff)
signature
split github webhook logic in to a more general webhook module
Diffstat (limited to 'modules')
-rw-r--r--modules/github.py223
-rw-r--r--modules/github/ghwebhook.md53
-rw-r--r--modules/webhooks/__init__.py190
-rw-r--r--modules/webhooks/github.py (renamed from modules/github/__init__.py)350
4 files changed, 440 insertions, 376 deletions
diff --git a/modules/github.py b/modules/github.py
new file mode 100644
index 00000000..14cb2314
--- /dev/null
+++ b/modules/github.py
@@ -0,0 +1,223 @@
+#--depends-on channel_access
+#--depends-on check_mode
+#--depends-on commands
+#--depends-on config
+#--depends-on permissions
+#--depends-on rest_api
+
+import datetime, itertools, json, math, re, urllib.parse
+from src import EventManager, ModuleManager, utils
+
+COLOR_BRANCH = utils.consts.ORANGE
+COLOR_REPO = utils.consts.GREY
+COLOR_POSITIVE = utils.consts.GREEN
+COLOR_NEUTRAL = utils.consts.LIGHTGREY
+COLOR_NEGATIVE = utils.consts.RED
+COLOR_ID = utils.consts.PINK
+
+API_ISSUE_URL = "https://api.github.com/repos/%s/%s/issues/%s"
+API_PULL_URL = "https://api.github.com/repos/%s/%s/pulls/%s"
+
+@utils.export("channelset", {"setting": "github-default-repo",
+ "help": "Set the default github repo for the current channel",
+ "example": "jesopo/bitbot"})
+@utils.export("channelset", {"setting": "auto-github",
+ "help": "Enable/disable automatically getting github issue/PR info",
+ "validate": utils.bool_or_none, "example": "on"})
+@utils.export("channelset", {"setting": "auto-github-cooldown",
+ "help": "Set amount of seconds between auto-github duplicates",
+ "validate": utils.int_or_none, "example": "300"})
+class Module(ModuleManager.BaseModule):
+ def _parse_ref(self, channel, ref):
+ repo, _, number = ref.rpartition("#")
+ org, _, repo = repo.partition("/")
+
+ default_repo = channel.get_setting("github-default-repo", "")
+ default_org, _, default_repo = default_repo.partition("/")
+
+ if org and not repo:
+ repo = org or default_repo
+ org = default_org
+ else:
+ org = org or default_org
+ repo = repo or default_repo
+
+ if not org or not repo or not number:
+ raise utils.EventError("Please provide username/repo#number")
+ if not number.isdigit():
+ raise utils.EventError("Issue number must be a number")
+ return org, repo, number
+
+ def _short_url(self, url):
+ try:
+ page = utils.http.request("https://git.io", method="POST",
+ post_data={"url": url})
+ return page.headers["Location"]
+ except utils.http.HTTPTimeoutException:
+ self.log.warn(
+ "HTTPTimeoutException while waiting for github short URL", [])
+ return url
+
+ def _change_count(self, n, symbol, color):
+ return utils.irc.color("%s%d" % (symbol, n), color)+utils.irc.bold("")
+ def _added(self, n):
+ return self._change_count(n, "+", COLOR_POSITIVE)
+ def _removed(self, n):
+ return self._change_count(n, "-", COLOR_NEGATIVE)
+ def _modified(self, n):
+ return self._change_count(n, "~", utils.consts.PURPLE)
+
+ def _parse_issue(self, page, username, repository, number):
+ repo = utils.irc.color("%s/%s" % (username, repository), COLOR_REPO)
+ number = utils.irc.color("#%s" % number, COLOR_ID)
+ labels = [label["name"] for label in page.data["labels"]]
+ labels_str = ""
+ if labels:
+ labels_str = "[%s] " % ", ".join(labels)
+
+ url = self._short_url(page.data["html_url"])
+
+ state = page.data["state"]
+ if state == "open":
+ state = utils.irc.color("open", COLOR_NEUTRAL)
+ elif state == "closed":
+ state = utils.irc.color("closed", COLOR_NEGATIVE)
+
+ return "(%s issue%s, %s) %s %s%s" % (
+ repo, number, state, page.data["title"], labels_str, url)
+ def _get_issue(self, username, repository, number):
+ return utils.http.request(
+ API_ISSUE_URL % (username, repository, number),
+ json=True)
+
+ @utils.hook("received.command.ghissue", min_args=1)
+ def github_issue(self, event):
+ if event["target"].get_setting("github-hide-prefix", False):
+ event["stdout"].hide_prefix()
+ event["stderr"].hide_prefix()
+
+ username, repository, number = self._parse_ref(
+ event["target"], event["args_split"][0])
+
+ page = self._get_issue(username, repository, number)
+ if page and page.code == 200:
+ self._parse_issue(page, username, repository, number)
+ else:
+ event["stderr"].write("Could not find issue")
+
+ def _parse_pull(self, page, username, repository, number):
+ repo = utils.irc.color("%s/%s" % (username, repository), COLOR_REPO)
+ number = utils.irc.color("#%s" % number, COLOR_ID)
+ branch_from = page.data["head"]["label"]
+ branch_to = page.data["base"]["label"]
+ added = self._added(page.data["additions"])
+ removed = self._removed(page.data["deletions"])
+ url = self._short_url(page.data["html_url"])
+
+ state = page.data["state"]
+ if page.data["merged"]:
+ state = utils.irc.color("merged", COLOR_POSITIVE)
+ elif state == "open":
+ state = utils.irc.color("open", COLOR_NEUTRAL)
+ elif state == "closed":
+ state = utils.irc.color("closed", COLOR_NEGATIVE)
+
+ return "(%s PR%s, %s) %s → %s [%s/%s] %s %s" % (
+ repo, number, state, branch_from, branch_to, added, removed,
+ page.data["title"], url)
+ def _get_pull(self, username, repository, number):
+ return utils.http.request(
+ API_PULL_URL % (username, repository, number),
+ json=True)
+ @utils.hook("received.command.ghpull", min_args=1)
+ def github_pull(self, event):
+ if event["target"].get_setting("github-hide-prefix", False):
+ event["stdout"].hide_prefix()
+ event["stderr"].hide_prefix()
+
+ username, repository, number = self._parse_ref(
+ event["target"], event["args_split"][0])
+ page = self._get_pull(username, repository, number)
+
+ if page and page.code == 200:
+ self._parse_pull(page, username, repository, number)
+ else:
+ event["stderr"].write("Could not find pull request")
+
+ def _get_info(self, target, ref):
+ username, repository, number = self._parse_ref(target, ref)
+ page = self._get_issue(username, repository, number)
+ if page and page.code == 200:
+ if "pull_request" in page.data:
+ pull = self._get_pull(username, repository, number)
+ return self._parse_pull(pull, username, repository, number)
+ else:
+ return self._parse_issue(page, username, repository, number)
+ else:
+ return None
+
+ @utils.hook("received.command.gh", alias_of="github")
+ @utils.hook("received.command.github", min_args=1)
+ def github(self, event):
+ if event["target"].get_setting("github-hide-prefix", False):
+ event["stdout"].hide_prefix()
+ event["stderr"].hide_prefix()
+ result = self._get_info(event["target"], event["args_split"][0])
+ if not result == None:
+ event["stdout"].write(result)
+ else:
+ event["stderr"].write("Issue/PR not found")
+
+ def _cache_ref(self, ref):
+ return "auto-github-%s" % ref.lower()
+ def _auto_github_cooldown(self, channel, ref):
+ cooldown = channel.get_setting("auto-github-cooldown", None)
+ if not cooldown == None:
+ cache = self._cache_ref(ref)
+ if not self.bot.cache.has_item(cache):
+ self.bot.cache.temporary_cache(cache, cooldown)
+ return True
+ else:
+ return False
+ else:
+ return True
+
+ @utils.hook("command.regex", ignore_action=False)
+ def url_regex(self, event):
+ """
+ :command: github
+ :pattern: https?://github.com/([^/]+)/([^/]+)/(pull|issues)/(\d+)
+ """
+ if event["target"].get_setting("auto-github", False):
+ event.eat()
+ ref = "%s/%s#%s" % (event["match"].group(1),
+ event["match"].group(2), event["match"].group(4))
+ if self._auto_github_cooldown(event["target"], ref):
+ try:
+ result = self._get_info(event["target"], ref)
+ except utils.EventError:
+ return
+ if result:
+ if event["target"].get_setting("github-hide-prefix", False):
+ event["stdout"].hide_prefix()
+ event["stdout"].write(result)
+
+ @utils.hook("command.regex", ignore_action=False)
+ def ref_regex(self, event):
+ """
+ :command: github
+ :pattern: (?:\S+(?:\/\S+)?)?#\d+
+ """
+ if event["target"].get_setting("auto-github", False):
+ event.eat()
+ ref = event["match"].group(0)
+ if self._auto_github_cooldown(event["target"], ref):
+ try:
+ result = self._get_info(event["target"],
+ event["match"].group(0))
+ except utils.EventError:
+ return
+ if result:
+ if event["target"].get_setting("github-hide-prefix", False):
+ event["stdout"].hide_prefix()
+ event["stdout"].write(result)
diff --git a/modules/github/ghwebhook.md b/modules/github/ghwebhook.md
deleted file mode 100644
index f533cc81..00000000
--- a/modules/github/ghwebhook.md
+++ /dev/null
@@ -1,53 +0,0 @@
-# !ghwebhook
-
-## List registered web hooks
-`!ghwebhook list`
-
-## Adding a web hook
-
-`!ghwebhook add [name]` where `[name]` is either a full repository name (e.g. `jesopo/bitbot`) to get a specific repository or a user/organisation name (e.g. `jesopo`) to get all repositories for that user/organisation
-
-## Removing a web hook
-Same as above but with `remove` instead of `add`
-
-## Modifying shown events
-`!ghwebhook events [hook] [events]` where `[hook]` is the `[name]` used in the `add` command and where `[events]` is a space-separated list of either raw events (see [here](https://developer.github.com/v3/activity/events/types/)) or the following (default: "ping code pr issue repo")
-
-#### ping
-Shows when a newly registered web hook first hits BitBot
-
-#### code
-Shows for commits and comments on commits
-
-#### pr-minimal
-Shows minimal pull request actions; opened, closed, reopened
-
-#### pr
-Shows the same actions as `pr-minimal` and also: edited, assigned, unassigned, review requests, comments on review requests
-
-#### pr-all
-Shows the same actions as `pr` and also: labeled, unlabeled, new commits
-
-#### issue-minimal
-Shows minimal issue actions; opened, closed, reopened, deleted
-
-#### issue
-Shows the same actions as `issue-minimal` and also: edited, assigned, unassigned, comments on issues
-
-#### issue-all
-Shows the same actions as `issue` and also: transferred, pinned, unpinned, labeled, unlabeled, milestoned, demilestoned
-
-#### repo
-Shows events related repositories themselves; repository/branch/tag created, repository/branch/tag deleted, release created, fork created
-
-#### team
-Shows when users are added or removed from teams
-
-## List shown events
-`!ghwebhook events [hook]`
-
-## Modify shown branches
-`!ghwebhook branches [hook] [branches]` where `[hook]` is the `[name]` used in the `add` command and where `[branches]` is a space-separated list of branch names
-
-## List shown branches
-`!ghwebhook branches [hook]`
diff --git a/modules/webhooks/__init__.py b/modules/webhooks/__init__.py
new file mode 100644
index 00000000..5b840470
--- /dev/null
+++ b/modules/webhooks/__init__.py
@@ -0,0 +1,190 @@
+from src import ModuleManager, utils
+from . import github
+
+@utils.export("channelset", {"setting": "git-prevent-highlight",
+ "help": "Enable/disable preventing highlights",
+ "validate": utils.bool_or_none, "example": "on"})
+@utils.export("channelset", {"setting": "git-hide-organisation",
+ "help": "Hide/show organisation in repository names",
+ "validate": utils.bool_or_none, "example": "on"})
+@utils.export("channelset", {"setting": "git-hide-prefix",
+ "help": "Hide/show command-like prefix on git webhook outputs",
+ "validate": utils.bool_or_none, "example": "on"})
+class Module(ModuleManager.BaseModule):
+ def on_load(self):
+ self._github = github.GitHub()
+
+ @utils.hook("api.post.github")
+ def github_webhook(self, event):
+ return self._webhook("github", "GitHub", self._github,
+ event["data"], event["headers"])
+
+ def _webhook(self, webhook_type, webhook_name, handler, payload_str,
+ headers):
+ payload = event["data"].decode("utf8")
+ if event["headers"]["Content-Type"] == FORM_ENCODED:
+ payload = urllib.parse.unquote(urllib.parse.parse_qs(payload)[
+ "payload"][0])
+ data = json.loads(payload)
+
+ full_name, repo_username, report_name, organisation = handler.names(
+ data, headers)
+ branch = handler.branch(data, headers)
+ event, event_action = handler.event(data, headers)
+
+ hooks = self.bot.database.channel_settings.find_by_setting(
+ "%s-hooks" % webhook_type)
+
+ targets = []
+ repo_hooked = False
+
+ for server_id, channel_name, hooked_repos in hooks:
+ found_hook = None
+ if full_name and full_name in hooked_repos:
+ found_hook = hooked_repos[full_name]
+ elif repo_username and repo_username in hooked_repos:
+ found_hook = hooked_repos[repo_username]
+ elif organisation and organisation in hooked_repos:
+ found_hook = hooked_repos[organisation]
+
+ repo_hooked = True
+ server = self.bot.get_server_by_id(server_id)
+ if server and channel_name in server.channels:
+ if (branch and
+ found_hook["branches"] and
+ not branch in found_hook["branches"]):
+ continue
+
+ events = []
+ for hooked_event in found_hook["events"]:
+ events.append(EVENT_CATEGORIES.get(hooked_event,
+ [hooked_event]))
+ events = list(itertools.chain(*events))
+
+ channel = server.channels.get(channel_name)
+ if (current_event in events or
+ (event_action and event_action in events)):
+ targets.append([server, channel])
+
+ if not targets:
+ if not repo_hooked:
+ return None
+ else:
+ return {"state": "success", "deliveries": 0}
+
+ outputs = handler.webhook(data, headers)
+
+ if outputs:
+ for server, channel in targets:
+ source = full_name or organisation
+ hide_org = channel.get_setting("git-hide-organisation", False)
+ if repo_name and hide_org:
+ source = repo_name
+
+ for output in outputs:
+ output = "(%s) %s" % (
+ utils.irc.color(source, COLOR_REPO), output)
+
+ if channel.get_setting("git-prevent-highlight", False):
+ output = self._prevent_highlight(server, channel,
+ output)
+
+ hide_prefix = channel.get_setting("git-hide-prefix", False)
+ self.events.on("send.stdout").call(target=channel,
+ module_name=webhook_name, server=server, message=output,
+ hide_prefix=hide_prefix)
+
+ def _prevent_highlight(self, server, channel, s):
+ for user in channel.users:
+ if len(user.nickname) == 1:
+ # if we don't ignore 1-letter nicknames, the below while loop
+ # will fire indefininitely.
+ continue
+
+ regex = re.compile(r"(.)\b(%s)(%s)" % (
+ re.escape(user.nickname[0]), re.escape(user.nickname[1:])),
+ re.I)
+ s = regex.sub("\\1\\2\u200c\\3", s)
+
+ return s
+
+ @utils.hook("received.command.webhook", min_args=1, channel_only=True)
+ def github_webhook(self, event):
+ """
+ :help: Add/remove/modify a git webhook
+ :require_mode: high
+ :require_access: git-webhook
+ :permission: gitoverride
+ :usage: list
+ :usage: add <hook>
+ :usage: remove <hook>
+ :usage: events <hook> [category [category ...]]
+ :usage: branches <hook> [branch [branch ...]]
+ """
+ all_hooks = event["target"].get_setting("webhooks", {})
+ hook_name = None
+ existing_hook = None
+ if len(event["args_split"]) > 1:
+ hook_name = event["args_split"][1]
+ for existing_hook_name in all_hooks.keys():
+ if existing_hook_name.lower() == hook_name.lower():
+ existing_hook = existing_hook_name
+ break
+
+ success_message = None
+
+ subcommand = event["args_split"][0].lower()
+ if subcommand == "list":
+ event["stdout"].write("Registered web hooks: %s" %
+ ", ".join(all_hooks.keys()))
+ elif subcommand == "add":
+ if existing_hook:
+ raise utils.EventError("There's already a hook for %s" %
+ hook_name)
+
+ all_hooks[hook_name] = {
+ "events": DEFAULT_EVENT_CATEGORIES.copy(),
+ "branches": [],
+ }
+ success_message = "Added hook for %s" % hook_name
+
+ elif subcommand == "remove":
+ if not existing_hook:
+ raise utils.EventError("No hook found for %s" % hook_name)
+
+ del all_hooks[existing_hook]
+ success_message = "Removed hook for %s" % hook_name
+
+ elif subcommand == "events":
+ if not existing_hook:
+ raise utils.EventError("No hook found for %s" % hook_name)
+
+ if len(event["args_split"]) < 3:
+ event["stdout"].write("Events for hook %s: %s" %
+ (hook_name, " ".join(all_hooks[existing_hook]["events"])))
+ else:
+ new_events = [e.lower() for e in event["args_split"][2:]]
+ all_hooks[existing_hook]["events"] = new_events
+ sucess_message = "Updated events for hook %s" % hook_name
+ elif subcommand == "branches":
+ if not existing_hook:
+ raise utils.EventError("No hook found for %s" % hook_name)
+
+ if len(event["args_split"]) < 3:
+ branches = ",".join(all_hooks[existing_hook]["branches"])
+ event["stdout"].write("Branches shown for hook %s: %s" %
+ (hook_name, branches))
+ else:
+ all_hooks[existing_hook]["branches"] = event["args_split"][2:]
+ success_message = "Updated branches for hook %s" % hook_name
+ else:
+ event["stderr"].write("Unknown command '%s'" %
+ event["args_split"][0])
+
+ if not success_message == None:
+ if all_hooks:
+ event["target"].set_setting("webhooks", all_hooks)
+ else:
+ event["target"].del_setting("webhooks")
+
+ event["stdout"].write(success_message)
diff --git a/modules/github/__init__.py b/modules/webhooks/github.py
index 46106a91..42587da1 100644
--- a/modules/github/__init__.py
+++ b/modules/webhooks/github.py
@@ -1,19 +1,5 @@
-#--depends-on channel_access
-#--depends-on check_mode
-#--depends-on commands
-#--depends-on config
-#--depends-on permissions
-#--depends-on rest_api
-
-import datetime, itertools, json, math, re, urllib.parse
-from src import EventManager, ModuleManager, utils
-
-COLOR_BRANCH = utils.consts.ORANGE
-COLOR_REPO = utils.consts.GREY
-COLOR_POSITIVE = utils.consts.GREEN
-COLOR_NEUTRAL = utils.consts.LIGHTGREY
-COLOR_NEGATIVE = utils.consts.RED
-COLOR_ID = utils.consts.PINK
+#--depends-on-github
+from src import ModuleManager, utils
FORM_ENCODED = "application/x-www-form-urlencoded"
@@ -21,9 +7,6 @@ COMMIT_URL = "https://github.com/%s/commit/%s"
COMMIT_RANGE_URL = "https://github.com/%s/compare/%s...%s"
CREATE_URL = "https://github.com/%s/tree/%s"
-API_ISSUE_URL = "https://api.github.com/repos/%s/%s/issues/%s"
-API_PULL_URL = "https://api.github.com/repos/%s/%s/pulls/%s"
-
DEFAULT_EVENT_CATEGORIES = [
"ping", "code", "pr", "issue", "repo"
]
@@ -98,289 +81,34 @@ CHECK_RUN_CONCLUSION = {
}
CHECK_RUN_FAILURES = ["failure", "cancelled", "timed_out", "action_required"]
-@utils.export("channelset", {"setting": "github-hide-prefix",
- "help": "Hide/show command-like prefix on Github hook outputs",
- "validate": utils.bool_or_none, "example": "on"})
-@utils.export("channelset", {"setting": "github-hide-organisation",
- "help": "Hide/show organisation in repository names",
- "validate": utils.bool_or_none, "example": "on"})
-@utils.export("channelset", {"setting": "github-default-repo",
- "help": "Set the default github repo for the current channel",
- "example": "jesopo/bitbot"})
-@utils.export("channelset", {"setting": "github-prevent-highlight",
- "help": "Enable/disable preventing highlights",
- "validate": utils.bool_or_none, "example": "on"})
-@utils.export("channelset", {"setting": "auto-github",
- "help": "Enable/disable automatically getting github issue/PR info",
- "validate": utils.bool_or_none, "example": "on"})
-@utils.export("channelset", {"setting": "auto-github-cooldown",
- "help": "Set amount of seconds between auto-github duplicates",
- "validate": utils.int_or_none, "example": "300"})
-class Module(ModuleManager.BaseModule):
- def _parse_ref(self, channel, ref):
- repo, _, number = ref.rpartition("#")
- org, _, repo = repo.partition("/")
-
- default_repo = channel.get_setting("github-default-repo", "")
- default_org, _, default_repo = default_repo.partition("/")
-
- if org and not repo:
- repo = org or default_repo
- org = default_org
- else:
- org = org or default_org
- repo = repo or default_repo
-
- if not org or not repo or not number:
- raise utils.EventError("Please provide username/repo#number")
- if not number.isdigit():
- raise utils.EventError("Issue number must be a number")
- return org, repo, number
-
- def _parse_issue(self, page, username, repository, number):
- repo = utils.irc.color("%s/%s" % (username, repository), COLOR_REPO)
- number = utils.irc.color("#%s" % number, COLOR_ID)
- labels = [label["name"] for label in page.data["labels"]]
- labels_str = ""
- if labels:
- labels_str = "[%s] " % ", ".join(labels)
-
- url = self._short_url(page.data["html_url"])
-
- state = page.data["state"]
- if state == "open":
- state = utils.irc.color("open", COLOR_NEUTRAL)
- elif state == "closed":
- state = utils.irc.color("closed", COLOR_NEGATIVE)
-
- return "(%s issue%s, %s) %s %s%s" % (
- repo, number, state, page.data["title"], labels_str, url)
- def _get_issue(self, username, repository, number):
- return utils.http.request(
- API_ISSUE_URL % (username, repository, number),
- json=True)
-
- @utils.hook("received.command.ghissue", min_args=1)
- def github_issue(self, event):
- if event["target"].get_setting("github-hide-prefix", False):
- event["stdout"].hide_prefix()
- event["stderr"].hide_prefix()
-
- username, repository, number = self._parse_ref(
- event["target"], event["args_split"][0])
-
- page = self._get_issue(username, repository, number)
- if page and page.code == 200:
- self._parse_issue(page, username, repository, number)
- else:
- event["stderr"].write("Could not find issue")
-
- def _parse_pull(self, page, username, repository, number):
- repo = utils.irc.color("%s/%s" % (username, repository), COLOR_REPO)
- number = utils.irc.color("#%s" % number, COLOR_ID)
- branch_from = page.data["head"]["label"]
- branch_to = page.data["base"]["label"]
- added = self._added(page.data["additions"])
- removed = self._removed(page.data["deletions"])
- url = self._short_url(page.data["html_url"])
-
- state = page.data["state"]
- if page.data["merged"]:
- state = utils.irc.color("merged", COLOR_POSITIVE)
- elif state == "open":
- state = utils.irc.color("open", COLOR_NEUTRAL)
- elif state == "closed":
- state = utils.irc.color("closed", COLOR_NEGATIVE)
-
- return "(%s PR%s, %s) %s → %s [%s/%s] %s %s" % (
- repo, number, state, branch_from, branch_to, added, removed,
- page.data["title"], url)
- def _get_pull(self, username, repository, number):
- return utils.http.request(
- API_PULL_URL % (username, repository, number),
- json=True)
- @utils.hook("received.command.ghpull", min_args=1)
- def github_pull(self, event):
- if event["target"].get_setting("github-hide-prefix", False):
- event["stdout"].hide_prefix()
- event["stderr"].hide_prefix()
-
- username, repository, number = self._parse_ref(
- event["target"], event["args_split"][0])
- page = self._get_pull(username, repository, number)
-
- if page and page.code == 200:
- self._parse_pull(page, username, repository, number)
- else:
- event["stderr"].write("Could not find pull request")
-
- def _get_info(self, target, ref):
- username, repository, number = self._parse_ref(target, ref)
- page = self._get_issue(username, repository, number)
- if page and page.code == 200:
- if "pull_request" in page.data:
- pull = self._get_pull(username, repository, number)
- return self._parse_pull(pull, username, repository, number)
- else:
- return self._parse_issue(page, username, repository, number)
- else:
- return None
-
- @utils.hook("received.command.gh", alias_of="github")
- @utils.hook("received.command.github", min_args=1)
- def github(self, event):
- if event["target"].get_setting("github-hide-prefix", False):
- event["stdout"].hide_prefix()
- event["stderr"].hide_prefix()
- result = self._get_info(event["target"], event["args_split"][0])
- if not result == None:
- event["stdout"].write(result)
- else:
- event["stderr"].write("Issue/PR not found")
-
- def _cache_ref(self, ref):
- return "auto-github-%s" % ref.lower()
- def _auto_github_cooldown(self, channel, ref):
- cooldown = channel.get_setting("auto-github-cooldown", None)
- if not cooldown == None:
- cache = self._cache_ref(ref)
- if not self.bot.cache.has_item(cache):
- self.bot.cache.temporary_cache(cache, cooldown)
- return True
- else:
- return False
- else:
- return True
-
- @utils.hook("command.regex", ignore_action=False)
- def url_regex(self, event):
- """
- :command: github
- :pattern: https?://github.com/([^/]+)/([^/]+)/(pull|issues)/(\d+)
- """
- if event["target"].get_setting("auto-github", False):
- event.eat()
- ref = "%s/%s#%s" % (event["match"].group(1),
- event["match"].group(2), event["match"].group(4))
- if self._auto_github_cooldown(event["target"], ref):
- try:
- result = self._get_info(event["target"], ref)
- except utils.EventError:
- return
- if result:
- if event["target"].get_setting("github-hide-prefix", False):
- event["stdout"].hide_prefix()
- event["stdout"].write(result)
-
- @utils.hook("command.regex", ignore_action=False)
- def ref_regex(self, event):
- """
- :command: github
- :pattern: (?:\S+(?:\/\S+)?)?#\d+
- """
- if event["target"].get_setting("auto-github", False):
- event.eat()
- ref = event["match"].group(0)
- if self._auto_github_cooldown(event["target"], ref):
- try:
- result = self._get_info(event["target"],
- event["match"].group(0))
- except utils.EventError:
- return
- if result:
- if event["target"].get_setting("github-hide-prefix", False):
- event["stdout"].hide_prefix()
- event["stdout"].write(result)
-
- @utils.hook("received.command.ghwebhook", min_args=1, channel_only=True)
- def github_webhook(self, event):
- """
- :help: Add/remove/modify a github webhook
- :require_mode: high
- :require_access: github-webhook
- :permission: githuboverride
- :usage: list
- :usage: add <hook>
- :usage: remove <hook>
- :usage: events <hook> [category [category ...]]
- :usage: branches <hook> [branch [branch ...]]
- """
- all_hooks = event["target"].get_setting("github-hooks", {})
- hook_name = None
- existing_hook = None
- if len(event["args_split"]) > 1:
- hook_name = event["args_split"][1]
- for existing_hook_name in all_hooks.keys():
- if existing_hook_name.lower() == hook_name.lower():
- existing_hook = existing_hook_name
- break
-
- subcommand = event["args_split"][0].lower()
- if subcommand == "list":
- event["stdout"].write("Registered web hooks: %s" %
- ", ".join(all_hooks.keys()))
- elif subcommand == "add":
- if existing_hook:
- event["stderr"].write("There's already a hook for %s" %
- hook_name)
- return
-
- all_hooks[hook_name] = {
- "events": DEFAULT_EVENT_CATEGORIES.copy(),
- "branches": []
- }
- event["target"].set_setting("github-hooks", all_hooks)
- event["stdout"].write("Added hook for %s" % hook_name)
- elif subcommand == "remove":
- if not existing_hook:
- event["stderr"].write("No hook found for %s" % hook_name)
- return
- del all_hooks[existing_hook]
- if all_hooks:
- event["target"].set_setting("github-hooks", all_hooks)
- else:
- event["target"].del_setting("github-hooks")
- event["stdout"].write("Removed hook for %s" % hook_name)
- elif subcommand == "events":
- if not existing_hook:
- event["stderr"].write("No hook found for %s" % hook_name)
- return
+class GitHub(object):
+ def names(self, data, headers):
+ full_name = None
+ repo_username = None
+ repo_name = None
+ if "repository" in data:
+ full_name = data["repository"]["full_name"]
+ repo_username, repo_name = full_name.split("/", 1)
- if len(event["args_split"]) < 3:
- event["stdout"].write("Events for hook %s: %s" %
- (hook_name, " ".join(all_hooks[existing_hook]["events"])))
- else:
- new_events = [e.lower() for e in event["args_split"][2:]]
- all_hooks[existing_hook]["events"] = new_events
- event["target"].set_setting("github-hooks", all_hooks)
- event["stdout"].write("Updated events for hook %s" % hook_name)
- elif subcommand == "branches":
- if not existing_hook:
- event["stderr"].write("No hook found for %s" % hook_name)
- return
+ organisation = None
+ if "organization" in data:
+ organisation = data["organization"]["login"]
+ return full_name, repo_username, repo_name, oraganisation
- if len(event["args_split"]) < 3:
- branches = ",".join(all_hooks[existing_hook]["branches"])
- event["stdout"].write("Branches shown for hook %s: %s" %
- (hook_name, branches))
- else:
- all_hooks[existing_hook]["branches"] = event["args_split"][2:]
- event["target"].set_setting("github-hooks", all_hooks)
- event["stdout"].write("Updated shown branches for hook %s" %
- hook_name)
- else:
- event["stderr"].write("Unknown command '%s'" %
- event["args_split"][0])
+ def branch(self, data, headers):
+ if "ref" in data:
+ return data["ref"].rpartition("/")[2]
+ return None
- @utils.hook("api.post.github")
- def webhook(self, event):
- payload = event["data"].decode("utf8")
- if event["headers"]["Content-Type"] == FORM_ENCODED:
- payload = urllib.parse.unquote(urllib.parse.parse_qs(payload)[
- "payload"][0])
- data = json.loads(payload)
+ def event(self, data, headers):
+ event = headers["X-GitHub-Event"]
+ event_action = None
+ if "action" in data:
+ event_action = "%s/%s" % (event, data["action"])
+ return event, event_action
- github_event = event["headers"]["X-GitHub-Event"]
+ def webhook(self, data, headers):
+ github_event = headers["X-GitHub-Event"]
full_name = None
repo_username = None
@@ -472,30 +200,7 @@ class Module(ModuleManager.BaseModule):
outputs = self.membership(organisation, data)
elif github_event == "watch":
outputs = self.watch(data)
-
-
- if outputs:
- for server, channel in targets:
- source = full_name or organisation
- hide_org = channel.get_setting(
- "github-hide-organisation", False)
- if repo_name and hide_org:
- source = repo_name
-
- for output in outputs:
- output = "(%s) %s" % (
- utils.irc.color(source, COLOR_REPO), output)
-
- if channel.get_setting("github-prevent-highlight", False):
- output = self._prevent_highlight(server, channel,
- output)
-
- self.events.on("send.stdout").call(target=channel,
- module_name="Github", server=server, message=output,
- hide_prefix=channel.get_setting(
- "github-hide-prefix", False))
-
- return {"state": "success", "deliveries": len(targets)}
+ return outputs
def _prevent_highlight(self, server, channel, s):
for user in channel.users:
@@ -576,7 +281,6 @@ class Module(ModuleManager.BaseModule):
return outputs
-
def commit_comment(self, full_name, data):
action = data["action"]
commit = self._short_hash(data["comment"]["commit_id"])