8000 Periodic job to label stale PRs python/core-workflow#93 by chetankm-cs · Pull Request #67 · python/bedevere · GitHub
[go: up one dir, main page]

Skip to content

Periodic job to label stale PRs python/core-workflow#93 #67

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

Closed
wants to merge 1 commit into from
Closed
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
10000
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 7 additions & 4 deletions bedevere/__main__.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,15 +10,14 @@
from gidgethub import aiohttp as gh_aiohttp
from gidgethub import routing
from gidgethub import sansio
from apscheduler.schedulers.asyncio import AsyncIOScheduler

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

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

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


async def main(request):
try:
body = await request.read()
Expand All @@ -44,8 +43,12 @@ async def main(request):
traceback.print_exc(file=sys.stderr)
return web.Response(status=500)


if __name__ == "__main__": # pragma: no cover

scheduler = AsyncIOScheduler()
scheduler.start()
scheduler.add_job(stale_pr.invoke, 'cron', hour='0')

app = web.Application()
app.router.add_post("/", main)
port = os.environ.get("PORT")
Expand Down
43 changes: 43 additions & 0 deletions bedevere/stale_pr.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
"""Add stale label to pull requests with label CLA not signed/awaiting changes and no activity."""
import os
from datetime import datetime
import asyncio
import aiohttp
from gidgethub import aiohttp as gh_aiohttp


from . import util

STALE_LABEL = 'stale'
PR_ACTIVE_DURATION = 30 #days

def is_pr(issue):
return issue.get('pull_request') != None

def is_stale(issue):
updated_at = datetime.strptime(issue['updated_at'], '%Y-%m-%dT%H:%M:%SZ')
return (datetime.now() - updated_at).days > PR_ACTIVE_DURATION

def has_stale_label(issue):
return STALE_LABEL in util.labels(issue)

async def process_issue(issue, gh):
if is_pr(issue) and is_stale(issue) and not has_stale_label(issue):
print("Adding stale label to issue " + str(issue['number']))
await gh.post(issue['labels_url'], data=[STALE_LABEL])

async def label_stale_prs(gh):
async for issue in gh.getiter("/repos/python/cpython/issues?labels=CLA%20not%20signed&sort=updated&direction=asc&state=open"):
await process_issue(issue, gh)

async for issue in gh.getiter("/repos/python/cpython/issues?labels=awaiting%20changes&sort=updated&direction=asc&state=open"):
await process_issue(issue, gh)


async def invoke():
oauth_token = os.environ.get("GH_AUTH")
async with aiohttp.ClientSession() as session:
gh = gh_aiohttp.GitHubAPI(session, "python/bedevere", oauth_token=oauth_token)
# Give GitHub some time to reach internal consistency.
await asyncio.sleep(1)
return await label_stale_prs(gh)
3 changes: 3 additions & 0 deletions requirements.txt
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
aiohttp==2.1.0
appdirs==1.4.3
APScheduler==3.3.1
async-timeout==1.2.1
cachetools==2.0.0
chardet==3.0.4
Expand All @@ -8,6 +9,8 @@ multidict==2.1.6
packaging==16.8
py==1.4.33
pyparsing==2.2.0
pytz==2017.2
six==1.10.0
tzlocal==1.4
uritemplate==3.0.0
yarl==0.10.3
104 changes: 104 additions & 0 deletions tests/test_stale_pr.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
import pytest
from datetime import datetime
from gidgethub import sansio

from bedevere import stale_pr


class FakeGH:

async def getiter(self, url):
for issue in self._issues:
yield issue

def __init__(self, *, issues, getitem=None):
self.post_url = None
self.post_data = None
self._issues = issues

async def post(self, url, data):
self.post_url = url
self.post_data = data


@pytest.mark.asyncio
async def test_stale_pr_labelled_stale():
issue = {
"labels_url": "https://api.github.com/repos/python/cpython/issues/3919/labels{/name}",
"id": 263653898,
"number": 3919,
"labels": [{
"name": "awaiting review"
},
{
"name": "CLA signed"
}
],
"state": "open",
"created_at": "2017-08-07T16:34:58Z",
"updated_at": "2017-08-07T16:35:01Z",
"pull_request": {
"url": "https://api.github.com/repos/python/cpython/pulls/3919"
}
}
gh = FakeGH(issues=[issue])
await stale_pr.label_stale_prs(gh)
assert gh.post_data == ["stale"]


@pytest.mark.asyncio
async def test_no_action_on_labelled_stale_pr():
issue = {
"labels_url": "https://api.github.com/repos/python/cpython/issues/3919/labels{/name}",
"id": 263653898,
"number": 3919,
"labels": [{
"name": "awaiting review"
},
{
"name": "stale"
}
],
"state": "open",
"created_at": "2017-10-07T16:34:58Z",
"updated_at": "2017-10-07T16:35:01Z",
"pull_request": {
"url": "https://api.github.com/repos/python/cpython/pulls/3919"
}
}
gh = FakeGH(issues=[issue])
await stale_pr.label_stale_prs(gh)
assert gh.post_data == None

@pytest.mark.asyncio
async def test_no_action_on_active_pr():
updated_at = datetime.utcnow().strftime("%Y-%m-%dT%H:%M:%SZ")
issue = {
"labels_url": "https://api.github.com/repos/python/cpython/issues/3919/labels{/name}",
"id": 263653898,
"number": 3919,
"labels": [{
"name": "awaiting review"
},
{
"name": "CLA signed"
}
],
"state": "open",
"created_at": "2016-10-07T16:34:58Z",
"updated_at": updated_at,
"pull_request": {
"url": "https://api.github.com/repos/python/cpython/pulls/3919"
}
}
gh = FakeGH(issues=[issue])
await stale_pr.label_stale_prs(gh)
assert gh.post_data == None

@pytest.mark.asyncio
async def test_invoke():
async def stub(self):
return "done"
stale_pr.label_stale_prs = stub
result = await stale_pr.invoke()
assert result == "done"
0