From 58020ee8e28ce0935a13d5ef495bf59723c7a010 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Ga=C3=ABtan=20Blond?= <gaetan@blond.tf>
Date: Wed, 5 Jan 2022 20:04:26 +0100
Subject: [PATCH] Added Github fetcher

---
 updates_notifier/entry.py                    | 10 +++++
 updates_notifier/fetchers/__init__.py        |  1 +
 updates_notifier/fetchers/github_fetcher.py  | 43 ++++++++++++++++++++
 updates_notifier/fetchers/project_fetcher.py | 14 +++++++
 4 files changed, 68 insertions(+)
 create mode 100644 updates_notifier/entry.py
 create mode 100644 updates_notifier/fetchers/github_fetcher.py
 create mode 100644 updates_notifier/fetchers/project_fetcher.py

diff --git a/updates_notifier/entry.py b/updates_notifier/entry.py
new file mode 100644
index 0000000..57481f4
--- /dev/null
+++ b/updates_notifier/entry.py
@@ -0,0 +1,10 @@
+from dataclasses import dataclass
+
+
+@dataclass
+class Entry:
+    feed_id: int
+    tag_id: str
+    name: str
+    version: str
+    url: str
diff --git a/updates_notifier/fetchers/__init__.py b/updates_notifier/fetchers/__init__.py
index e69de29..a6b34eb 100644
--- a/updates_notifier/fetchers/__init__.py
+++ b/updates_notifier/fetchers/__init__.py
@@ -0,0 +1 @@
+from .project_fetcher import ProjectFetcher
diff --git a/updates_notifier/fetchers/github_fetcher.py b/updates_notifier/fetchers/github_fetcher.py
new file mode 100644
index 0000000..0b572fd
--- /dev/null
+++ b/updates_notifier/fetchers/github_fetcher.py
@@ -0,0 +1,43 @@
+import logging
+import requests
+from typing import List
+
+from ..entry import Entry
+from .project_fetcher import ProjectFetcher
+
+logger = logging.getLogger(__name__)
+
+
+class GithubFetcher(ProjectFetcher):
+    def __init__(self, feed_id: int, name: str, repository: str):
+        super().__init__(feed_id, name)
+
+        self.repository = repository
+
+    def _get_releases_url(self) -> str:
+        return f"https://api.github.com/repos/{self.repository}/releases"
+
+    def fetch_entries(self) -> List[Entry]:
+        req = requests.get(self._get_releases_url())
+        if req.status_code != requests.codes.ok:
+            logger.error(
+                "Failed to get %s at %s, server returned %s.",
+                self.name,
+                self.repository,
+                req.status_code,
+            )
+            return []
+
+        entries: List[Entry] = []
+
+        try:
+            for remote_entry in req.json():
+                tag_id = remote_entry["id"]
+                tag_name = remote_entry["tag_name"]
+                url = remote_entry["html_url"]
+                entries.append(Entry(self.feed_id, tag_id, self.name, tag_name, url))
+        except requests.exceptions.JSONDecodeError as err:
+            logger.error(
+                "Failed to parse entries of project %s: %s", self.name, str(err)
+            )
+        return entries
diff --git a/updates_notifier/fetchers/project_fetcher.py b/updates_notifier/fetchers/project_fetcher.py
new file mode 100644
index 0000000..56cf664
--- /dev/null
+++ b/updates_notifier/fetchers/project_fetcher.py
@@ -0,0 +1,14 @@
+from abc import ABCMeta, abstractmethod
+from typing import List
+
+from ..entry import Entry
+
+
+class ProjectFetcher(metaclass=ABCMeta):
+    def __init__(self, feed_id: int, name: str):
+        self.feed_id = feed_id
+        self.name = name
+
+    @abstractmethod
+    def fetch_entries(self) -> List[Entry]:
+        pass
-- 
GitLab