-
-
Notifications
You must be signed in to change notification settings - Fork 12
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
10 changed files
with
277 additions
and
71 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
#! /usr/bin/env python | ||
|
||
import asyncio | ||
import os | ||
from octomachinery.github.api.tokens import GitHubOAuthToken | ||
from octomachinery.github.api.raw_client import RawGitHubAPI | ||
|
||
|
||
async def main(): | ||
access_token = GitHubOAuthToken(os.environ['GITHUB_TOKEN']) | ||
gh = RawGitHubAPI(access_token, user_agent='webknjaz') | ||
await gh.post( | ||
'/repos/mariatta/strange-relationship/issues', | ||
data={ | ||
'title': 'We got a problem', | ||
'body': 'Use more emoji!', | ||
}, | ||
) | ||
|
||
|
||
asyncio.run(main()) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,4 @@ | ||
"""GitHub App infra.""" | ||
|
||
#from .github import Application # noqa: F401 | ||
from .server.runner import run # noqa: F401 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,106 @@ | ||
# FIXME: is this even needed? | ||
from __future__ import annotations | ||
|
||
import logging | ||
from typing import Iterable, Optional, TYPE_CHECKING | ||
|
||
from aiohttp.web_runner import GracefulExit | ||
from anyio import run as run_until_complete | ||
import attr | ||
|
||
# pylint: disable=relative-beyond-top-level | ||
from ..app.server.machinery import run_forever | ||
|
||
# pylint: disable=relative-beyond-top-level | ||
from ..app.config import BotAppConfig | ||
|
||
# pylint: disable=relative-beyond-top-level | ||
from ..routing.default_router import WEBHOOK_EVENTS_ROUTER | ||
|
||
# pylint: disable=relative-beyond-top-level | ||
from ..utils.asynctools import auto_cleanup_aio_tasks | ||
|
||
if TYPE_CHECKING: | ||
# pylint: disable=relative-beyond-top-level | ||
from ..routing.abc import OctomachineryRouterBase | ||
|
||
|
||
logger = logging.getLogger(__name__) | ||
|
||
|
||
# server entity vs client-holding object? | ||
@attr.s | ||
class GitHubApplication: # server-only? | ||
# GitHubEventsReceiver? | ||
# GitHubAppsContainer? | ||
# OctomachineryApplication? | ||
_event_routers: Iterable[OctomachineryRouterBase] = attr.ib( | ||
default={WEBHOOK_EVENTS_ROUTER}, | ||
converter=frozenset, | ||
) | ||
_config: Optional[BotAppConfig] = attr.ib( | ||
default=None, | ||
) | ||
|
||
@auto_cleanup_aio_tasks | ||
async def serve_forever(self): | ||
"""Spawn an HTTP server in an async context.""" | ||
return await run_forever(self._config, self._event_routers) | ||
accept_webhooks = serve_forever | ||
|
||
@classmethod | ||
def run_simple( # FIXME: | ||
cls, | ||
*, | ||
name: Optional[str] = None, | ||
version: Optional[str] = None, | ||
url: Optional[str] = None, | ||
config: Optional[BotAppConfig] = None, | ||
event_routers: Optional[Iterable[OctomachineryRouterBase]] = None, | ||
): | ||
"""Start up a server.""" | ||
if ( | ||
config is not None and | ||
(name is not None or version is not None or url is not None) | ||
): | ||
raise TypeError( | ||
f'{cls.__name__}.run_simple() takes name, ' | ||
'version and url arguments only if ' | ||
'the config is not provided.', | ||
) | ||
if config is None: | ||
config = BotAppConfig.from_dotenv( | ||
app_name=name, | ||
app_version=version, | ||
app_url=url, | ||
) | ||
|
||
logging.basicConfig( | ||
level=logging.DEBUG | ||
if config.runtime.debug # pylint: disable=no-member | ||
else logging.INFO, | ||
) | ||
if config.runtime.debug: # pylint: disable=no-member | ||
logger.debug( | ||
' App version: %s '.center(50, '='), | ||
config.github.app_version, | ||
) | ||
|
||
cls_kwargs = {'config': config} | ||
if event_routers is not None: | ||
cls_kwargs['event_routers'] = event_routers | ||
|
||
cls(**cls_kwargs).start() | ||
|
||
def start(self): | ||
try: | ||
run_until_complete(self.serve_forever) | ||
except (GracefulExit, KeyboardInterrupt): | ||
logger.info(' Exiting the app '.center(50, '=')) | ||
|
||
block = start | ||
|
||
#@classmethod | ||
#run??serve_forever w/ anyio? like app.server.runner | ||
|
||
#also need an instance method too |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,73 +1,6 @@ | ||
"""Octomachinery CLI runner.""" | ||
|
||
import logging | ||
import sys | ||
from typing import Iterable, Optional | ||
from ..github import GitHubApplication as _GitHubApplication | ||
|
||
from aiohttp.web_runner import GracefulExit | ||
from anyio import run as run_until_complete | ||
|
||
import attr | ||
|
||
# pylint: disable=relative-beyond-top-level | ||
from ..config import BotAppConfig | ||
# pylint: disable=relative-beyond-top-level | ||
from ..routing import WEBHOOK_EVENTS_ROUTER | ||
# pylint: disable=relative-beyond-top-level | ||
from ..routing.abc import OctomachineryRouterBase | ||
# pylint: disable=relative-beyond-top-level | ||
from .config import WebServerConfig | ||
# pylint: disable=relative-beyond-top-level | ||
from .machinery import run_forever as run_server_forever | ||
|
||
|
||
logger = logging.getLogger(__name__) | ||
|
||
|
||
def run( | ||
*, | ||
name: Optional[str] = None, | ||
version: Optional[str] = None, | ||
url: Optional[str] = None, | ||
config: Optional[BotAppConfig] = None, | ||
event_routers: Optional[Iterable[OctomachineryRouterBase]] = None, | ||
): | ||
"""Start up a server using CLI args for host and port.""" | ||
if event_routers is None: | ||
event_routers = {WEBHOOK_EVENTS_ROUTER} | ||
|
||
if ( | ||
config is not None and | ||
(name is not None or version is not None or url is not None) | ||
): | ||
raise TypeError( | ||
'run() takes either a BotAppConfig instance as a config argument ' | ||
'or name, version and url arguments.', | ||
) | ||
if config is None: | ||
config = BotAppConfig.from_dotenv( | ||
app_name=name, | ||
app_version=version, | ||
app_url=url, | ||
) | ||
if len(sys.argv) > 2: | ||
config = attr.evolve( # type: ignore[misc] | ||
config, | ||
server=WebServerConfig(*sys.argv[1:3]), | ||
) | ||
|
||
logging.basicConfig( | ||
level=logging.DEBUG | ||
if config.runtime.debug # pylint: disable=no-member | ||
else logging.INFO, | ||
) | ||
if config.runtime.debug: # pylint: disable=no-member | ||
logger.debug( | ||
' App version: %s '.center(50, '='), | ||
config.github.app_version, | ||
) | ||
|
||
try: | ||
run_until_complete(run_server_forever, config, event_routers) | ||
except (GracefulExit, KeyboardInterrupt): | ||
logger.info(' Exiting the app '.center(50, '=')) | ||
run = _GitHubApplication.run_simple |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
--- | ||
# This needs to be a sequence of mappings; | ||
# it cannot be just a mapping because headers | ||
# may occur multiple times | ||
- Content-Type: application/json | ||
- X-GitHub-Delivery: 2791443c-641a-40fa-836d-031a26f0d45f | ||
- X-GitHub-Event: ping | ||
--- | ||
{ | ||
"hook": {"app_id": 0}, | ||
"hook_id": 0, | ||
"zen": "Hey zen!" | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
"""Ping event handler.""" | ||
print(f'{__file__} imported') | ||
import logging | ||
|
||
from octomachinery.app.routing import process_event | ||
from octomachinery.app.routing import WEBHOOK_EVENTS_ROUTER | ||
from octomachinery.app.routing.decorators import process_webhook_payload | ||
from octomachinery.app.runtime.context import RUNTIME_CONTEXT | ||
|
||
|
||
logging.basicConfig() | ||
logger = logging.getLogger(__name__) | ||
logger.setLevel(logging.DEBUG) | ||
|
||
|
||
@process_event('ping') | ||
@process_webhook_payload | ||
async def on_ping(*, hook, hook_id, zen): | ||
"""React to ping webhook event.""" | ||
print('got ping') | ||
app_id = hook['app_id'] | ||
|
||
logger.info( | ||
'Processing ping for App ID %s ' | ||
'with Hook ID %s ' | ||
'sharing Zen: %s', | ||
app_id, | ||
hook_id, | ||
zen, | ||
) | ||
|
||
logger.info( | ||
'Github App Wrapper from context in ping handler: %s', | ||
RUNTIME_CONTEXT.github_app, | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,53 @@ | ||
import asyncio | ||
import pathlib | ||
|
||
from aiohttp.client import ClientSession | ||
|
||
from octomachinery.github.api.app_client import GitHubApp | ||
from octomachinery.github.config.app import GitHubAppIntegrationConfig | ||
|
||
|
||
target_github_account_or_org = 'sanitizers' # where the app is installed to | ||
|
||
github_app_id = 28012 | ||
github_app_private_key_path = pathlib.Path( | ||
'~/Downloads/diactoros.2019-03-30.private-key.pem', | ||
).expanduser().resolve() | ||
|
||
github_app_config = GitHubAppIntegrationConfig( | ||
app_id=github_app_id, | ||
private_key=github_app_private_key_path.read_text(), | ||
|
||
app_name='MyGitHubClient', | ||
app_version='1.0', | ||
app_url='https://awesome-app.dev', | ||
) | ||
|
||
|
||
async def get_github_client(github_app, account): | ||
github_app_installations = await github_app.get_installations() | ||
target_github_app_installation = next( # find the one | ||
( | ||
i for n, i in github_app_installations.items() | ||
if i._metadata.account['login'] == account | ||
), | ||
None, | ||
) | ||
return target_github_app_installation.api_client | ||
|
||
|
||
async def main(): | ||
async with ClientSession() as http_session: | ||
github_app = GitHubApp(github_app_config, http_session) | ||
github_api = await get_github_client( | ||
github_app, target_github_account_or_org, | ||
) | ||
org = await github_api.getitem( | ||
'/orgs/{account_name}', | ||
url_vars={'account_name': target_github_account_or_org}, | ||
) | ||
print(f'Org found: {org["login"]}') | ||
print(f'Rate limit stats: {github_api.rate_limit!s}') | ||
|
||
|
||
asyncio.run(main()) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
from octomachinery.app.config import BotAppConfig | ||
from octomachinery.app.github import GitHubApplication | ||
from octomachinery.routing.routers import ConcurrentRouter | ||
|
||
|
||
router1 = ConcurrentRouter() # .on and other helpers? | ||
|
||
app1 = GitHubApplication( | ||
event_routers={router1}, | ||
config=BotAppConfig.from_dotenv(), | ||
) | ||
|
||
|
||
# process many events arriving over HTTP: | ||
__name__ == '__main__' and app1.start() | ||
# FIXME: use variants? | ||
# await app1.serve_forever() # ? == app1.start()? <- Probot | ||
|
||
# NOTE: Depending on whether the API is for external or internal use, | ||
# NOTE: its semantics may feel different. What for external caller is | ||
# NOTE: "send event into the system", for internals would be "dispatch/ | ||
# NOTE: handle the received event". | ||
# process a single event: | ||
# await app1.dispatch_event(event) # ? == await app1.receive(event) <- Probot | ||
# [BAD] await app1.simulate_event(event)? <-- tests? FIXME: have a pytest fixture called `simulate_event`? |