From 2a2e211d2bc0487b317932400b79f4106145ffff Mon Sep 17 00:00:00 2001 From: Adnene Guessoum Date: Sun, 22 Dec 2024 13:28:51 +0100 Subject: [PATCH] add: response filter function with tests --- .env.example | 3 ++ .gitignore | 2 ++ pyproject.toml | 1 + script/panopticron.py | 41 ++++++++++++++++++++---- tests/test_panopticron.py | 67 ++++++++++++++++++++++++++++++++++----- 5 files changed, 100 insertions(+), 14 deletions(-) diff --git a/.env.example b/.env.example index 89fca5f..00963fe 100644 --- a/.env.example +++ b/.env.example @@ -2,3 +2,6 @@ PERSONAL_GITHUB_USERNAME = "your_github_username" PERSONAL_GITHUB_TOKEN = "your_github_token" # you can create a token from "https://github.com/settings/apps" + +# the person you want to follow +TARGET_GITHUB_USERNAME = "target_username" diff --git a/.gitignore b/.gitignore index 3b4d127..dbc0f3d 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,8 @@ poetry.lock .env +run.sh # python package __pycache__/ *.pyc +temp_*.py diff --git a/pyproject.toml b/pyproject.toml index 8f4064e..c624a3f 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -10,6 +10,7 @@ readme = "README.md" python = "^3.10" python-dotenv = "^1.0.1" requests = "^2.32.3" +python-dateutil = "^2.9.0.post0" [tool.poetry.group.dev.dependencies] flake8 = "^5.0.4" diff --git a/script/panopticron.py b/script/panopticron.py index a5eb6db..54cccd3 100644 --- a/script/panopticron.py +++ b/script/panopticron.py @@ -1,14 +1,17 @@ """ Script to check on specific gh user's contributions, and send an email. """ +import datetime import logging import os +from urllib.parse import urljoin import requests +from dateutil import parser from dotenv import load_dotenv logger = logging.getLogger(__name__) load_dotenv() -PERSONAL_GITHUB_USERNAME = os.getenv("PERSONAL_GITHUB_USERNAME") PERSONAL_GITHUB_TOKEN = os.getenv("PERSONAL_GITHUB_TOKEN") +TARGET_GITHUB_USERNAME = os.getenv("TARGET_GITHUB_USERNAME") def get_user_activity(username): @@ -53,11 +56,37 @@ def check_sanity_github_api_response(response, username): return response.json() -def main(): - """TODO""" - print("TODO") - return 0 +def filter_last_24_hours_activity(user_activity): + """extract relevant info from response""" + + today = datetime.datetime.now(datetime.timezone.utc) + user_activity_last_24_hours = [] + for event in user_activity: + if not today - parser.parse(event["created_at"]) < datetime.timedelta(days=1): + continue + event_type = event["type"] + repo_name = event["repo"]["name"] + created_at = event["created_at"] + body = ( + f"\n ===================== \n" + f"New activity by {TARGET_GITHUB_USERNAME}:\n\n" + f"Url: {event.get('url', '')}" + f"Event Type: {event_type}\n" + f"Repository: {repo_name}\n" + f"Time: {created_at}\n" + f"Repo_URL: {urljoin('https://github.com/', repo_name)}\n" + f"author_URL: {urljoin('https://github.com/', TARGET_GITHUB_USERNAME)}" + f"\n ===================== \n" + ) + user_activity_last_24_hours.append(body) + + return user_activity_last_24_hours + + +def main(username): + """main function when running the script""" + return username if __name__ == "__main__": - main() + main(TARGET_GITHUB_USERNAME) diff --git a/tests/test_panopticron.py b/tests/test_panopticron.py index 2f31090..f54ee57 100644 --- a/tests/test_panopticron.py +++ b/tests/test_panopticron.py @@ -1,21 +1,60 @@ """test file for panopticron.py script""" +import datetime + from script import panopticron +TARGET_GITHUB_USERNAME = "testuser" + class MockEmptyResponse: def json(self): return {} +class ValidUserActivity: + """mock response for user activity to keep.""" + + @staticmethod + def get_user_activity(): + now = datetime.datetime.now(datetime.timezone.utc) + return [ + { + "created_at": (now - datetime.timedelta(hours=1)).isoformat(), + "type": "PushEvent", + "repo": {"name": "testuser/test-repo"}, + "url": "https://api.github.com/events/123456789", + }, + { + "created_at": (now - datetime.timedelta(hours=3)).isoformat(), + "type": "PullRequestEvent", + "repo": {"name": "testuser/another-repo"}, + "url": "https://api.github.com/events/987654321", + }, + ] + + +class InvalidUserActivity: + """mock response for user activity from 2 days ago.""" + + @staticmethod + def get_user_activity(): + now = datetime.datetime.now(datetime.timezone.utc) + return [ + { + "created_at": (now - datetime.timedelta(days=2)).isoformat(), + "type": "IssueCommentEvent", + "repo": {"name": "testuser/old-repo"}, + "url": "https://api.github.com/events/111111111", + } + ] + + class TestPanopticron: - def test_panopticron(self, capsys): - return_value = panopticron.main() - capture = capsys.readouterr() - assert capture.out == "TODO\n" - assert capture.err == "" - assert return_value == 0 - - def test_sanity_check_user_activity_wrong_username(self, capsys, caplog): + def test_main(self): + result = panopticron.main(TARGET_GITHUB_USERNAME) + assert result == TARGET_GITHUB_USERNAME + + def test_check_sanity_github_api_response_wrong_username(self, capsys, caplog): username = "nonexistentuser" response = MockEmptyResponse() # github api response for nonexistent user sanity_check = panopticron.check_sanity_github_api_response(response, username) @@ -25,3 +64,15 @@ def test_sanity_check_user_activity_wrong_username(self, capsys, caplog): assert capture_out_err.err == "" assert f"No data found for {username}" in capture_log assert sanity_check is None + + def test_filter_last_24_hours_activity_valid(self): + user_activity = ValidUserActivity.get_user_activity() + result = panopticron.filter_last_24_hours_activity(user_activity) + assert len(result) == 2 + assert "PushEvent" in result[0] + assert "PullRequestEvent" in result[1] + + def test_filter_last_24_hours_activity_invalid(self): + user_activity = InvalidUserActivity.get_user_activity() + result = panopticron.filter_last_24_hours_activity(user_activity) + assert len(result) == 0