Skip to content

Commit

Permalink
Merge pull request #596 from pradyunsg/lint-and-format
Browse files Browse the repository at this point in the history
Add linting and auto-formatting via pre-commit
  • Loading branch information
ambv authored Oct 13, 2023
2 parents 53b2f45 + 6d71728 commit a3d2fc6
Show file tree
Hide file tree
Showing 21 changed files with 1,032 additions and 865 deletions.
1 change: 1 addition & 0 deletions .git-blame-ignore-revs
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
35235fd609a52db835beb2a96d0da461a0eab3ed
24 changes: 24 additions & 0 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
repos:
- repo: https://github.com/psf/black
rev: 23.9.1
hooks:
- id: black

- repo: https://github.com/PyCQA/isort
rev: 5.12.0
hooks:
- id: isort
files: \.py$

- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v4.5.0
hooks:
- id: check-builtin-literals
- id: check-added-large-files
- id: check-case-conflict
- id: check-toml
- id: check-yaml
- id: debug-statements
- id: end-of-file-fixer
- id: forbid-new-submodules
- id: trailing-whitespace
28 changes: 14 additions & 14 deletions CONTRIBUTING.rst
Original file line number Diff line number Diff line change
Expand Up @@ -46,30 +46,30 @@ Heroku admins can do it too.
#. Install Heroku CLI

Details at: https://devcenter.heroku.com/articles/heroku-cli

#. Login to Heroku CLI on the command line and follow instructions::

heroku login


#. If you haven't already, get a clone of the bedevere repo::

git clone [email protected]:python/bedevere.git

Or, using `GitHub CLI`_::
gh repo clone python/bedevere

gh repo clone python/bedevere

#. From the ``bedevere`` directory, add the ``bedevere`` Heroku app as remote branch::

heroku git:remote -a bedevere


#. From the ``bedevere`` directory, push to Heroku::

git push heroku main


After a successful push, the deployment will begin.

Heroku app collaborators and members
Expand Down
36 changes: 20 additions & 16 deletions bedevere/__main__.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,36 +5,38 @@
import traceback

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

from . import backport, gh_issue, close_pr, filepaths, news, stage
from . import backport, close_pr, filepaths, gh_issue, news, stage

import sentry_sdk

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

sentry_sdk.init(os.environ.get("SENTRY_DSN"))


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)
print("GH delivery ID", event.delivery_id, file=sys.stderr)
if event.event == "ping":
return web.Response(status=200)

async with aiohttp.ClientSession() as session:
gh = gh_aiohttp.GitHubAPI(session, "python/bedevere",
cache=cache)
gh = gh_aiohttp.GitHubAPI(session, "python/bedevere", cache=cache)

if event.data.get("installation"):
# This path only works on GitHub App
Expand All @@ -43,14 +45,14 @@ async def main(request):
gh,
installation_id=installation_id,
app_id=os.environ.get("GH_APP_ID"),
private_key=os.environ.get("GH_PRIVATE_KEY")
private_key=os.environ.get("GH_PRIVATE_KEY"),
)
gh.oauth_token = installation_access_token["token"]
# Give GitHub some time to reach internal consistency.
await asyncio.sleep(1)
await router.dispatch(event, gh, session=session)
try:
print('GH requests remaining:', gh.rate_limit.remaining)
print("GH requests remaining:", gh.rate_limit.remaining)
except AttributeError:
pass
return web.Response(status=200)
Expand All @@ -62,7 +64,9 @@ async def main(request):
@router.register("installation", action="created")
async def repo_installation_added(event, gh, *args, **kwargs):
# installation_id = event.data["installation"]["id"]
print(f"App installed by {event.data['installation']['account']['login']}, installation_id: {event.data['installation']['id']}")
print(
f"App installed by {event.data['installation']['account']['login']}, installation_id: {event.data['installation']['id']}"
)


if __name__ == "__main__": # pragma: no cover
Expand Down
74 changes: 43 additions & 31 deletions bedevere/backport.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,27 +6,35 @@

from . import util

create_status = functools.partial(util.create_status, 'bedevere/maintenance-branch-pr')
create_status = functools.partial(util.create_status, "bedevere/maintenance-branch-pr")


router = gidgethub.routing.Router()

TITLE_RE = re.compile(r'\s*\[(?P<branch>\d+\.\d+)\].+\((?:GH-|#)(?P<pr>\d+)\)', re.IGNORECASE)
MAINTENANCE_BRANCH_TITLE_RE = re.compile(r'\s*\[(?P<branch>\d+\.\d+)\].+')
MAINTENANCE_BRANCH_RE = re.compile(r'\s*(?P<branch>\d+\.\d+)')
BACKPORT_LABEL = 'needs backport to {branch}'
MESSAGE_TEMPLATE = ('[GH-{pr}](https://github.com/python/cpython/pull/{pr}) is '
'a backport of this pull request to the '
'[{branch} branch](https://github.com/python/cpython/tree/{branch}).')
TITLE_RE = re.compile(
r"\s*\[(?P<branch>\d+\.\d+)\].+\((?:GH-|#)(?P<pr>\d+)\)", re.IGNORECASE
)
MAINTENANCE_BRANCH_TITLE_RE = re.compile(r"\s*\[(?P<branch>\d+\.\d+)\].+")
MAINTENANCE_BRANCH_RE = re.compile(r"\s*(?P<branch>\d+\.\d+)")
BACKPORT_LABEL = "needs backport to {branch}"
MESSAGE_TEMPLATE = (
"[GH-{pr}](https://github.com/python/cpython/pull/{pr}) is "
"a backport of this pull request to the "
"[{branch} branch](https://github.com/python/cpython/tree/{branch})."
)


BACKPORT_TITLE_DEVGUIDE_URL = "https://devguide.python.org/committing/#backport-pr-title"
BACKPORT_TITLE_DEVGUIDE_URL = (
"https://devguide.python.org/committing/#backport-pr-title"
)


async def _copy_over_labels(gh, original_issue, backport_issue):
"""Copy over relevant labels from the original PR to the backport PR."""
label_prefixes = "skip", "type", "sprint"
labels = list(filter(lambda x: x.startswith(label_prefixes),
util.labels(original_issue)))
labels = list(
filter(lambda x: x.startswith(label_prefixes), util.labels(original_issue))
)
if labels:
await gh.post(backport_issue["labels_url"], data=labels)

Expand All @@ -38,10 +46,10 @@ async def _remove_backport_label(gh, original_issue, branch, backport_pr_number)
"""
backport_label = BACKPORT_LABEL.format(branch=branch)
message = MESSAGE_TEMPLATE.format(branch=branch, pr=backport_pr_number)
await gh.post(original_issue['comments_url'], data={'body': message})
await gh.post(original_issue["comments_url"], data={"body": message})
if backport_label not in util.labels(original_issue):
return
await gh.delete(original_issue['labels_url'], {'name': backport_label})
await gh.delete(original_issue["labels_url"], {"name": backport_label})


@router.register("pull_request", action="opened")
Expand All @@ -50,18 +58,17 @@ async def manage_labels(event, gh, *args, **kwargs):
if event.data["action"] == "edited" and "title" not in event.data["changes"]:
return
pull_request = event.data["pull_request"]
title = util.normalize_title(pull_request['title'],
pull_request['body'])
title = util.normalize_title(pull_request["title"], pull_request["body"])
title_match = TITLE_RE.match(title)
if title_match is None:
return
branch = title_match.group('branch')
original_pr_number = title_match.group('pr')
branch = title_match.group("branch")
original_pr_number = title_match.group("pr")

original_issue = await gh.getitem(event.data['repository']['issues_url'],
{'number': original_pr_number})
await _remove_backport_label(gh, original_issue, branch,
event.data["number"])
original_issue = await gh.getitem(
event.data["repository"]["issues_url"], {"number": original_pr_number}
)
await _remove_backport_label(gh, original_issue, branch, event.data["number"])

backport_issue = await util.issue_for_PR(gh, pull_request)
await _copy_over_labels(gh, original_issue, backport_issue)
Expand All @@ -78,7 +85,7 @@ def is_maintenance_branch(ref):
>>> is_maintenance_branch("gh-1234/something-completely-different")
False
"""
maintenance_branch_pattern = r'\d+\.\d+'
maintenance_branch_pattern = r"\d+\.\d+"
return bool(re.fullmatch(maintenance_branch_pattern, ref))


Expand All @@ -102,17 +109,19 @@ async def validate_maintenance_branch_pr(event, gh, *args, **kwargs):
if not is_maintenance_branch(base_branch):
return

title = util.normalize_title(pull_request["title"],
pull_request["body"])
title = util.normalize_title(pull_request["title"], pull_request["body"])
title_match = MAINTENANCE_BRANCH_TITLE_RE.match(title)

if title_match is None:
status = create_status(util.StatusState.FAILURE,
description="Not a valid maintenance branch PR title.",
target_url=BACKPORT_TITLE_DEVGUIDE_URL)
status = create_status(
util.StatusState.FAILURE,
description="Not a valid maintenance branch PR title.",
target_url=BACKPORT_TITLE_DEVGUIDE_URL,
)
else:
status = create_status(util.StatusState.SUCCESS,
description="Valid maintenance branch PR title.")
status = create_status(
util.StatusState.SUCCESS, description="Valid maintenance branch PR title."
)
await util.post_status(gh, event, status)


Expand All @@ -130,6 +139,9 @@ async def maintenance_branch_created(event, gh, *args, **kwargs):
if MAINTENANCE_BRANCH_RE.match(branch_name):
await gh.post(
"/repos/python/cpython/labels",
data={"name": f"needs backport to {branch_name}", "color": "c2e0c6",
"description": "bug and security fixes"},
data={
"name": f"needs backport to {branch_name}",
"color": "c2e0c6",
"description": "bug and security fixes",
},
)
34 changes: 19 additions & 15 deletions bedevere/close_pr.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,7 @@

import gidgethub.routing


PYTHON_MAINT_BRANCH_RE = re.compile(r'^\w+:\d+\.\d+$')
PYTHON_MAINT_BRANCH_RE = re.compile(r"^\w+:\d+\.\d+$")

INVALID_PR_COMMENT = """\
PRs attempting to merge a maintenance branch into the \
Expand All @@ -16,6 +15,7 @@

router = gidgethub.routing.Router()


@router.register("pull_request", action="opened")
@router.register("pull_request", action="synchronize")
async def close_invalid_pr(event, gh, *args, **kwargs):
Expand All @@ -28,17 +28,15 @@ async def close_invalid_pr(event, gh, *args, **kwargs):
head_label = event.data["pull_request"]["head"]["label"]
base_label = event.data["pull_request"]["base"]["label"]

if PYTHON_MAINT_BRANCH_RE.match(head_label) and \
base_label == "python:main":
data = {'state': 'closed'}
if PYTHON_MAINT_BRANCH_RE.match(head_label) and base_label == "python:main":
data = {"state": "closed"}
await gh.patch(event.data["pull_request"]["url"], data=data)
await gh.post(
f'{event.data["pull_request"]["issue_url"]}/labels',
data=["invalid"]
f'{event.data["pull_request"]["issue_url"]}/labels', data=["invalid"]
)
await gh.post(
f'{event.data["pull_request"]["issue_url"]}/comments',
data={'body': INVALID_PR_COMMENT}
data={"body": INVALID_PR_COMMENT},
)


Expand All @@ -53,10 +51,16 @@ async def dismiss_invalid_pr_review_request(event, gh, *args, **kwargs):
head_label = event.data["pull_request"]["head"]["label"]
base_label = event.data["pull_request"]["base"]["label"]

if PYTHON_MAINT_BRANCH_RE.match(head_label) and \
base_label == "python:main":
data = {"reviewers": [reviewer["login"] for reviewer in event.data["pull_request"]["requested_reviewers"]],
"team_reviewers": [team["name"] for team in event.data["pull_request"]["requested_teams"]]
}
await gh.delete(f'{event.data["pull_request"]["url"]}/requested_reviewers',
data=data)
if PYTHON_MAINT_BRANCH_RE.match(head_label) and base_label == "python:main":
data = {
"reviewers": [
reviewer["login"]
for reviewer in event.data["pull_request"]["requested_reviewers"]
],
"team_reviewers": [
team["name"] for team in event.data["pull_request"]["requested_teams"]
],
}
await gh.delete(
f'{event.data["pull_request"]["url"]}/requested_reviewers', data=data
)
17 changes: 7 additions & 10 deletions bedevere/filepaths.py
Original file line number Diff line number Diff line change
@@ -1,22 +1,19 @@
"""Checks related to filepaths on a pull request."""
import gidgethub.routing

from . import news
from . import prtype
from . import util

from . import news, prtype, util

router = gidgethub.routing.Router()


@router.register('pull_request', action='opened')
@router.register('pull_request', action='synchronize')
@router.register('pull_request', action='reopened')
@router.register("pull_request", action="opened")
@router.register("pull_request", action="synchronize")
@router.register("pull_request", action="reopened")
async def check_file_paths(event, gh, *args, **kwargs):
pull_request = event.data['pull_request']
pull_request = event.data["pull_request"]
files = await util.files_for_PR(gh, pull_request)
filenames = [file['file_name'] for file in files]
if event.data['action'] == 'opened':
filenames = [file["file_name"] for file in files]
if event.data["action"] == "opened":
labels = await prtype.classify_by_filepaths(gh, pull_request, filenames)
if prtype.Labels.skip_news not in labels:
await news.check_news(gh, pull_request, files)
Expand Down
Loading

0 comments on commit a3d2fc6

Please sign in to comment.