diff --git a/projects/gh-unnotifier/BUILD b/projects/gh-unnotifier/BUILD deleted file mode 100644 index a820dab..0000000 --- a/projects/gh-unnotifier/BUILD +++ /dev/null @@ -1,9 +0,0 @@ -py_project( - name = "gh-unnotifier", - main = "src/python/ghunnotif/__main__.py", - main_deps = [ - py_requirement("click"), - py_requirement("requests"), - py_requirement("pytimeparse"), - ] -) diff --git a/projects/gh-unnotifier/src/python/ghunnotif/__main__.py b/projects/gh-unnotifier/src/python/ghunnotif/__main__.py deleted file mode 100644 index d4a7e44..0000000 --- a/projects/gh-unnotifier/src/python/ghunnotif/__main__.py +++ /dev/null @@ -1,125 +0,0 @@ -#!/usr/bin/env python3 - -import os -from pathlib import Path -import tomllib -from typing import Optional -from datetime import datetime, timedelta, timezone -from time import sleep - -import click -import requests -import pytimeparse - -class Client(object): - BASE = "https://api.github.com" - HEADERS = {"Accept": "application/vnd.github+json"} - - def __init__(self, token): - self._token = token - self._session = requests.Session() - self._session.headers["Authorization"] = f"Bearer {token}" - - def get_notifications(self, page=1): - resp = self._session.get(f"{self.BASE}/notifications", headers=self.HEADERS, params={"page": page, "all": "false"}) - resp.raise_for_status() - return resp.json() - - def get_all_notifications(self): - page = 1 - while True: - results = self.get_notifications(page=page) - if not results: - return - yield from results - page += 1 - - def read(self, notif): - return self._session.patch(notif["url"]).raise_for_status() - - def unsubscribe(self, notif): - return self._session.delete(notif["subscription_url"]).raise_for_status() - - def get_pr(self, - url: Optional[str] = None, - repo: Optional[str] = None, - id: Optional[int] = None): - url = url or f"{self.BASE}/{repo}/pulls/{id}" - resp = self._session.get(url, headers=self.HEADERS) - resp.raise_for_status() - return resp.json() - - -@click.group() -def cli(): - pass - - -@cli.command() -@click.option("--config", "config_path", type=Path, default=lambda: Path(os.getenv("BUILD_WORKSPACE_DIRECTORY", "")) / "projects/gh-unnotifier/config.toml") -def oneshot(config_path: Path): - with open(config_path, "rb") as fp: - config = tomllib.load(fp) - - client = Client(config["gh-unnotifier"]["api_key"]) - for notif in client.get_all_notifications(): - subject = notif["subject"] - pr = None - if "/pulls/" in subject["url"]: - pr = client.get_pr(url=subject["url"]) - if pr["state"] == "closed": - client.read(notif) - client.unsubscribe(notif) - - print("Resolved", notif["id"]) - continue - - print(notif["id"], notif["subscription_url"], notif["reason"], notif["subject"], pr) - - -def parse_seconds(text: str) -> timedelta: - return timedelta(seconds=pytimeparse.parse(text)) - - -@cli.command() -@click.option("--config", "config_path", type=Path, default=lambda: Path(os.getenv("BUILD_WORKSPACE_DIRECTORY", "")) / "projects/gh-unnotifier/config.toml") -@click.option("--schedule", "schedule", default="15 seconds", type=parse_seconds) -def maintain(config_path: Path, schedule: timedelta): - with open(config_path, "rb") as fp: - config = tomllib.load(fp) - - client = Client(config["gh-unnotifier"]["api_key"]) - mark = None - while True: - try: - prev = mark - mark = datetime.now(timezone.utc) - tick = mark + schedule - assert tick - schedule == mark - for notif in client.get_all_notifications(): - subject = notif["subject"] - - # Don't waste time on notifications which haven't changed since the last scrub - updated_at = datetime.fromisoformat(notif["updated_at"]) - if prev and updated_at < prev: - continue - - pr = None - if "/pulls/" in subject["url"]: - pr = client.get_pr(url=subject["url"]) - if pr["state"] == "closed": - client.read(notif) - client.unsubscribe(notif) - - click.echo(f"Resolved {notif['id']}") - continue - - click.echo("Napping...") - sleep((tick - datetime.now(timezone.utc)).total_seconds()) - - except KeyboardInterrupt: - break - - -if __name__ == "__main__": - cli() diff --git a/tools/python/requirements.in b/tools/python/requirements.in index 7546ca0..f48906d 100644 --- a/tools/python/requirements.in +++ b/tools/python/requirements.in @@ -53,4 +53,3 @@ toml unify yamllint yaspin -pytimeparse diff --git a/tools/python/requirements_lock.txt b/tools/python/requirements_lock.txt index e2c15b9..5c93185 100644 --- a/tools/python/requirements_lock.txt +++ b/tools/python/requirements_lock.txt @@ -1,26 +1,25 @@ -aiohttp==3.8.5 +aiohttp==3.8.4 aiohttp-basicauth==1.0.0 aiosignal==1.3.1 -aiosql==9.0 +aiosql==8.0 alabaster==0.7.13 -annotated-types==0.5.0 -async-lru==2.0.4 +async-lru==2.0.2 async-timeout==4.0.2 attrs==23.1.0 autocommand==2.2.2 -autoflake==2.2.0 +autoflake==2.1.1 Babel==2.12.1 beautifulsoup4==4.12.2 -black==23.7.0 +black==23.3.0 blinker==1.6.2 build==0.10.0 cachetools==5.3.1 -certifi==2023.7.22 -charset-normalizer==3.2.0 +certifi==2023.5.7 +charset-normalizer==3.1.0 cheroot==10.0.0 CherryPy==18.8.0 -click==8.1.6 -colored==2.2.3 +click==8.1.3 +colored==1.4.4 commonmark==0.9.1 coverage==7.2.7 decorator==5.1.1 @@ -29,54 +28,53 @@ docutils==0.20.1 ExifRead==3.0.0 flake8==6.0.0 Flask==2.3.2 -frozenlist==1.4.0 -hypothesis==6.82.0 +frozenlist==1.3.3 +hypothesis==6.75.9 ibis==3.2.0 icmplib==3.0.3 idna==3.4 imagesize==1.4.1 -inflect==7.0.0 +inflect==6.0.4 iniconfig==2.0.0 isort==5.12.0 itsdangerous==2.1.2 -jaraco.collections==4.3.0 +jaraco.collections==4.2.0 jaraco.context==4.3.0 -jaraco.functools==3.8.0 -jaraco.text==3.11.1 +jaraco.functools==3.7.0 +jaraco.text @ git+https://github.com/arrdem/jaraco.text.git@0dd8d0b25a93c3fad896f3a92d11caff61ff273d jedi==0.18.2 Jinja2==3.1.2 -jsonschema==4.18.4 -jsonschema-spec==0.2.3 -jsonschema-specifications==2023.7.1 -lark==1.1.7 +jsonschema==4.17.3 +jsonschema-spec==0.1.4 +lark==1.1.5 lazy-object-proxy==1.9.0 libsass==0.22.0 livereload==2.6.3 -lxml==4.9.3 -Markdown==3.4.4 +lxml==4.9.2 +Markdown==3.4.3 MarkupSafe==2.1.3 mccabe==0.7.0 -meraki==1.34.0 +meraki==1.33.0 mirakuru==2.5.1 mistune==2.0.5 -more-itertools==10.0.0 +more-itertools==9.1.0 multidict==6.0.4 mypy-extensions==1.0.0 octorest==0.4 -openapi-schema-validator==0.6.0 -openapi-spec-validator==0.6.0 +openapi-schema-validator==0.4.4 +openapi-spec-validator==0.5.6 packaging==23.1 parso==0.8.3 pathable==0.4.3 pathspec==0.11.1 picobox==3.0.0 pip==23.1.2 -pip-tools==7.1.0 -platformdirs==3.9.1 -pluggy==1.2.0 -port-for==0.7.1 -portend==3.2.0 -prompt-toolkit==3.0.39 +pip-tools==6.13.0 +platformdirs==3.5.1 +pluggy==1.0.0 +port-for==0.6.3 +portend==3.1.0 +prompt-toolkit==3.0.38 proquint==0.2.1 psutil==5.9.5 psycopg==3.1.9 @@ -85,34 +83,30 @@ pudb==2022.1.3 py==1.11.0 pycodestyle==2.10.0 pycryptodome==3.18.0 -pydantic==2.1.1 -pydantic_core==2.4.0 +pydantic==1.10.8 pyflakes==3.0.1 Pygments==2.15.1 pyproject_hooks==1.0.0 pyrsistent==0.19.3 -pytest==7.4.0 +pytest==7.3.1 pytest-cov==4.1.0 pytest-postgresql==5.0.0 pytest-pudb==0.7.0 pytest-timeout==2.1.0 -pytimeparse==1.1.8 pytz==2023.3 -PyYAML==6.0.1 +PyYAML==6.0 recommonmark==0.7.1 -redis==4.6.0 -referencing==0.29.3 +redis==4.5.5 requests==2.31.0 retry==0.9.2 rfc3339-validator==0.1.4 -rpds-py==0.9.2 -setuptools==68.0.0 +setuptools==67.7.2 six==1.16.0 smbus2==0.4.2 snowballstemmer==2.2.0 sortedcontainers==2.4.0 soupsieve==2.4.1 -Sphinx==7.1.1 +Sphinx==7.0.1 sphinx_mdinclude==0.5.3 sphinxcontrib-applehelp==1.0.4 sphinxcontrib-devhelp==1.0.2 @@ -123,19 +117,19 @@ sphinxcontrib-openapi==0.8.1 sphinxcontrib-programoutput==0.17 sphinxcontrib-qthelp==1.0.3 sphinxcontrib-serializinghtml==1.1.5 -tempora==5.5.0 +tempora==5.2.2 termcolor==2.3.0 toml==0.10.2 tornado==6.3.2 -typing_extensions==4.7.1 +typing_extensions==4.6.3 unify==0.5 untokenize==0.1.1 -urllib3==2.0.4 +urllib3==2.0.2 urwid==2.1.2 urwid-readline==0.13 wcwidth==0.2.6 -websocket-client==1.6.1 -Werkzeug==2.3.6 +websocket-client==1.5.2 +Werkzeug==2.3.4 wheel==0.40.0 yamllint==1.32.0 yarl==1.9.2