From df0c68ece5a12a8e14801b06c69aa17475762dec Mon Sep 17 00:00:00 2001 From: Harry Lees Date: Wed, 20 Apr 2022 11:40:19 +0100 Subject: [PATCH 1/5] added roundup_summary.py script to actions --- .github/actions/roundup_summary.py | 108 +++++++++++++++++++++++++++++ 1 file changed, 108 insertions(+) create mode 100644 .github/actions/roundup_summary.py diff --git a/.github/actions/roundup_summary.py b/.github/actions/roundup_summary.py new file mode 100644 index 00000000000000..9a53707ef4da86 --- /dev/null +++ b/.github/actions/roundup_summary.py @@ -0,0 +1,108 @@ +import json +import os +from datetime import date, timedelta +from typing import Iterable + +import requests + +ISSUE_ENDPOINT = "https://github.com/python/cpython/issues" +SEARCH_ENDPOINT = "https://api.github.com/search/issues" +GRAPHQL_ENDPOINT = "https://api.github.com/graphql" +MAILGUN_ENDPOINT = "https://api.mailgun.net/v3/mg.python.org" + + +def get_issue_counts(token: str) -> tuple[int, int]: + """use the GraphQL API to get the number of opened and closed issues + without having to query every single issue and count them.""" + data = { + "query": """ + { + repository(owner: "python", name: "cpython") { + open: issues(states: OPEN) { totalCount } + closed: issues(states: CLOSED) { totalCount } + } + } + """ + } + response = requests.post(GRAPHQL_ENDPOINT, json=data, headers={ + "Authorization": f"Bearer {token}", + "accept": "application/vnd.github.v3+json" + }) + repo = response.json()["data"]["repository"] + open = repo["open"]["totalCount"] + closed = repo["closed"]["totalCount"] + return open, closed + +def get_issues(filters: Iterable[str], token: str, all_: bool = True): + """return a list of results from the Github search API""" + # TODO: if there are more than 100 issues, we need to include pagination + # this doesn't occur very often, but it should still be included just incase. + search = " ".join(filters) + data = {"query": """ + {{ + search(query:"{}" type: ISSUE first: 100) + {{ + pageInfo {{ hasNextPage endCursor startCursor }} + nodes {{ + ... on Issue {{ + title number author {{ login }} closedAt createdAt + }} + }} + }} + }} + """.format(search)} + response = requests.post(GRAPHQL_ENDPOINT, json=data, headers={ + "Authorization": f"Bearer {token}", + "accept": "application/vnd.github.v3+json" + }) + return response.json()["data"]["search"]["nodes"] + +def send_report(payload: str, token: str) -> int: + """send the report using the Mailgun API""" + params = { + "from": "Cpython Issues ", + "to": "", + "subject": "Summary of Python tracker Issues", + "template": "issue-tracker-template", + "o:tracking-clicks": "no", + "h:X-Mailgun-Variables": payload, + } + response = requests.post( + MAILGUN_ENDPOINT, + auth=("api", token), + json=params) + return response.status_code + +if __name__ == '__main__': + date_from = date.today() - timedelta(days=7) + github_token = os.environ.get("github_api_token") + mailgun_token = os.environ.get("mailgun_api_key") + + total_open, total_closed = get_issue_counts(github_token) + closed = get_issues(("repo:python/cpython", f"closed:>{date_from}", "type:issue"), github_token) + opened = get_issues(("repo:python/cpython", "state:open", f"created:>{date_from}", "type:issue"), github_token) + most_discussed = get_issues( + ("repo:python/cpython", "state:open", "type:issue", "sort:comments"), + github_token, + False) + no_comments = get_issues( + ("repo:python/cpython", "state:open", "type:issue", "comments:0", "sort:updated"), + github_token, + False) + + payload = { + "opened_issues": opened, + "closed_issues": closed, + "most_discussed": most_discussed[:10], + "no_comments": no_comments[:15], + "total_open": total_open, + "total_closed": total_closed, + "week_delta": len(opened) - len(closed), + } + status_code = send_report(json.dumps(payload), mailgun_token) + if status_code == 200: + print("successfully sent email") + else: + # in this case, fail the GitHub action + print("failed to send email", status_code) + exit(1) From d1d7faf72fac1fc9087ec7d2dad1c2e6c34fbaf7 Mon Sep 17 00:00:00 2001 From: Harry Lees Date: Wed, 20 Apr 2022 11:41:07 +0100 Subject: [PATCH 2/5] added roundup.yml workflow --- .github/workflows/roundup.yml | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) create mode 100644 .github/workflows/roundup.yml diff --git a/.github/workflows/roundup.yml b/.github/workflows/roundup.yml new file mode 100644 index 00000000000000..c39b3642d35f24 --- /dev/null +++ b/.github/workflows/roundup.yml @@ -0,0 +1,26 @@ +name: weekly-summary + +on: + schedule: + - cron: "15 19 * * FRI" + +jobs: + roundup-summary: + runs-on: ubuntu-latest + permissions: + issues: read + steps: + - name: checkout repo + uses: actions/checkout@v2 + - name: setup python + uses: actions/setup-python@v2 + with: + python-version: 3.10.1 + - name: install deps + run: pip install requests + - name: execute script + run: | + python -u ./.github/actions/roundup_summary.py + env: + github_api_token: ${{ secrets.GITHUB_TOKEN }} + mailgun_api_key: ${{ secrets.GITHUB_TOKEN }} \ No newline at end of file From beface59f3b82c7d5b243db277bcd8a3fab33724 Mon Sep 17 00:00:00 2001 From: Harry Lees Date: Wed, 20 Apr 2022 11:42:41 +0100 Subject: [PATCH 3/5] added name to ACKS --- Misc/ACKS | 1 + 1 file changed, 1 insertion(+) diff --git a/Misc/ACKS b/Misc/ACKS index a1df84c0d6779e..1c458dcfbc2fa5 100644 --- a/Misc/ACKS +++ b/Misc/ACKS @@ -1029,6 +1029,7 @@ James Lee John J. Lee Thomas Lee Robert Leenders +Harry Lees Cooper Ry Lees Yaron de Leeuw Tennessee Leeuwenburg From dd3d0223a5bcf3eb217585529ed02b533a41fc8b Mon Sep 17 00:00:00 2001 From: Harry Lees Date: Wed, 20 Apr 2022 12:43:52 +0100 Subject: [PATCH 4/5] use f-string instead of str.format() in get_issues() --- .github/actions/roundup_summary.py | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/.github/actions/roundup_summary.py b/.github/actions/roundup_summary.py index 9a53707ef4da86..8ab92a5980714f 100644 --- a/.github/actions/roundup_summary.py +++ b/.github/actions/roundup_summary.py @@ -37,10 +37,9 @@ def get_issues(filters: Iterable[str], token: str, all_: bool = True): """return a list of results from the Github search API""" # TODO: if there are more than 100 issues, we need to include pagination # this doesn't occur very often, but it should still be included just incase. - search = " ".join(filters) - data = {"query": """ + data = {"query": f""" {{ - search(query:"{}" type: ISSUE first: 100) + search(query:"{' '.join(filters)}" type: ISSUE first: 100) {{ pageInfo {{ hasNextPage endCursor startCursor }} nodes {{ @@ -50,7 +49,7 @@ def get_issues(filters: Iterable[str], token: str, all_: bool = True): }} }} }} - """.format(search)} + """} response = requests.post(GRAPHQL_ENDPOINT, json=data, headers={ "Authorization": f"Bearer {token}", "accept": "application/vnd.github.v3+json" From 24b5b8aec4899d727d2af869b1ac0d08be1f74a7 Mon Sep 17 00:00:00 2001 From: Harry Lees Date: Thu, 5 May 2022 15:05:40 +0100 Subject: [PATCH 5/5] fixed mailgun api key to use PSF_MAILGUN_KEY instead of incorrect GITHUB_TOKEN --- .github/workflows/roundup.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/roundup.yml b/.github/workflows/roundup.yml index c39b3642d35f24..0765a112298726 100644 --- a/.github/workflows/roundup.yml +++ b/.github/workflows/roundup.yml @@ -23,4 +23,4 @@ jobs: python -u ./.github/actions/roundup_summary.py env: github_api_token: ${{ secrets.GITHUB_TOKEN }} - mailgun_api_key: ${{ secrets.GITHUB_TOKEN }} \ No newline at end of file + mailgun_api_key: ${{ secrets.PSF_MAILGUN_KEY }} \ No newline at end of file