Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor into modules #53

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
123 changes: 1 addition & 122 deletions snekomatic/app.py
Original file line number Diff line number Diff line change
@@ -1,16 +1,12 @@
import sys
import os
import trio
from glom import glom
import hypercorn
import hypercorn.trio
import quart
from quart import request
from quart_trio import QuartTrio
import gidgethub

from .db import PersistentStringSet
from .gh import GithubApp
from .events import github_app
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's not "events", it's

Suggested change
from .events import github_app
from .event_handlers import github_app

conceptionally.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I suppose we might want the name to include "github" too, since we might have other kinds of events later?

I also guess we might eventually want to refactor along the lines of logically-related-features, like "inviting new users", "dependency bumping", etc., instead of lower-level functional categories like "reacting to github events", "text strings", etc.

But no need to make the perfect the enemy of the good... I'm happy with merging this now and then worrying about that stuff later. @wgwz, what do you think?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fair enough

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I like both of the suggestions! I definitely prefer taking it one step further and splitting up the modules into logically related features. I'm willing to do that for this MR.


# we should stash the delivery id in a contextvar and include it in logging
# also maybe structlog? eh print is so handy for now
Expand Down Expand Up @@ -39,7 +35,6 @@
# the milestone coming and then when you get there it *is* a milestone.

quart_app = QuartTrio(__name__)
github_app = GithubApp()

if "SENTRY_DSN" in os.environ:
import sentry_sdk
Expand Down Expand Up @@ -67,122 +62,6 @@ async def webhook_github():
return ""


SENT_INVITATION = PersistentStringSet("SENT_INVITATION")


# dedent, remove single newlines (but not double-newlines), remove
# leading/trailing newlines
def _fix_markdown(s):
import textwrap

s = s.strip("\n")
s = textwrap.dedent(s)
s = s.replace("\n\n", "__PARAGRAPH_BREAK__")
s = s.replace("\n", " ")
s = s.replace("__PARAGRAPH_BREAK__", "\n\n")
return s


invite_message = _fix_markdown(
"""
Hey @{username}, it looks like that was the first time we merged one of
your PRs! Thanks so much! :tada: :birthday:

If you want to keep contributing, we'd love to have you. So, I just sent
you an invitation to join the python-trio organization on Github! If you
accept, then here's what will happen:

* Github will automatically subscribe you to notifications on all our
repositories. (But you can unsubscribe again if you don't want the
spam.)

* You'll be able to help us manage issues (add labels, close them, etc.)

* You'll be able to review and merge other people's pull requests

* You'll get a [member] badge next to your name when participating in the
Trio repos, and you'll have the option of adding your name to our
[member's page](https://github.com/orgs/python-trio/people) and putting
our icon on your Github profile
([details](https://help.github.com/en/articles/publicizing-or-hiding-organization-membership))

If you want to read more, [here's the relevant section in our contributing
guide](https://trio.readthedocs.io/en/latest/contributing.html#joining-the-team).

Alternatively, you're free to decline or ignore the invitation. You'll
still be able to contribute as much or as little as you like, and I won't
hassle you about joining again. But if you ever change your mind, just let
us know and we'll send another invitation. We'd love to have you, but more
importantly we want you to do whatever's best for you.

If you have any questions, well... I am just a [humble Python
script](https://github.com/python-trio/snekomatic), so I probably can't
help. But please do post a comment here, or [in our
chat](https://gitter.im/python-trio/general), or [on our
forum](https://trio.discourse.group/c/help-and-advice), whatever's
easiest, and someone will help you out!

"""
)


async def _member_state(gh_client, org, member):
# Returns "active" (they're a member), "pending" (they're not a member,
# but they have an invitation they haven't responded to yet), or None
# (they're not a member and don't have a pending invitation)
try:
response = await gh_client.getitem(
"/orgs/{org}/memberships/{username}",
url_vars={"org": org, "username": member},
)
except gidgethub.BadRequest as exc:
if exc.status_code == 404:
return None
else:
raise
else:
return glom(response, "state")


# There's no "merged" event; instead you get action=closed + merged=True
@github_app.route("pull_request", action="closed")
async def pull_request_merged(event_type, payload, gh_client):
print("PR closed")
if not glom(payload, "pull_request.merged"):
print("but not merged, so never mind")
return
creator = glom(payload, "pull_request.user.login")
org = glom(payload, "organization.login")
print(f"PR by {creator} was merged!")

if creator in SENT_INVITATION:
print("The database says we already sent an invitation")
return

state = await _member_state(gh_client, org, creator)
if state is not None:
# Remember for later so we don't keep checking the Github API over and
# over.
SENT_INVITATION.add(creator)
print(f"They already have member state {state}; not inviting")
return

print("Inviting! Woohoo!")
# Send an invitation
await gh_client.put(
"/orgs/{org}/memberships/{username}",
url_vars={"org": org, "username": creator},
data={"role": "member"},
)
# Record that we did
SENT_INVITATION.add(creator)
# Welcome them
await gh_client.post(
glom(payload, "pull_request.comments_url"),
data={"body": invite_message.format(username=creator)},
)


async def main(*, task_status=trio.TASK_STATUS_IGNORED):
print("~~~ Starting up! ~~~")
# On Heroku, have to bind to whatever $PORT says:
Expand Down
67 changes: 67 additions & 0 deletions snekomatic/events.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
"""Github Event handlers for the snekomatic app."""
import gidgethub
from glom import glom
from .gh import GithubApp
from .db import PersistentStringSet
from .messaging import invite_message


github_app = GithubApp()
SENT_INVITATION = PersistentStringSet("SENT_INVITATION")


async def _member_state(gh_client, org, member):
# Returns "active" (they're a member), "pending" (they're not a member,
# but they have an invitation they haven't responded to yet), or None
# (they're not a member and don't have a pending invitation)
try:
response = await gh_client.getitem(
"/orgs/{org}/memberships/{username}",
url_vars={"org": org, "username": member},
)
except gidgethub.BadRequest as exc:
if exc.status_code == 404:
return None
else:
raise
else:
return glom(response, "state")


# There's no "merged" event; instead you get action=closed + merged=True
@github_app.route("pull_request", action="closed")
async def pull_request_merged(event_type, payload, gh_client):
print("PR closed")
if not glom(payload, "pull_request.merged"):
print("but not merged, so never mind")
return
creator = glom(payload, "pull_request.user.login")
org = glom(payload, "organization.login")
print(f"PR by {creator} was merged!")

if creator in SENT_INVITATION:
print("The database says we already sent an invitation")
return

state = await _member_state(gh_client, org, creator)
if state is not None:
# Remember for later so we don't keep checking the Github API over and
# over.
SENT_INVITATION.add(creator)
print(f"They already have member state {state}; not inviting")
return

print("Inviting! Woohoo!")
# Send an invitation
await gh_client.put(
"/orgs/{org}/memberships/{username}",
url_vars={"org": org, "username": creator},
data={"role": "member"},
)
# Record that we did
SENT_INVITATION.add(creator)
# Welcome them
await gh_client.post(
glom(payload, "pull_request.comments_url"),
data={"body": invite_message.format(username=creator)},
)
57 changes: 57 additions & 0 deletions snekomatic/messaging.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
"""Messaging for the snekomatic app."""
# dedent, remove single newlines (but not double-newlines), remove
# leading/trailing newlines


def _fix_markdown(s):
import textwrap

s = s.strip("\n")
s = textwrap.dedent(s)
s = s.replace("\n\n", "__PARAGRAPH_BREAK__")
s = s.replace("\n", " ")
s = s.replace("__PARAGRAPH_BREAK__", "\n\n")
return s


invite_message = _fix_markdown(
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could as well just have a Jinja template instead.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That is a good point! I would like to add that in as well.

"""
Hey @{username}, it looks like that was the first time we merged one of
your PRs! Thanks so much! :tada: :birthday:

If you want to keep contributing, we'd love to have you. So, I just sent
you an invitation to join the python-trio organization on Github! If you
accept, then here's what will happen:

* Github will automatically subscribe you to notifications on all our
repositories. (But you can unsubscribe again if you don't want the
spam.)

* You'll be able to help us manage issues (add labels, close them, etc.)

* You'll be able to review and merge other people's pull requests

* You'll get a [member] badge next to your name when participating in the
Trio repos, and you'll have the option of adding your name to our
[member's page](https://github.com/orgs/python-trio/people) and putting
our icon on your Github profile
([details](https://help.github.com/en/articles/publicizing-or-hiding-organization-membership))

If you want to read more, [here's the relevant section in our contributing
guide](https://trio.readthedocs.io/en/latest/contributing.html#joining-the-team).

Alternatively, you're free to decline or ignore the invitation. You'll
still be able to contribute as much or as little as you like, and I won't
hassle you about joining again. But if you ever change your mind, just let
us know and we'll send another invitation. We'd love to have you, but more
importantly we want you to do whatever's best for you.

If you have any questions, well... I am just a [humble Python
script](https://github.com/python-trio/snekomatic), so I probably can't
help. But please do post a comment here, or [in our
chat](https://gitter.im/python-trio/general), or [on our
forum](https://trio.discourse.group/c/help-and-advice), whatever's
easiest, and someone will help you out!

"""
)