feat: récupération cachée des issues roadmap GitHub #94
This commit is contained in:
@@ -0,0 +1,36 @@
|
|||||||
|
import httpx
|
||||||
|
|
||||||
|
from src.utils.cache import cache
|
||||||
|
|
||||||
|
GITHUB_REPO = "ColinMaudry/decp.info"
|
||||||
|
_LABEL_KEYS = {"en cours": "en_cours", "mis au vote": "au_vote"}
|
||||||
|
|
||||||
|
|
||||||
|
@cache.memoize(timeout=3600)
|
||||||
|
def fetch_roadmap_issues() -> dict[str, list[dict]]:
|
||||||
|
"""Issues ouvertes du dépôt portant un label de roadmap, regroupées par label.
|
||||||
|
|
||||||
|
Appel anonyme à l'API GitHub publique. Mis en cache 1 h.
|
||||||
|
"""
|
||||||
|
resp = httpx.get(
|
||||||
|
f"https://api.github.com/repos/{GITHUB_REPO}/issues",
|
||||||
|
params={"state": "open", "per_page": 100},
|
||||||
|
headers={"Accept": "application/vnd.github+json"},
|
||||||
|
timeout=10,
|
||||||
|
)
|
||||||
|
resp.raise_for_status()
|
||||||
|
result: dict[str, list[dict]] = {"en_cours": [], "au_vote": []}
|
||||||
|
for issue in resp.json():
|
||||||
|
if "pull_request" in issue:
|
||||||
|
continue # l'endpoint /issues inclut les PR
|
||||||
|
labels = {lbl["name"] for lbl in issue.get("labels", [])}
|
||||||
|
for label, key in _LABEL_KEYS.items():
|
||||||
|
if label in labels:
|
||||||
|
result[key].append(
|
||||||
|
{
|
||||||
|
"number": issue["number"],
|
||||||
|
"title": issue["title"],
|
||||||
|
"html_url": issue["html_url"],
|
||||||
|
}
|
||||||
|
)
|
||||||
|
return result
|
||||||
@@ -0,0 +1,53 @@
|
|||||||
|
from src.roadmap import github
|
||||||
|
|
||||||
|
|
||||||
|
class _FakeResp:
|
||||||
|
def __init__(self, payload):
|
||||||
|
self._payload = payload
|
||||||
|
|
||||||
|
def raise_for_status(self):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def json(self):
|
||||||
|
return self._payload
|
||||||
|
|
||||||
|
|
||||||
|
_ISSUES = [
|
||||||
|
{
|
||||||
|
"number": 10,
|
||||||
|
"title": "Feature en cours",
|
||||||
|
"html_url": "https://github.com/ColinMaudry/decp.info/issues/10",
|
||||||
|
"labels": [{"name": "en cours"}],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"number": 20,
|
||||||
|
"title": "Feature au vote",
|
||||||
|
"html_url": "https://github.com/ColinMaudry/decp.info/issues/20",
|
||||||
|
"labels": [{"name": "mis au vote"}],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"number": 30,
|
||||||
|
"title": "Issue sans label pertinent",
|
||||||
|
"html_url": "https://github.com/ColinMaudry/decp.info/issues/30",
|
||||||
|
"labels": [{"name": "bug"}],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"number": 40,
|
||||||
|
"title": "Une PR déguisée en issue",
|
||||||
|
"html_url": "https://github.com/ColinMaudry/decp.info/pull/40",
|
||||||
|
"labels": [{"name": "mis au vote"}],
|
||||||
|
"pull_request": {"url": "..."},
|
||||||
|
},
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
def test_fetch_roadmap_issues_filters_by_label(monkeypatch):
|
||||||
|
monkeypatch.setattr(github.httpx, "get", lambda *a, **k: _FakeResp(_ISSUES))
|
||||||
|
result = github.fetch_roadmap_issues.uncached()
|
||||||
|
assert [i["number"] for i in result["en_cours"]] == [10]
|
||||||
|
assert [i["number"] for i in result["au_vote"]] == [20] # PR #40 exclue
|
||||||
|
assert result["en_cours"][0] == {
|
||||||
|
"number": 10,
|
||||||
|
"title": "Feature en cours",
|
||||||
|
"html_url": "https://github.com/ColinMaudry/decp.info/issues/10",
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user