{ "cells": [ { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "#default_exp event" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# The events API\n", "\n", "> Helpers for getting GitHub API events" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "#export\n", "from fastcore.utils import *\n", "from fastcore.foundation import *\n", "from fastcore.meta import *\n", "from ghapi.core import *\n", "from ghapi.page import *\n", "from ghapi.actions import *\n", "\n", "import time,json,gzip\n", "from itertools import islice" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "#hide\n", "from nbdev.showdoc import show_doc\n", "from IPython.display import Markdown\n", "import matplotlib.pyplot as plt\n", "from collections import Counter" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "api = GhApi()" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "#export\n", "def _list_events(g, username=None, org=None, owner=None, repo=None):\n", " if (username or org or owner) and \\\n", " not (bool(username) ^ bool(org) ^ bool(owner)): raise Exception('Can not pass more than one of username, org, and owner')\n", " if (owner and not repo): owner,repo = repo.split('/')\n", " if owner: return g.list_public_events_for_repo_network,{'owner':owner,'repo':repo}\n", " if org: return g.list_public_org_events,{'org':org}\n", " if username: return g.list_public_events_for_user,{'username':username}\n", " return g.list_public_events,{}" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "#export\n", "def _id2int(x):\n", " x.id = int(x.id)\n", " return x" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "#export\n", "@patch\n", "@delegates(_list_events)\n", "def list_events(self:GhApi, per_page=30, page=1, **kwargs):\n", " \"Fetch public events for repo network, org, user, or all\"\n", " oper,kw = _list_events(self.activity, **kwargs)\n", " return oper(per_page=per_page, page=page, **kw).map(_id2int)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "#export\n", "@patch\n", "@delegates(_list_events)\n", "def list_events_parallel(self:GhApi, per_page=30, n_pages=8, **kwargs):\n", " \"Fetch as many events from `list_events` in parallel as available\"\n", " oper,kw = _list_events(self.activity, **kwargs)\n", " return pages(oper, n_pages, per_page=per_page, **kw).concat().map(_id2int)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "`list_events` and `list_events_parallel` support the following:\n", "\n", "|Events from|Example|\n", "|:-|:-|\n", "|Organization|`api.list_events_parallel(org='fastai')`\n", "|User|`api.list_events_parallel(username='jph00')`\n", "|Repository network|`api.list_events_parallel(owner='fastai', repo='fastcore')`\n", "|All public|`api.list_events_parallel()`" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "#export\n", "_bot_re = re.compile('b[o0]t')\n", "def _want_evt(o, types, incl_bot):\n", " if not incl_bot and _bot_re.search(nested_attr(o, 'actor.login') or ''): return False\n", " if types and o.type not in types: return False\n", " return True" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "#export\n", "class GhEvent(AttrDict):\n", " \"Class for events returned from `fetch_events\"\n", " pass\n", "\n", "for o in Event: exec(f'class {snake2camel(o)}Event(GhEvent):pass')" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [ { "data": { "text/markdown": [ "

class GhEvent[source]

\n", "\n", "> GhEvent() :: `AttrDict`\n", "\n", "Class for events returned from `fetch_events" ], "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "show_doc(GhEvent, title_level=4)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "['PageBuildEvent', 'ContentReferenceEvent', 'RepositoryImportEvent', 'CreateEvent', 'WorkflowRunEvent', 'DeleteEvent', 'OrganizationEvent', 'SponsorshipEvent', 'ProjectColumnEvent', 'PushEvent', 'ContextEvent', 'MilestoneEvent', 'ProjectCardEvent', 'ProjectEvent', 'PackageEvent', 'PullRequestEvent', 'RepositoryDispatchEvent', 'TeamAddEvent', 'WorkflowDispatchEvent', 'MemberEvent', 'MetaEvent', 'CodeScanningAlertEvent', 'PublicEvent', 'NeedsEvent', 'CheckRunEvent', 'SecurityAdvisoryEvent', 'PullRequestReviewCommentEvent', 'OrgBlockEvent', 'CommitCommentEvent', 'WatchEvent', 'MarketplacePurchaseEvent', 'StarEvent', 'InstallationRepositoriesEvent', 'CheckSuiteEvent', 'GithubAppAuthorizationEvent', 'TeamEvent', 'StatusEvent', 'RepositoryVulnerabilityAlertEvent', 'PullRequestReviewEvent', 'LabelEvent', 'InstallationEvent', 'ReleaseEvent', 'IssuesEvent', 'RepositoryEvent', 'GollumEvent', 'MembershipEvent', 'DeploymentEvent', 'DeployKeyEvent', 'IssueCommentEvent', 'PingEvent', 'DeploymentStatusEvent', 'ForkEvent', 'ScheduleEvent']\n" ] } ], "source": [ "print([snake2camel(o)+'Event' for o in Event])" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "#export\n", "_all_ = [\n", " 'PageBuildEvent', 'ContentReferenceEvent', 'RepositoryImportEvent', 'CreateEvent', 'WorkflowRunEvent', 'DeleteEvent', 'OrganizationEvent',\n", " 'SponsorshipEvent', 'ProjectColumnEvent', 'PushEvent', 'ContextEvent', 'MilestoneEvent', 'ProjectCardEvent', 'ProjectEvent', 'PackageEvent',\n", " 'PullRequestEvent', 'RepositoryDispatchEvent', 'TeamAddEvent', 'WorkflowDispatchEvent', 'MemberEvent', 'MetaEvent', 'CodeScanningAlertEvent',\n", " 'PublicEvent', 'NeedsEvent', 'CheckRunEvent', 'SecurityAdvisoryEvent', 'PullRequestReviewCommentEvent', 'OrgBlockEvent',\n", " 'CommitCommentEvent', 'WatchEvent', 'MarketplacePurchaseEvent', 'StarEvent', 'InstallationRepositoriesEvent', 'CheckSuiteEvent',\n", " 'GithubAppAuthorizationEvent', 'TeamEvent', 'StatusEvent', 'RepositoryVulnerabilityAlertEvent', 'PullRequestReviewEvent', 'LabelEvent',\n", " 'InstallationEvent', 'ReleaseEvent', 'IssuesEvent', 'RepositoryEvent', 'GollumEvent', 'MembershipEvent', 'DeploymentEvent', 'DeployKeyEvent',\n", " 'IssueCommentEvent', 'PingEvent', 'DeploymentStatusEvent', 'ForkEvent', 'ScheduleEvent']" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "#export\n", "def _cast_evt(o): return globals()[o.type](o)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "#export\n", "@patch\n", "@delegates(_list_events)\n", "def fetch_events(self:GhApi, n_pages=3, pause=0.4, per_page=30, types=None, incl_bot=False, **kwargs):\n", " \"Generate an infinite stream of events, optionally filtered to `types, with `pause` seconds between requests\"\n", " seen = set()\n", " if types: types=setify(types or None)\n", " g = globals()\n", " while True:\n", " evts = self.list_events_parallel(n_pages=n_pages, per_page=per_page, **kwargs)\n", " new_evts = L(_cast_evt(o) for o in evts if o.id not in seen and _want_evt(o, types, incl_bot))\n", " seen.update(new_evts.attrgot('id'))\n", " yield from new_evts\n", " if pause: time.sleep(pause)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "#export\n", "def load_sample_events():\n", " \"Load sample events, downloading if needed\"\n", " name = 'sample_evts.json.gz'\n", " url = f'https://raw.githubusercontent.com/fastai/ghapi/master/examples/{name}'\n", " try: path = Path(__file__).parent\n", " except NameError: path = Path()/'examples'\n", " path = path/name\n", " if not path.exists():path.write_bytes(urlread(url, decode=False))\n", " return dict2obj(json.load(open_file(path))).map(_cast_evt)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "#export\n", "def save_sample_events(n=5000):\n", " \"Save the most recent `n` events as compressed JSON\"\n", " evts = list(islice(api.fetch_events(incl_bot=True), n))\n", " with gzip.open('sample_evts.json.gz', 'wt') as f: json.dump(obj2dict(evts), f)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "#export\n", "#hide\n", "@patch(as_prop=True)\n", "def full_type(self:GhEvent):\n", " \"Concatenation of `type` and `payload.action` (if available)\"\n", " act = getattr(self.payload, 'action', '')\n", " return f'{self.type}_{act}' if act else self.type" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "5000 sample events (taken from a single recent period) are available, and are downloaded and cached by `load_sample_events`. `full_type` provides the combination of `type` and `payload.action` (where available) for each event. Here's the frequency of all `full_types` in the sample:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [ { "data": { "image/png": "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\n", "text/plain": [ "
" ] }, "metadata": { "needs_background": "light" }, "output_type": "display_data" } ], "source": [ "evts = load_sample_events()\n", "x,y = zip(*Counter([o.full_type for o in evts]).most_common())\n", "plt.figure(figsize=(8, 6))\n", "plt.barh(x,y);" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "#export\n", "_all_ = ['PageBuildEvent', 'ContentReferenceEvent', 'RepositoryImportEvent', 'CreateEvent', 'WorkflowRunEvent', 'DeleteEvent', 'OrganizationEvent', 'SponsorshipEvent', 'ProjectColumnEvent', 'PushEvent', 'ContextEvent', 'MilestoneEvent', 'ProjectCardEvent', 'ProjectEvent', 'PackageEvent', 'PullRequestEvent', 'RepositoryDispatchEvent', 'TeamAddEvent', 'WorkflowDispatchEvent', 'MemberEvent', 'MetaEvent', 'CodeScanningAlertEvent', 'PublicEvent', 'NeedsEvent', 'CheckRunEvent', 'SecurityAdvisoryEvent', 'PullRequestReviewCommentEvent', 'OrgBlockEvent', 'CommitCommentEvent', 'WatchEvent', 'MarketplacePurchaseEvent', 'StarEvent', 'InstallationRepositoriesEvent', 'CheckSuiteEvent', 'GithubAppAuthorizationEvent', 'TeamEvent', 'StatusEvent', 'RepositoryVulnerabilityAlertEvent', 'PullRequestReviewEvent', 'LabelEvent', 'InstallationEvent', 'ReleaseEvent', 'IssuesEvent', 'RepositoryEvent', 'GollumEvent', 'MembershipEvent', 'DeploymentEvent', 'DeployKeyEvent', 'IssueCommentEvent', 'PingEvent', 'DeploymentStatusEvent', 'ForkEvent', 'ScheduleEvent']" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "#export\n", "evt_emojis = dict(\n", " PushEvent= '⭐',\n", " CreateEvent= '🏭',\n", " IssueCommentEvent_created= 'πŸ’¬',\n", " WatchEvent_started= 'πŸ‘€',\n", " PullRequestEvent_closed= 'πŸ“ͺ',\n", " PullRequestReviewEvent_created= 'πŸ’Œ',\n", " PullRequestEvent_opened= 'πŸ“¬',\n", " PullRequestReviewCommentEvent_created= 'πŸ—¨',\n", " DeleteEvent= 'βœ‚',\n", " ForkEvent= '🍽',\n", " IssuesEvent_opened= 'πŸ›',\n", " IssuesEvent_closed= '🎁',\n", " ReleaseEvent_published= 'πŸš€',\n", " MemberEvent_added= 'πŸ’ƒ',\n", " CommitCommentEvent= 'πŸŽ‰',\n", " GollumEvent= 'πŸ“š',\n", " PublicEvent= 'β™₯',\n", " IssuesEvent_reopened= 'πŸ”',\n", " PullRequestEvent_reopened= 'πŸ”'\n", ")" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "#export\n", "def _ref(pay, pre=''): return f'{pre} \"{pay.ref.split(\"/\")[-1]}\"' if pay.ref else ''\n", "def _ref_detl(pay): return pay.ref_type + _ref(pay)\n", "\n", "def _action(self):\n", " pay = self.payload\n", " det = (f'issue #{pay.issue.number} on' if isinstance(self,IssuesEvent) else\n", " f'PR #{pay.number} on' if isinstance(self,PullRequestEvent) else\n", " f'member {pay.member.login} in' if isinstance(self,MemberEvent) else\n", " f'review comment on PR #{pay.pull_request.number} in' if isinstance(self,PullRequestReviewCommentEvent) else\n", " f'comment on issue #{pay.issue.number} in' if isinstance(self,IssueCommentEvent) else\n", " f'release {pay.release.tag_name} in' if isinstance(self,ReleaseEvent) else\n", " 'PR review in' if isinstance(self,PullRequestReviewEvent) else\n", " 'watching' if isinstance(self,WatchEvent) else '')\n", " if det: return f'{pay.action} {det}'" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "#export\n", "#hide\n", "@patch(as_prop=True)\n", "def description(self:GhEvent):\n", " \"Description of event\"\n", " act,pay,cls,repo = self.actor,self.payload,type(self),self.repo\n", " res = _action(self)\n", " return res if res else (\n", " f'deleted {_ref_detl(pay)} in' if isinstance(self,DeleteEvent) else\n", " f'created {_ref_detl(pay)} in' if isinstance(self,CreateEvent) else\n", " f'pushed {len(pay.commits)} commits{_ref(pay,\" to\")} in' if isinstance(self,PushEvent) else\n", " f'created commit comment in' if isinstance(self,CommitCommentEvent) else\n", " f'{pay.pages[0].action} wiki page in' if isinstance(self,GollumEvent) else\n", " f'forked' if isinstance(self,ForkEvent) else\n", " f'made public repo ' if isinstance(self,PublicEvent) else\n", " remove_suffix(self.type, \"Event\")\n", " )\n", "\n", "#export\n", "@patch(as_prop=True)\n", "def emoji(self:GhEvent):\n", " \"Emoji for event from `evt_emojis`\"\n", " return evt_emojis.get(self.full_type, '❌')" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "#export\n", "#hide\n", "described_evts = (PushEvent,CreateEvent,IssueCommentEvent,WatchEvent,PullRequestEvent,PullRequestReviewEvent,PullRequestReviewCommentEvent,\n", " DeleteEvent,ForkEvent,IssuesEvent,ReleaseEvent,MemberEvent,CommitCommentEvent,GollumEvent,PublicEvent)\n", "\n", "_text_keys = dict(\n", " CreateEvent = \"description\",\n", " PullRequestEvent = \"pull_request.title\",\n", " PullRequestReviewCommentEvent = \"comment.body\",\n", " ForkEvent = \"forkee.description\",\n", " CommitCommentEvent = \"comment.body\",\n", " PullRequestReviewEvent = \"review.body\",\n", " ReleaseEvent = \"release.body\",\n", " IssuesEvent = \"issue.title\",\n", " IssueCommentEvent = \"comment.body\"\n", ")\n", "\n", "@patch(as_prop=True)\n", "def text(self:GhEvent):\n", " \"Text (e.g. body or title) of event, if exists\"\n", " return nested_idx(self.payload, *_text_keys.get(self.type, '').split('.')) or ''" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "You can use the `description`, `text`, and `emoji` properties to display events, e.g:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [ { "data": { "text/markdown": [ "|Type|Description|\n", "|:--|:--|\n", "|Push|⭐ **fedya** pushed 1 commits to \"rolling\" in *OpenMandrivaAssociation/g…*|\n", "|Delete|βœ‚ **dependabot[bot]** deleted branch \"packit-0.5.0\" in *paketo-buildpacks/occam*|\n", "|Create|🏭 **github-classroom[bot]** created repository in *Introduction-to-Programming-OSOWSKI/…*: \"1-5-add-two-numbers-noraahlman23 created by GitHu…\"|\n", "|PR |πŸ“¬ **JerryMacedoCastro** opened PR #1 on *JerryMacedoCastro/tb-arquitetura-js*: \"Input component created\"|\n", "|Member|πŸ’ƒ **github-classroom[bot]** added member noraahlman23 in *Introduction-to-Programming-O…*|\n", "|Public|β™₯ **navikt** made public repo *navikt/syfoinntektsmelding*|\n", "|PR Review Comment|πŸ—¨ **fruttasecca** created review comment on PR #97 in *orchest/orchest*: \"Does this make it so that users coming from an ol…\"|\n", "|Fork|🍽 **amin-lotf** forked *vinaygaba/Learn-Jetpack-Compose-By-Example*: \"πŸš€ This project contains various examples that sho…\"|\n", "|Commit Comment|πŸŽ‰ **vercel[bot]** created commint comment in *Samaraferreira/test-frontend*: \"Successfully deployed to the following URLs: * […\"|\n", "|Watch|πŸ‘€ **ikarius** started watching *jorgebucaran/awsm.fish*|\n", "|PR Review|πŸ’Œ **fruttasecca** created PR review in *orchest/orchest*|\n", "|Release|πŸš€ **github-actions[bot]** published release v1.1.3 in *vouv/srun*|\n", "|Issues|πŸ› **efritz** opened issue #16915 on *sourcegraph/sourcegraph*: \"auto-indexing: Add docker/src-cli command wall cl…\"|\n", "|Gollum|πŸ“š **TradingToolCrypto** created wiki page in *TradingToolCrypto/TradingTool-Wiki*|\n", "|Issue Comment|πŸ’¬ **jerhard** created comment on issue #2570 in *ls1intum/Artemis*: \"Do you think that spaces (or even white space cha…\"|" ], "text/plain": [ "" ] }, "execution_count": null, "metadata": {}, "output_type": "execute_result" } ], "source": [ "exs = [first(evts, risinstance(o)) for o in described_evts]\n", "\n", "def _fmt_evt(o):\n", " res = f'{o.emoji} **{o.actor.login}** ' + truncstr(f'{o.description} *{o.repo.name}',60) + '*'\n", " if o.text: res += f': \"{truncstr(o.text, 50)}\"'\n", " return res.replace('\\n',' ')\n", "\n", "Markdown('|Type|Description|\\n|:--|:--|\\n' +\n", " '\\n'.join(f'|{camel2words(o.type.replace(\"PullRequest\",\"PR \")[:-5])}|{_fmt_evt(o)}|' for o in exs))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Export -" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Converted 00_core.ipynb.\n", "Converted 01_actions.ipynb.\n", "Converted 02_auth.ipynb.\n", "Converted 03_page.ipynb.\n", "Converted 04_event.ipynb.\n", "Converted 10_cli.ipynb.\n", "Converted 50_fullapi.ipynb.\n", "Converted 80_tutorial_actions.ipynb.\n", "Converted 90_build_lib.ipynb.\n", "Converted index.ipynb.\n" ] } ], "source": [ "#hide\n", "from nbdev.export import notebook2script\n", "notebook2script()" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [] } ], "metadata": { "kernelspec": { "display_name": "Python 3", "language": "python", "name": "python3" } }, "nbformat": 4, "nbformat_minor": 4 }