Prepare deployment and Forgejo CI
Some checks failed
CI / check (push) Failing after 8s

This commit is contained in:
kacper 2026-04-14 20:17:29 -04:00
parent 51706d2d11
commit 853e99ca5f
21 changed files with 1402 additions and 77 deletions

View file

@ -167,7 +167,7 @@ class AppTestCase(unittest.TestCase):
fake_client = _FakeForgejoClient(user={"login": "kacper"})
with (
patch("prototype_cache.build_live_prototype_payload", new=builder),
patch("app.ForgejoClient", return_value=fake_client),
patch("app.ForgejoClient", return_value=fake_client) as client_factory,
):
response = self.client.get(
"/api/prototype",
@ -181,6 +181,38 @@ class AppTestCase(unittest.TestCase):
self.assertEqual(response_payload["auth"]["authenticated"], True)
self.assertEqual(response_payload["auth"]["login"], "kacper")
self.assertEqual(response_payload["auth"]["source"], "authorization")
self.assertEqual(client_factory.call_args.kwargs["auth_scheme"], "token")
def test_prototype_preserves_bearer_authorization_scheme(self) -> None:
payload = {
"hero": {"title": "Robot U"},
"auth": {
"authenticated": False,
"login": None,
"source": "none",
"can_reply": False,
"oauth_configured": True,
},
"featured_courses": [],
"recent_posts": [],
"recent_discussions": [],
"upcoming_events": [],
"source_of_truth": [],
}
builder = AsyncMock(return_value=payload)
fake_client = _FakeForgejoClient(user={"login": "kacper"})
with (
patch("prototype_cache.build_live_prototype_payload", new=builder),
patch("app.ForgejoClient", return_value=fake_client) as client_factory,
):
response = self.client.get(
"/api/prototype",
headers={"Authorization": "Bearer oauth-token"},
)
self.assertEqual(response.status_code, 200)
self.assertEqual(client_factory.call_args.kwargs["forgejo_token"], "oauth-token")
self.assertEqual(client_factory.call_args.kwargs["auth_scheme"], "Bearer")
def test_prototype_can_use_server_token_without_user_session(self) -> None:
payload = {
@ -378,7 +410,7 @@ class AppTestCase(unittest.TestCase):
"updated_at": "2026-04-11T12:00:00Z",
"html_url": "https://aksal.cloud/Robot-U/robot-u-site/issues/9",
"user": {"login": "Kacper", "avatar_url": ""},
"labels": [],
"labels": [{"name": "discussion"}],
"state": "open",
},
comments=[
@ -400,6 +432,26 @@ class AppTestCase(unittest.TestCase):
self.assertEqual(payload["comments"][0]["body"], "Reply body")
self.assertEqual(payload["links"][0]["kind"], "post")
def test_discussion_detail_rejects_issue_without_discussion_label(self) -> None:
fake_client = _FakeForgejoClient(
issue={
"id": 456,
"number": 9,
"title": "Encoder math question",
"body": "Regular issue",
"comments": 0,
"updated_at": "2026-04-11T12:00:00Z",
"html_url": "https://aksal.cloud/Robot-U/robot-u-site/issues/9",
"user": {"login": "Kacper", "avatar_url": ""},
"labels": [],
"state": "open",
},
)
with patch("app.ForgejoClient", return_value=fake_client):
response = self.client.get("/api/discussions/Robot-U/robot-u-site/9")
self.assertEqual(response.status_code, 404)
def test_create_discussion_reply_invalidates_prototype_cache(self) -> None:
initial_payload = {
"hero": {"title": "Before"},
@ -496,6 +548,7 @@ class AppTestCase(unittest.TestCase):
)
self.assertEqual(payload["id"], 456)
self.assertEqual(payload["repo"], "Robot-U/robot-u-site")
self.assertEqual(payload["labels"], ["discussion"])
self.assertEqual(payload["links"][0]["kind"], "post")
def test_create_general_discussion_uses_configured_repo(self) -> None:
@ -532,6 +585,7 @@ class AppTestCase(unittest.TestCase):
fake_client.created_issue,
("Robot-U", "community", "General project help", "I need help choosing motors."),
)
self.assertEqual(fake_client.created_issue_labels, [123])
def test_create_discussion_rejects_server_token_fallback(self) -> None:
get_settings.cache_clear()
@ -583,6 +637,7 @@ class AppTestCase(unittest.TestCase):
self.assertEqual(response.status_code, 200)
self.assertEqual(client_factory.call_args.kwargs["forgejo_token"], "oauth-token")
self.assertEqual(client_factory.call_args.kwargs["auth_scheme"], "Bearer")
self.assertEqual(
reply_client.created_comment, ("Robot-U", "RobotClass", 2, "Thanks, this helped.")
)
@ -638,6 +693,7 @@ class _FakeForgejoClient:
self._repo_private = repo_private
self.created_comment: tuple[str, str, int, str] | None = None
self.created_issue: tuple[str, str, str, str] | None = None
self.created_issue_labels: list[int] | None = None
self.exchanged_code: str | None = None
async def __aenter__(self) -> _FakeForgejoClient:
@ -664,12 +720,27 @@ class _FakeForgejoClient:
repo: str,
title: str,
body: str,
label_ids: list[int] | None = None,
) -> dict[str, object]:
self.created_issue = (owner, repo, title, body)
self.created_issue_labels = label_ids
if self._issue is None:
raise AssertionError("Fake issue was not configured.")
return self._issue
async def ensure_repo_label(
self,
_owner: str,
_repo: str,
_name: str,
*,
color: str,
description: str,
) -> int:
assert color
assert description
return 123
async def fetch_issue(self, _owner: str, _repo: str, _issue_number: int) -> dict[str, object]:
if self._issue is None:
raise AssertionError("Fake issue was not configured.")

View file

@ -3,7 +3,13 @@ from __future__ import annotations
import unittest
from typing import Any
from live_prototype import _post_card, _summarize_repo, discussion_links_from_text
from live_prototype import (
_post_card,
_summarize_repo,
discussion_card_from_issue,
discussion_links_from_text,
issue_has_discussion_label,
)
class LivePrototypeTestCase(unittest.IsolatedAsyncioTestCase):
@ -16,7 +22,10 @@ class LivePrototypeTestCase(unittest.IsolatedAsyncioTestCase):
"full_name": "Robot-U/robot-u-site",
"description": "Robot U site source",
"updated_at": "2026-04-13T00:00:00Z",
"owner": {"login": "Robot-U"},
"owner": {
"login": "Robot-U",
"avatar_url": "https://aksal.cloud/avatars/robot-u.png",
},
},
)
@ -25,6 +34,7 @@ class LivePrototypeTestCase(unittest.IsolatedAsyncioTestCase):
self.assertEqual(summary["blog_count"], 1)
post = _post_card(summary["blog_posts"][0])
self.assertEqual(post["title"], "Building Robot U")
self.assertEqual(post["owner_avatar_url"], "https://aksal.cloud/avatars/robot-u.png")
self.assertEqual(post["slug"], "building-robot-u-site")
self.assertEqual(post["repo"], "Robot-U/robot-u-site")
self.assertEqual(post["path"], "blogs/building-robot-u-site")
@ -49,6 +59,29 @@ class LivePrototypeTestCase(unittest.IsolatedAsyncioTestCase):
self.assertEqual(links[1]["kind"], "post")
self.assertEqual(links[1]["path"], "/posts/Robot-U/robot-u-site/building-robot-u-site")
def test_discussion_card_exposes_created_at(self) -> None:
card = discussion_card_from_issue(
{
"id": 42,
"number": 7,
"title": "Encoder count issue",
"body": "The count jumps when the motor turns.",
"comments": 3,
"created_at": "2026-04-12T10:00:00Z",
"updated_at": "2026-04-13T10:00:00Z",
"repository": {"full_name": "Robot-U/general_forum"},
"user": {"login": "kacper", "avatar_url": "https://aksal.cloud/avatar.png"},
},
)
self.assertEqual(card["created_at"], "2026-04-12T10:00:00Z")
def test_discussion_label_detection_is_case_insensitive(self) -> None:
self.assertTrue(
issue_has_discussion_label({"labels": [{"name": "Discussion"}, {"name": "bug"}]})
)
self.assertFalse(issue_has_discussion_label({"labels": [{"name": "question"}]}))
class _FakeContentClient:
async def list_directory(