Ejemplo n.º 1
0
async def test_dispatching():
    router = routing.Router()
    event = sansio.Event({
        "action": "new",
        "count": 42
    },
                         event="nothing",
                         delivery_id="1234")
    await router.dispatch(event)  # Should raise no exceptions.

    shallow_registration = Callback()
    deep_registration_1 = Callback()
    deep_registration_2 = Callback()
    deep_registration_3 = Callback()
    never_called_1 = Callback()
    never_called_2 = Callback()
    never_called_3 = Callback()
    # Wrong event.
    router.add(never_called_1.meth, "something")
    # Wrong event and data detail.
    router.add(never_called_1.meth, "something", action="new")
    # Wrong data detail key.
    router.add(never_called_1.meth, "nothing", never=42)
    # Wrong data detail value.
    router.add(never_called_1.meth, "nothing", count=-13)
    await router.dispatch(event)
    assert not never_called_1.called

    router = routing.Router()
    router.add(shallow_registration.meth, "something")
    router.add(deep_registration_1.meth, "something", action="new")
    router.add(deep_registration_2.meth, "something", action="new")
    router.add(deep_registration_3.meth, "something", count=42)
    router.add(never_called_1.meth, "something else")
    router.add(never_called_2.meth, "something", never="called")
    router.add(never_called_3.meth, "something", count=-13)
    event = sansio.Event({
        "action": "new",
        "count": 42,
        "ignored": True
    },
                         event="something",
                         delivery_id="1234")
    await router.dispatch(event)
    assert shallow_registration.called
    assert deep_registration_1.called
    assert deep_registration_2.called
    assert deep_registration_3.called
    assert not never_called_1.called
    assert not never_called_2.called
    assert not never_called_3.called
Ejemplo n.º 2
0
async def test_router_copy():
    router = routing.Router()
    deep_callback = Callback()
    shallow_callback = Callback()
    router.add(deep_callback.meth, "something", extra=42)
    router.add(shallow_callback.meth, "something")
    event = sansio.Event({"extra": 42}, event="something", delivery_id="1234")
    await router.dispatch(event)
    assert deep_callback.called
    assert shallow_callback.called
    deep_callback.called = shallow_callback.called = False
    other_router = routing.Router(router)
    await other_router.dispatch(event)
    assert deep_callback.called
    assert shallow_callback.called
Ejemplo n.º 3
0
async def test_shallow_callback():
    router = routing.Router()
    callback = Callback()
    router.add(callback.meth, "pull_request")
    event = sansio.Event({}, event="pull_request", delivery_id="1234")
    await router.dispatch(event)
    assert callback.called
    assert callback.event == event
Ejemplo n.º 4
0
async def test_deep_callback():
    router = routing.Router()
    callback = Callback()
    router.add(callback.meth, "pull_request", data=42)
    event = sansio.Event({"data": 42}, event="pull_request", delivery_id="1234")
    await router.dispatch(event)
    assert callback.called
    assert callback.event == event
    assert not callback.args
    assert not callback.kwargs
Ejemplo n.º 5
0
async def test_register():
    router = routing.Router()
    called = False

    @router.register("pull_request", action="new")
    async def callback(event):
        nonlocal called
        called = True

    event = sansio.Event({"action": "new"}, event="pull_request", delivery_id="1234")
    await router.dispatch(event)
    assert called
Ejemplo n.º 6
0
async def test_shallow_callback():
    router = routing.Router()
    callback = Callback()
    router.add(callback.meth, "pull_request")
    event = sansio.Event({}, event="pull_request", delivery_id="1234")
    await router.dispatch(event)
    assert callback.called
    assert callback.event == event
    assert not callback.args
    assert not callback.kwargs
    await router.dispatch(event, 42, hello="world")
    assert callback.args == (42, )
    assert callback.kwargs == {"hello": "world"}
Ejemplo n.º 7
0
    async def configure(self, config, router, session):
        logger.debug('Configuring github plugin')

        self._verification = os.environ.get('SIRBOT_GITHUB_SECRET')
        if not self._verification:
            raise GitHubSetupError('SIRBOT_GITHUB_SECRET NOT SET')

        path = os.path.join(os.path.dirname(os.path.abspath(__file__)), '..',
                            'config.yml')

        with open(path) as file:
            defaultconfig = yaml.load(file)

        self._config = merge_dict(config, defaultconfig[self.__name__])
        self._session = session
        self._http_router = router
        self._github_router = routing.Router()

        logger.debug('Adding github endpoint: %s', self._config['endpoint'])
        self._http_router.add_route('POST', self._config['endpoint'],
                                    self._dispatch)

        self._started = True
Ejemplo n.º 8
0
import asyncio
import datetime
import os
from typing import Any

import aiohttp
import cachetools
from aiohttp import web
from gidgethub import routing
from gidgethub.sansio import Event

from . import check_runs, installations, issues, pull_requests
from .api import GitHubAPI
from .log import CustomAccessLogger, logger

router = routing.Router(check_runs.router, installations.router, issues.router,
                        pull_requests.router)

cache = cachetools.LRUCache(maxsize=500)  # type: cachetools.LRUCache[Any, Any]


async def main(request: web.Request) -> web.Response:
    try:
        body = await request.read()
        secret = os.environ.get("GITHUB_SECRET")
        event = Event.from_http(request.headers, body, secret=secret)
        if event.event == "ping":
            return web.Response(status=200)
        logger.info(
            "event=%(event)s delivery_id=%(delivery_id)s",
            {
                "event": f"{event.event}:{event.data['action']}",
Ejemplo n.º 9
0
import logging
from typing import Any

from gidgethub import routing
from gidgethub.sansio import Event

from algorithms_keeper import utils
from algorithms_keeper.api import GitHubAPI
from algorithms_keeper.constants import EMPTY_ISSUE_BODY_COMMENT, Label

issues_router = routing.Router()

logger = logging.getLogger(__package__)


@issues_router.register("issues", action="opened")
async def close_invalid_issue(event: Event, gh: GitHubAPI, *args: Any,
                              **kwargs: Any) -> None:
    """Close an invalid issue.

    An issue is considered invalid if:
    - It doesn't contain any description.
    """
    issue = event.data["issue"]

    if not issue["body"]:
        logger.info("Empty issue body: %s", issue["html_url"])
        await utils.close_pr_or_issue(
            gh,
            comment=EMPTY_ISSUE_BODY_COMMENT.format(
                user_login=issue["user"]["login"]),
Ejemplo n.º 10
0
import asyncio
import os
import sys
import traceback

import aiohttp
from aiohttp import web
import cachetools
from gidgethub import aiohttp as gh_aiohttp
from gidgethub import routing
from gidgethub import sansio

from . import black_out


router = routing.Router(black_out.router)
cache = cachetools.LRUCache(maxsize=500)


async def main(request):
    try:
        body = await request.read()
        secret = os.environ.get("GH_SECRET")
        event = sansio.Event.from_http(request.headers, body, secret=secret)
        print("GH delivery ID", event.delivery_id, file=sys.stderr)
        if event.event == "ping":
            return web.Response(status=200)
        oauth_token = os.environ.get("GH_AUTH")
        async with aiohttp.ClientSession() as session:
            gh = gh_aiohttp.GitHubAPI(
                session,
Ejemplo n.º 11
0
import logging
from typing import Any

from gidgethub import routing
from gidgethub.sansio import Event

from algorithms_keeper.api import GitHubAPI
from algorithms_keeper.constants import GREETING_COMMENT

installation_router = routing.Router()

logger = logging.getLogger(__package__)


@installation_router.register("installation", action="created")
@installation_router.register("installation_repositories", action="added")
async def repo_installation_added(event: Event, gh: GitHubAPI, *args: Any,
                                  **kwargs: Any) -> None:
    """Give the repository a heads up that the app has been installed.

    This callback will be triggered by two events:
    1. When a new installation for this app is added
    2. When a new repository is added in an existing installation
    """
    try:
        repositories = event.data["repositories"]
    except KeyError:
        repositories = event.data["repositories_added"]

    for repository in repositories:
        repo_name = repository["full_name"]
Ejemplo n.º 12
0
import asyncio
import importlib
import os
import sys
import traceback

import aiohttp
from aiohttp import web
import cachetools
from gidgethub import aiohttp as gh_aiohttp
from gidgethub import routing
from gidgethub import sansio

from . import backport, bpo

router = routing.Router(backport.router, bpo.router)
cache = cachetools.LRUCache(maxsize=500)


async def main(request):
    try:
        body = await request.read()
        secret = os.environ.get("GH_SECRET")
        event = sansio.Event.from_http(request.headers, body, secret=secret)
        print('GH delivery ID', event.delivery_id, file=sys.stderr)
        if event.event == "ping":
            return web.Response(status=200)
        oauth_token = os.environ.get("GH_AUTH")
        with aiohttp.ClientSession() as session:
            gh = gh_aiohttp.GitHubAPI(session,
                                      "python/bedevere",
Ejemplo n.º 13
0
import os
import sys
import traceback
import cachetools

from aiohttp import web

from gidgethub import aiohttp as gh_aiohttp
from gidgethub import routing
from gidgethub import sansio

from . import backport_pr
from . import delete_branch
from . import status_change

router = routing.Router(backport_pr.router, delete_branch.router,
                        status_change.router)

cache = cachetools.LRUCache(maxsize=500)


async def main(request):
    try:
        body = await request.read()

        secret = os.environ.get("GH_SECRET")
        event = sansio.Event.from_http(request.headers, body, secret=secret)
        print('GH delivery ID', event.delivery_id, file=sys.stderr)
        if event.event == "ping":
            return web.Response(status=200)
        oauth_token = os.environ.get("GH_AUTH")
        async with aiohttp.ClientSession() as session:
Ejemplo n.º 14
0
    post = await request.post()
    sha = post['sha'].strip()
    async with dbpool.acquire() as conn:
        async with conn.cursor() as cursor:
            await cursor.execute('INSERT INTO authorized_shas (sha) VALUES (%s);', sha)
    log.info(f'authorized sha: {sha}')
    session = await aiohttp_session.get_session(request)
    set_message(session, f'SHA {sha} authorized.', 'info')
    raise web.HTTPFound('/')


@routes.get('/healthcheck')
async def healthcheck(request):  # pylint: disable=unused-argument
    return web.Response(status=200)

gh_router = gh_routing.Router()


@gh_router.register('pull_request')
async def pull_request_callback(event):
    gh_pr = event.data['pull_request']
    number = gh_pr['number']
    target_branch = FQBranch.from_gh_json(gh_pr['base'])
    for wb in watched_branches:
        if (wb.prs and number in wb.prs) or (wb.branch == target_branch):
            await wb.notify_github_changed(event.app)


@gh_router.register('push')
async def push_callback(event):
    data = event.data
Ejemplo n.º 15
0
from algorithms_keeper.constants import (
    CHECKBOX_NOT_TICKED_COMMENT,
    EMPTY_PR_BODY_COMMENT,
    INVALID_EXTENSION_COMMENT,
    MAX_PR_REACHED_COMMENT,
    PR_REVIEW_COMMENT,
    Label,
)
from algorithms_keeper.parser import PythonParser

# To disable this check, set the constant to 0.
MAX_PR_PER_USER = 3
STAGE_PREFIX = "awaiting"
MAX_RETRIES = 5

pull_request_router = routing.Router()

logger = logging.getLogger(__package__)


async def update_stage_label(
    gh: GitHubAPI, *, pull_request: Dict[str, Any], next_label: Optional[str] = None
) -> None:
    """Update the stage label of the given pull request.

    This is a two steps process with one being optional:

    1. Remove any of the stage labels, if present.
    2. Add the next stage label given in the `next_label` argument.

    If `next_label` argument is not provided, then only the first step is performed.
Ejemplo n.º 16
0
def test_too_much_detail():
    router = routing.Router()
    with pytest.raises(TypeError):
        router.add(None, "pull_request", data=42, too_much=6)
Ejemplo n.º 17
0
import asyncio
import logging
import os

import aiohttp
import azure.functions as func
from gidgethub import aiohttp as gh_aiohttp
from gidgethub import routing

from ..ghutils import ping
from ..ghutils import server
from . import classify, closed


router = routing.Router(classify.router, closed.router, ping.router)

CLIENT_SESSION = None


async def main(req: func.HttpRequest) -> func.HttpResponse:
    global CLIENT_SESSION

    try:
        if CLIENT_SESSION is None:
            CLIENT_SESSION = aiohttp.ClientSession()
        secret = os.environ.get("GH_SECRET")
        oauth_token = os.environ.get("GH_AUTH")
        body = req.get_body()
        gh = gh_aiohttp.GitHubAPI(
            CLIENT_SESSION, "Microsoft/pvscbot", oauth_token=oauth_token
        )
Ejemplo n.º 18
0
import asyncio
import os
import sys
import traceback

import aiohttp
import cachetools
from aiohttp import web
from gidgethub import aiohttp as gh_aiohttp
from gidgethub import routing, sansio

from . import check_runs, installations

router = routing.Router(installations.router, check_runs.router)

cache = cachetools.LRUCache(maxsize=500)  # type: cachetools.LRUCache


async def main(request: web.Request) -> web.Response:
    try:
        body = await request.read()
        secret = os.environ.get("GITHUB_SECRET")
        event = sansio.Event.from_http(request.headers, body, secret=secret)
        if event.event == "ping":
            return web.Response(status=200)
        async with aiohttp.ClientSession() as session:
            gh = gh_aiohttp.GitHubAPI(session, "algorithms-bot", cache=cache)
            # Give GitHub some time to reach internal consistency.
            await asyncio.sleep(1)
            await router.dispatch(event, gh)
        try:
Ejemplo n.º 19
0
import asyncio
import os
import sys
import traceback

import aiohttp
from aiohttp import web
import cachetools
from gidgethub import aiohttp as gh_aiohttp
from gidgethub import routing
from gidgethub import sansio

from . import wip

router = routing.Router(wip.router)
cache = cachetools.LRUCache(maxsize=500)


async def handler(request):
    try:
        body = await request.read()
        secret = os.environ.get("GH_SECRET")
        event = sansio.Event.from_http(request.headers, body, secret=secret)
        print('GH delivery ID', event.delivery_id, file=sys.stderr)
        if event.event == "ping":
            return web.Response(status=200)
        oauth_token = os.environ.get("GH_AUTH")
        async with aiohttp.ClientSession() as session:
            gh = gh_aiohttp.GitHubAPI(session,
                                      "aio-libs/github-bot",
                                      oauth_token=oauth_token,
Ejemplo n.º 20
0
import os
import aiohttp
from gidgethub.aiohttp import GitHubAPI
from aiohttp import web
from gidgethub import routing, sansio
from gidgethub import aiohttp as gh_aiohttp
from utils.auth import get_jwt, get_installation, get_installation_access_token
import event
import json

routes = web.RouteTableDef()
router = routing.Router(event.router)


@routes.post("/")
async def main(request):
    body = await request.read()
    user = json.loads(body.decode('utf8'))['repository']['owner']['login']
    repo = json.loads(body.decode('utf8'))['repository']['full_name']
    secret = os.environ.get("GH_SECRET")
    event = sansio.Event.from_http(request.headers, body, secret=secret)
    async with aiohttp.ClientSession() as session:
        app_id = os.getenv("GH_APP_ID")
        jwt = get_jwt(app_id)
        gh = gh_aiohttp.GitHubAPI(session, user)
        try:
            installation = await get_installation(gh, jwt, user)
        except ValueError as ve:
            print(ve)
        else:
            access_token = await get_installation_access_token(
Ejemplo n.º 21
0
import asyncio
import importlib
import os
import sys
import traceback

import aiohttp
from aiohttp import web
import cachetools
from gidgethub import aiohttp as gh_aiohttp
from gidgethub import routing
from gidgethub import sansio

from . import review

router = routing.Router(review.router)
cache = cachetools.LRUCache(maxsize=500)


async def main(request):
    """The actual webserver instance to work
    with GH webhooks later on"""
    try:
        body = await request.read()
        secret = os.environ.get("GH_SECRET")
        bot_usr = os.environ.get("GH_USERNAME")
        event = sansio.Event.from_http(request.headers, body, secret=secret)
        print("GH delivery ID", event.delivery_id, file=sys.stderr)
        if event.event == "ping":
            return web.Response(status=200)
        oauth_token = os.environ.get("GH_AUTH")
Ejemplo n.º 22
0
import asyncio
import importlib
import os
import sys
import traceback

import aiohttp
from aiohttp import web
import cachetools
from gidgethub import aiohttp as gh_aiohttp
from gidgethub import routing
from gidgethub import sansio

from . import backport, bpo, close_pr, follow_up, news, stage

router = routing.Router(backport.router, bpo.router, close_pr.router,
                        follow_up.router, news.router, stage.router)
cache = cachetools.LRUCache(maxsize=500)


async def main(request):
    try:
        body = await request.read()
        secret = os.environ.get("GH_SECRET")
        event = sansio.Event.from_http(request.headers, body, secret=secret)
        print('GH delivery ID', event.delivery_id, file=sys.stderr)
        if event.event == "ping":
            return web.Response(status=200)
        oauth_token = os.environ.get("GH_AUTH")
        async with aiohttp.ClientSession() as session:
            gh = gh_aiohttp.GitHubAPI(session,
                                      "python/bedevere",
Ejemplo n.º 23
0
import logging
from typing import Any, List

from gidgethub import routing
from gidgethub.sansio import Event

from algorithms_keeper import utils
from algorithms_keeper.api import GitHubAPI
from algorithms_keeper.constants import Label

check_run_router = routing.Router()

logger = logging.getLogger(__package__)


@check_run_router.register("check_run", action="completed")
async def check_ci_status_and_label(event: Event, gh: GitHubAPI, *args: Any,
                                    **kwargs: Any) -> None:
    """Add and remove label when any of the check runs fail.

    This event will be triggered on every check run when it is completed but we only
    want to know the final conclusion. So, the `if` statement makes sure we execute
    the block only when the last check run is completed.
    """
    repository = event.data["repository"]["full_name"]

    try:
        commit_sha = event.data["check_run"]["head_sha"]
        pr_for_commit = await utils.get_pr_for_commit(gh,
                                                      sha=commit_sha,
                                                      repository=repository)
Ejemplo n.º 24
0
import os

from aiohttp import web
import aiohttp

from gidgethub import routing, sansio
from gidgethub import aiohttp as gh_aiohttp

from . import pull_request
from . import comments

router = routing.Router(pull_request.router, comments.router)


async def test(request):
    return web.Response(status=200, text="Hello world!")


async def main(request):
    # read the GitHub webhook payload
    body = await request.read()

    # our authentication token and secret
    oauth_token = os.environ.get("GH_TOKEN")

    # a representation of GitHub webhook event
    event = sansio.Event.from_http(request.headers, body)

    # instead of mariatta, use your own username
    async with aiohttp.ClientSession() as session:
        gh = gh_aiohttp.GitHubAPI(session,
Ejemplo n.º 25
0
``@algorithms-keeper review-all`` to trigger the checks for all the pull request files,
including the modified files. As we cannot post review comments on lines not part of
the diff, this command only modify the labels accordingly.
"""
import logging
import re
from typing import Any, Pattern

from gidgethub import routing
from gidgethub.sansio import Event

from algorithms_keeper import utils
from algorithms_keeper.api import GitHubAPI
from algorithms_keeper.event.pull_request import check_pr_files

commands_router = routing.Router()

COMMAND_RE: Pattern[str] = re.compile(r"@algorithms-keeper\s+([a-z\-]+)",
                                      re.IGNORECASE)

logger = logging.getLogger(__package__)


@commands_router.register("issue_comment", action="created")
async def main(event: Event, gh: GitHubAPI, *args: Any, **kwargs: Any) -> None:
    """Main function to parse the issue comment body and call the respective command
    function if it matches.

    Only the comments made by either the member or the owner of the organization will
    be considered.
    """
Ejemplo n.º 26
0
import importlib
import logging
import os
import sys
import traceback

import aiohttp
from aiohttp import web
from gidgethub import aiohttp as gh_aiohttp
from gidgethub import routing
from gidgethub import sansio

from .ghutils import server
from .github import classify, closed, news

router = routing.Router(classify.router, closed.router, news.router)


async def hello(_):
    return web.Response(text="Hello, world")


async def main(request):
    try:
        body = await request.read()
        secret = os.environ.get("GH_SECRET")
        oauth_token = os.environ.get("GH_AUTH")
        async with aiohttp.ClientSession() as session:
            gh = gh_aiohttp.GitHubAPI(session,
                                      "Microsoft/pvscbot",
                                      oauth_token=oauth_token)
Ejemplo n.º 27
0
import aiohttp
from aiohttp import web
import cachetools
from gidgethub import aiohttp as gh_aiohttp
from gidgethub import routing
from gidgethub import sansio
from gidgethub import apps

from webservice import issues, installation

cache = cachetools.LRUCache(maxsize=500)

routes = web.RouteTableDef()

router = routing.Router(issues.router, installation.router)


@routes.get("/", name="home")
async def handle_get(request):
    return web.Response(text="Hello world")


@routes.post("/webhook")
async def webhook(request):
    try:
        body = await request.read()
        secret = os.environ.get("GH_SECRET")
        event = sansio.Event.from_http(request.headers, body, secret=secret)
        if event.event == "ping":
            return web.Response(status=200)
Ejemplo n.º 28
0
"""Check if a bugs.python.org issue number is specified in the pull request's title."""
import re

from gidgethub import routing

from . import util

router = routing.Router()
TAG_NAME = "issue-number"
CLOSING_TAG = f"<!-- /{TAG_NAME} -->"
BODY = f"""\
{{body}}

<!-- {TAG_NAME}: bpo-{{issue_number}} -->
https://bugs.python.org/issue{{issue_number}}
{CLOSING_TAG}
"""

ISSUE_RE = re.compile(r"bpo-(?P<issue>\d+)")
SKIP_ISSUE_LABEL = util.skip_label("issue")
STATUS_CONTEXT = "bedevere/issue-number"
# Try to keep descriptions at or below 50 characters, else GitHub's CSS will truncate it.
_FAILURE_DESCRIPTION = 'No issue # in title or "skip issue" label found'
_FAILURE_URL = "https://devguide.python.org/pullrequest/#submitting"
FAILURE_STATUS = util.create_status(STATUS_CONTEXT,
                                    util.StatusState.FAILURE,
                                    description=_FAILURE_DESCRIPTION,
                                    target_url=_FAILURE_URL)
del _FAILURE_DESCRIPTION
del _FAILURE_URL
SKIP_ISSUE_STATUS = util.create_status(STATUS_CONTEXT,
Ejemplo n.º 29
0
import sys
import traceback

import aiohttp
from aiohttp import web
from gidgethub import apps
from gidgethub import routing
from gidgethub import sansio
from gidgethub.aiohttp import GitHubAPI

from marvin import commands
from marvin import constants
from marvin import status
from marvin import triage_runner

router = routing.Router(commands.router, status.router)
routes = web.RouteTableDef()


def is_bot_comment(event: sansio.Event) -> bool:
    """Determine whether an event was triggered by our own comments."""
    if "comment" not in event.data:
        return False
    comment = event.data["comment"]
    comment_author_login = comment["user"]["login"]
    return comment_author_login in [constants.BOT_NAME, constants.BOT_NAME + "[bot]"]


def is_opted_in(event: sansio.Event) -> bool:
    """Perform a conservative opt-in check.