Fix Forgejo issue lifecycle identifiers
All checks were successful
CI Smoke / host-smoke (push) Successful in 0s
CI Smoke / container-smoke (push) Successful in 1s
Build and Publish Container Image / build-and-push (push) Successful in 38s

This commit is contained in:
tegwick 2026-08-19 23:04:04 +02:00
parent d58bfd1f96
commit 3523a7decc
3 changed files with 33 additions and 2 deletions

View file

@ -49,7 +49,7 @@
| task | ISSUE-WP-0006-T04 | todo | — | workplans/ISSUE-WP-0006-forgejo-only-projection-boundary.md |
| task | ISSUE-WP-0007-T00 | done | — | workplans/ISSUE-WP-0007-rapp-issue-core-railiance01-migration.md |
| task | ISSUE-WP-0007-T01 | done | — | workplans/ISSUE-WP-0007-rapp-issue-core-railiance01-migration.md |
| task | ISSUE-WP-0007-T02 | todo | — | workplans/ISSUE-WP-0007-rapp-issue-core-railiance01-migration.md |
| task | ISSUE-WP-0007-T02 | progress | — | workplans/ISSUE-WP-0007-rapp-issue-core-railiance01-migration.md |
| task | ISSUE-WP-0007-T03 | todo | — | workplans/ISSUE-WP-0007-rapp-issue-core-railiance01-migration.md |
| task | ISSUE-WP-0007-T04 | todo | — | workplans/ISSUE-WP-0007-rapp-issue-core-railiance01-migration.md |
| task | ISSUE-WP-0007-T05 | todo | — | workplans/ISSUE-WP-0007-rapp-issue-core-railiance01-migration.md |

View file

@ -113,6 +113,21 @@ def _mapping_backend_name(backend_type: str) -> str:
return "sqlite" if backend_type == "local" else backend_type
def _public_issue_id(issue: Issue, backend_type: str) -> str:
"""Return the identifier accepted by the backend's issue routes.
Forgejo/Gitea exposes both a database-wide ``id`` and a repository-local
issue ``number``. Its issue CRUD routes address the latter, so returning
the database ID from ingestion makes the documented POST -> PATCH lifecycle
fail with 404. Local backends continue to expose their native string ID.
"""
if backend_type in {"gitea", "github"} and issue.number:
return str(issue.number)
if issue.id:
return issue.id
return str(issue.number)
def _upsert_mapping_if_requested(
payload: TaskIngestionRequest,
*,
@ -184,7 +199,7 @@ async def ingest_task(payload: TaskIngestionRequest) -> TaskIngestionResponse:
except Exception:
pass
issue_id = created.id or str(created.number)
issue_id = _public_issue_id(created, backend_type)
issue_url: Optional[str] = None
if created.sync_metadata:
issue_url = created.sync_metadata.get("url") or created.sync_metadata.get("html_url")

View file

@ -6,6 +6,7 @@ import os
import tempfile
import uuid
from pathlib import Path
from types import SimpleNamespace
import pytest
@ -15,6 +16,7 @@ pytest.importorskip("httpx")
from fastapi.testclient import TestClient
from issue_core.api.app import create_app
from issue_core.api.ingest import _public_issue_id
API_KEY = "test-key-not-a-real-secret-only-for-pytest"
@ -75,6 +77,20 @@ def test_healthz(client):
assert response.json()["status"] == "ok"
@pytest.mark.unit
def test_public_issue_id_uses_repository_number_for_gitea():
issue = SimpleNamespace(id="91234", number=176)
assert _public_issue_id(issue, "gitea") == "176"
@pytest.mark.unit
def test_public_issue_id_preserves_native_local_id():
issue = SimpleNamespace(id="2c29792e-1234-4567-890a-22c4fa664abc", number=12)
assert _public_issue_id(issue, "local") == issue.id
@pytest.mark.unit
def test_ingest_rejects_missing_api_key(client, valid_payload):
response = client.post("/issues/", json=valid_payload)