Beispiel #1
0
async def main(request: Request) -> 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 Response(status=200)
        logger.info(
            "event=%s delivery_id=%s",
            f"{event.event}:{event.data['action']}",
            event.delivery_id,
        )
        async with ClientSession() as session:
            gh = GitHubAPI(
                event.data["installation"]["id"],
                session,
                "dhruvmanila/algorithms-keeper",
                cache=cache,
            )
            # Give GitHub some time to reach internal consistency.
            await asyncio.sleep(1)
            await main_router.dispatch(event, gh)
        if gh.rate_limit is not None:  # pragma: no cover
            logger.info(
                "ratelimit=%s, time_remaining=%s",
                f"{gh.rate_limit.remaining}/{gh.rate_limit.limit}",
                gh.rate_limit.reset_datetime - datetime.now(timezone.utc),
            )
        return Response(status=200)
    except Exception as err:
        logger.exception(err)
        return Response(status=500, text=str(err))
Beispiel #2
0
 async def event_from_request(self, request):
     """Get an event object out of HTTP request."""
     event = Event.from_http(
         request.headers,
         await request.read(),
         secret=self._config.webhook_secret,
     )
     await self.pre_process_webhook_event(event)
     return event
Beispiel #3
0
 async def _dispatch(self, request):
     try:
         event = Event.from_http(request.headers,
                                 await request.read(),
                                 secret=self._verification)
         await self._github_router.dispatch(event)
     except Exception as e:
         logger.exception(e)
         return Response(status=500)
     else:
         return Response(status=200)
def test_process_webhook_payload(incoming_event, is_successful):
    """Test that @process_webhook_payload unpacks event into kw-args."""
    event = Event(data=incoming_event, event=None, delivery_id=None)

    if is_successful:
        assert (
            # pylint: disable=missing-kwoa,too-many-function-args
            fake_event_handler(event) == tuple(incoming_event.values()))
    else:
        with pytest.raises(TypeError):
            # pylint: disable=missing-kwoa,too-many-function-args
            fake_event_handler(event)
Beispiel #5
0
async def review(event: Event, gh: GitHubAPI, *args: Any,
                 **kwargs: Any) -> None:
    """Review command to trigger the checks for all the pull request files."""
    issue = event.data["issue"]
    comment = event.data["comment"]
    if "pull_request" in issue:
        # Give a heads up that the command has been received.
        await utils.add_reaction(gh, reaction="+1", comment=comment)
        event.data["pull_request"] = await utils.get_pr_for_issue(gh,
                                                                  issue=issue)
        await check_pr_files(event, gh, *args, **kwargs)
    else:
        # The command cannot be run on an issue.
        await utils.add_reaction(gh, reaction="-1", comment=comment)
Beispiel #6
0
 def event(self):  # noqa: D401
     """Parsed GitHub Action event data."""
     try:
         # NOTE: This could be async but it probably doesn't matter
         # NOTE: since it's called just once during init and GitHub
         # NOTE: Action runtime only has one event to process
         # pylint: disable=no-member
         with self._metadata.event_path.open() as event_source:
             return Event(
                 json.load(event_source),
                 event=self._metadata.event_name,
                 delivery_id=uuid4(),
             )
     except TypeError:
         return None
Beispiel #7
0
async def dispatch(request):
    github = request.app.plugins['github']
    payload = await request.read()

    try:
        event = Event.from_http(request.headers, payload, secret=github.verify)
        await github.router.dispatch(event, app=request.app)
    except ValidationFailure as e:
        LOG.debug('Github webhook failed verification: %s, %s',
                  request.headers, payload)
        return Response(status=401)
    except Exception as e:
        LOG.exception(e)
        return Response(status=500)
    else:
        return Response(status=200)
Beispiel #8
0
 async def dispatch_webhook(self, headers, body):
     event = Event.from_http(headers, body, secret=self.webhook_secret)
     print(
         f"GH webhook received: type={event.event}, delivery id={event.delivery_id}"
     )
     # Wait a bit to give Github's eventual consistency time to catch up
     await anyio.sleep(1)
     installation_id = glom(event.data, "installation.id", default=None)
     if installation_id is None:
         print("No associated installation; not dispatching")
         return
     client = self.client_for(installation_id)
     for route in self._routes[event.event]:
         if _all_match(event.data, route.restrictions):
             print(f"Routing to {route.async_fn!r}")
             await route.async_fn(event.event, event.data, client)
     try:
         limit = client.rate_limit.remaining
     except AttributeError:
         pass
     else:
         print(f"Rate limit for install {installation_id}: {limit}")
Beispiel #9
0
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']}",
                "delivery_id": event.delivery_id,
            },
        )
        async with aiohttp.ClientSession() as session:
            gh = GitHubAPI(session,
                           "dhruvmanila/algorithms-keeper",
                           cache=cache)
            # Give GitHub some time to reach internal consistency.
            await asyncio.sleep(1)
            await router.dispatch(event, gh)
        try:
            logger.info(
                "ratelimit=%(ratelimit)s time_remaining=%(time_remaining)s",
                {
                    "ratelimit":
                    f"{gh.rate_limit.remaining}/{gh.rate_limit.limit}",
                    "time_remaining":
                    gh.rate_limit.reset_datetime -
                    datetime.datetime.now(datetime.timezone.utc),
                },
            )
        except AttributeError:
            pass
        return web.Response(status=200)
    except Exception as err:
        logger.exception(err)
        return web.Response(status=500, text=str(err))
# Reminder: ``Event.delivery_id`` is used as a short description for the respective
# test case and as a way to id the specific test case in the parametrized group.
@pytest.mark.asyncio
@pytest.mark.parametrize(
    "event, gh, expected",
    (
        # Installation was created on a repository.
        (
            Event(
                data={
                    "action": "created",
                    "installation": {
                        "id": number
                    },
                    "repositories": [{
                        "full_name": repository
                    }],
                    "sender": {
                        "login": user
                    },
                },
                event="installation",
                delivery_id="installation_created",
            ),
            MockGitHubAPI(post={issue_path: {
                "url": issue_url
            }}),
            ExpectedData(
                post_url=[issue_path],
                post_data=[{
                    "title": "Installation successful!",
                    "body": FILLED_GREETING_COMMENT,
    assert match.group(1) == group


# Reminder: ``Event.delivery_id`` is used as a short description for the respective
# test case and as a way to id the specific test case in the parametrized group.
@pytest.mark.asyncio
@pytest.mark.parametrize(
    "event, gh, expected",
    (
        # Issue comment made by a non member, so do nothing.
        (
            Event(
                data={
                    "action": "created",
                    "comment": {
                        "author_association": "NONE",
                    },
                },
                event="issue_comment",
                delivery_id="non_member_commented",
            ),
            MockGitHubAPI(),
            ExpectedData(),
        ),
        # Issue comment came from an issue instead of a pull request, so do nothing.
        (
            Event(
                data={
                    "action": "created",
                    "comment": {
                        "url": comment_url,
                        "author_association": "MEMBER",
Beispiel #12
0
# test case and as a way to id the specific test case in the parametrized group.
@pytest.mark.asyncio
@pytest.mark.parametrize(
    "event, gh, expected",
    (
        # Issue opened with an empty description so label it invalid, comment and
        # close the issue.
        (
            Event(
                data={
                    "action": "opened",
                    "issue": {
                        "url": issue_url,
                        "comments_url": comments_url,
                        "labels_url": labels_url,
                        "user": {"login": user},
                        "body": "",
                        "html_url": html_issue_url,
                    },
                },
                event="issues",
                delivery_id="empty_description",
            ),
            MockGitHubAPI(),
            ExpectedData(
                post_url=[comments_url, labels_url],
                post_data=[
                    {"body": comment},
                    {"labels": [Label.INVALID]},
                ],
                patch_url=[issue_url],
 Event(
     data={
         "action": "opened",
         "pull_request": {
             "url":
             pr_url,
             "body":
             CHECKBOX_TICKED_UPPER,  # Case doesn't matter
             "user": {
                 "login": user
             },
             "labels": [],
             "author_association":
             "NONE",
             "comments_url":
             comments_url,
             "issue_url":
             issue_url,
             "html_url":
             html_pr_url,
             "requested_reviewers": [{
                 "login": "******"
             }, {
                 "login": "******"
             }],
             "draft":
             False,
             "mergeable":
             True,
         },
         "repository": {
             "full_name": repository
         },
     },
     event="pull_request",
     delivery_id=MAX_PR_TEST_ENABLED_ID,
 ),
# Reminder: ``Event.delivery_id`` is used as a short description for the respective
# test case and as a way to id the specific test case in the parametrized group.
@pytest.mark.asyncio
@pytest.mark.parametrize(
    "event, gh, expected",
    (
        # Check run completed from a commit which does not belong to a pull request.
        (
            Event(
                data={
                    "action": "completed",
                    "check_run": {
                        "head_sha": sha,
                    },
                    "repository": {
                        "full_name": repository
                    },
                },
                event="check_run",
                delivery_id="commit_not_from_pr",
            ),
            MockGitHubAPI(
                getitem={search_url: {
                    "total_count": 0,
                    "items": [],
                }}),
            ExpectedData(getitem_url=[search_url]),
        ),
        # Check run completed but some of the other checks are in progress.
        (