Fix server threading, tag URLs, and tag date resolution

- Switch to ThreadingHTTPServer to handle concurrent requests
- Catch BrokenPipeError on response writes to suppress noisy tracebacks
- Change tag URL from /tags/ to /releases/tag/
- Resolve tag dates via commit SHA from tags API + commits endpoint (works for public repos without auth)
- Update tests to match new tag date resolution approach
This commit is contained in:
2026-07-28 12:25:04 +02:00
parent 7aeecc1e15
commit e1bd1ad9eb
4 changed files with 39 additions and 54 deletions
+2 -2
View File
@@ -307,11 +307,11 @@ def cmd_serve(args: argparse.Namespace, db_path: str) -> None:
port = args.port or DEFAULT_SERVER_PORT
from src.server import create_handler
from http.server import HTTPServer
from http.server import ThreadingHTTPServer
handler = create_handler(db_path)
try:
server = HTTPServer((host, port), handler)
server = ThreadingHTTPServer((host, port), handler)
except OSError as e:
if e.errno == 98: # Address already in use
error(f"Port {port} is already in use")
+11 -21
View File
@@ -117,40 +117,30 @@ class GitHubClient:
result = []
for tag in data:
tag_name = tag["name"]
published_at = self._get_tag_date(owner_repo, tag_name)
commit_sha = tag.get("commit", {}).get("sha")
published_at = self._get_tag_date(owner_repo, commit_sha)
result.append({
"tag_name": tag_name,
"title": tag_name,
"body": "",
"published_at": published_at,
"html_url": f"https://github.com/{owner_repo}/tags/{tag_name}",
"html_url": f"https://github.com/{owner_repo}/releases/tag/{tag_name}",
})
return result
def _get_tag_date(self, owner_repo: str, tag_name: str) -> str:
"""Get the commit date for a tag by resolving the git ref."""
def _get_tag_date(self, owner_repo: str, commit_sha: str | None) -> str:
"""Get the commit date for a tag using the commit SHA from tags API."""
if not commit_sha:
return datetime.now(timezone.utc).isoformat()
try:
resp = self._request(
"GET",
f"{self.BASE_URL}/repos/{owner_repo}/git/ref/tags/{tag_name}",
f"{self.BASE_URL}/repos/{owner_repo}/commits/{commit_sha}",
)
data = resp.json()
# The ref may point to a commit directly or to a tag object
obj = data.get("object", {})
obj_type = obj.get("type")
if obj_type == "commit":
author_date = obj.get("author", {}).get("date")
if author_date:
return author_date
elif obj_type == "tag":
# Follow the tag object to get the commit
commit_sha = obj.get("sha")
if commit_sha:
commit_resp = self._request("GET", f"{self.BASE_URL}/repos/{owner_repo}/git/commits/{commit_sha}")
commit_data = commit_resp.json()
author_date = commit_data.get("author", {}).get("date")
if author_date:
return author_date
author_date = data.get("commit", {}).get("author", {}).get("date")
if author_date:
return author_date
except Exception:
pass
return datetime.now(timezone.utc).isoformat()
+12 -3
View File
@@ -39,20 +39,29 @@ def create_handler(db_path: str):
self.send_response(200)
self.send_header("Content-Type", "application/rss+xml; charset=utf-8")
self.end_headers()
self.wfile.write(feed_xml.encode("utf-8"))
try:
self.wfile.write(feed_xml.encode("utf-8"))
except BrokenPipeError:
pass
def _serve_index(self):
html = generate_index_html(self._base_url())
self.send_response(200)
self.send_header("Content-Type", "text/html; charset=utf-8")
self.end_headers()
self.wfile.write(html.encode("utf-8"))
try:
self.wfile.write(html.encode("utf-8"))
except BrokenPipeError:
pass
def _serve_health(self):
self.send_response(200)
self.send_header("Content-Type", "text/plain")
self.end_headers()
self.wfile.write(b"OK")
try:
self.wfile.write(b"OK")
except BrokenPipeError:
pass
def _base_url(self) -> str:
host = self.server.server_address[0]