feat: git label import
This commit is contained in:
parent
d6d094a67d
commit
017ab4951a
|
|
@ -339,6 +339,7 @@ def _mask_repository(repository: ForgejoRepository, connection: ForgejoConnectio
|
||||||
"active": repository.active,
|
"active": repository.active,
|
||||||
"connection": _create_connection_info(connection) if connection is not None else None,
|
"connection": _create_connection_info(connection) if connection is not None else None,
|
||||||
"has_webhook_secret": bool(repository.webhook_secret),
|
"has_webhook_secret": bool(repository.webhook_secret),
|
||||||
|
"labels": repository.labels if repository.labels is not None else [],
|
||||||
"last_sync_at": repository.last_sync_at,
|
"last_sync_at": repository.last_sync_at,
|
||||||
"last_sync_error": repository.last_sync_error,
|
"last_sync_error": repository.last_sync_error,
|
||||||
"created_at": repository.created_at,
|
"created_at": repository.created_at,
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,8 @@ from __future__ import annotations
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
from uuid import UUID, uuid4
|
from uuid import UUID, uuid4
|
||||||
|
|
||||||
|
from sqlalchemy import Column
|
||||||
|
from sqlalchemy import JSON
|
||||||
from sqlmodel import Field
|
from sqlmodel import Field
|
||||||
|
|
||||||
from app.core.time import utcnow
|
from app.core.time import utcnow
|
||||||
|
|
@ -27,6 +29,10 @@ class ForgejoRepository(QueryModel, table=True):
|
||||||
default_branch: str = Field(default="main")
|
default_branch: str = Field(default="main")
|
||||||
active: bool = Field(default=True)
|
active: bool = Field(default=True)
|
||||||
webhook_secret: str | None = Field(default=None)
|
webhook_secret: str | None = Field(default=None)
|
||||||
|
labels: list[dict[str, object]] = Field(
|
||||||
|
default_factory=list,
|
||||||
|
sa_column=Column(JSON, nullable=False, server_default="[]"),
|
||||||
|
)
|
||||||
last_sync_at: datetime | None = Field(default=None)
|
last_sync_at: datetime | None = Field(default=None)
|
||||||
last_sync_error: str | None = Field(default=None)
|
last_sync_error: str | None = Field(default=None)
|
||||||
created_at: datetime = Field(default_factory=utcnow)
|
created_at: datetime = Field(default_factory=utcnow)
|
||||||
|
|
|
||||||
|
|
@ -108,6 +108,7 @@ class ForgejoRepositoryRead(ForgejoRepositoryBase):
|
||||||
connection_id: UUID
|
connection_id: UUID
|
||||||
connection: ForgejoRepositoryConnectionInfo
|
connection: ForgejoRepositoryConnectionInfo
|
||||||
has_webhook_secret: bool = False
|
has_webhook_secret: bool = False
|
||||||
|
labels: list[dict[str, object]] = Field(default_factory=list)
|
||||||
last_sync_at: datetime | None
|
last_sync_at: datetime | None
|
||||||
last_sync_error: str | None
|
last_sync_error: str | None
|
||||||
created_at: datetime
|
created_at: datetime
|
||||||
|
|
|
||||||
|
|
@ -157,6 +157,32 @@ class ForgejoAPIClient:
|
||||||
response.raise_for_status()
|
response.raise_for_status()
|
||||||
return response.json()
|
return response.json()
|
||||||
|
|
||||||
|
async def list_labels(
|
||||||
|
self,
|
||||||
|
owner: str,
|
||||||
|
repo: str,
|
||||||
|
limit: int = 50,
|
||||||
|
) -> list[dict[str, object]]:
|
||||||
|
"""
|
||||||
|
List all labels defined on a repository.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
owner: Repository owner
|
||||||
|
repo: Repository name
|
||||||
|
limit: Max labels to fetch per page
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
List of label dicts with id, name, color, description.
|
||||||
|
"""
|
||||||
|
client = await self._get_client()
|
||||||
|
response = await client.get(
|
||||||
|
f"/api/v1/repos/{owner}/{repo}/labels",
|
||||||
|
params={"limit": limit, "page": 1},
|
||||||
|
)
|
||||||
|
response.raise_for_status()
|
||||||
|
data = response.json()
|
||||||
|
return list(data) if isinstance(data, list) else []
|
||||||
|
|
||||||
async def list_user_repos(
|
async def list_user_repos(
|
||||||
self,
|
self,
|
||||||
limit: int = 50,
|
limit: int = 50,
|
||||||
|
|
|
||||||
|
|
@ -146,6 +146,30 @@ class IssueSyncService:
|
||||||
break
|
break
|
||||||
current_page += 1
|
current_page += 1
|
||||||
|
|
||||||
|
# Sync repository label catalog
|
||||||
|
try:
|
||||||
|
async with get_forgejo_client(connection) as client:
|
||||||
|
fetched_labels = await client.list_labels(
|
||||||
|
owner=repository.owner,
|
||||||
|
repo=repository.repo,
|
||||||
|
)
|
||||||
|
repository.labels = [
|
||||||
|
{
|
||||||
|
"id": lbl.get("id"),
|
||||||
|
"name": lbl.get("name", ""),
|
||||||
|
"color": lbl.get("color", ""),
|
||||||
|
"description": lbl.get("description") or "",
|
||||||
|
}
|
||||||
|
for lbl in fetched_labels
|
||||||
|
if lbl.get("name")
|
||||||
|
]
|
||||||
|
except Exception as exc:
|
||||||
|
logger.warning(
|
||||||
|
"label_sync_failed",
|
||||||
|
repository_id=str(repository_id),
|
||||||
|
error=str(exc),
|
||||||
|
)
|
||||||
|
|
||||||
# Update repository sync metadata
|
# Update repository sync metadata
|
||||||
repository.last_sync_at = utcnow()
|
repository.last_sync_at = utcnow()
|
||||||
repository.last_sync_error = None
|
repository.last_sync_error = None
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,33 @@
|
||||||
|
"""add labels column to forgejo_repositories
|
||||||
|
|
||||||
|
Revision ID: a1b2c3d4e5f7
|
||||||
|
Revises: f5a2b3c4d5e6
|
||||||
|
Create Date: 2026-05-19 00:00:00.000000
|
||||||
|
|
||||||
|
"""
|
||||||
|
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
import sqlalchemy as sa
|
||||||
|
from alembic import op
|
||||||
|
|
||||||
|
revision = "a1b2c3d4e5f7"
|
||||||
|
down_revision = "f5a2b3c4d5e6"
|
||||||
|
branch_labels = None
|
||||||
|
depends_on = None
|
||||||
|
|
||||||
|
|
||||||
|
def upgrade() -> None:
|
||||||
|
op.add_column(
|
||||||
|
"forgejo_repositories",
|
||||||
|
sa.Column(
|
||||||
|
"labels",
|
||||||
|
sa.JSON(),
|
||||||
|
nullable=False,
|
||||||
|
server_default="[]",
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def downgrade() -> None:
|
||||||
|
op.drop_column("forgejo_repositories", "labels")
|
||||||
|
|
@ -27,6 +27,13 @@ export interface ForgejoConnectionUpdate {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Forgejo Repository types
|
// Forgejo Repository types
|
||||||
|
export interface ForgejoRepoLabel {
|
||||||
|
id: number | null;
|
||||||
|
name: string;
|
||||||
|
color: string;
|
||||||
|
description: string;
|
||||||
|
}
|
||||||
|
|
||||||
export interface ForgejoRepository {
|
export interface ForgejoRepository {
|
||||||
id: string;
|
id: string;
|
||||||
organization_id: string;
|
organization_id: string;
|
||||||
|
|
@ -37,6 +44,7 @@ export interface ForgejoRepository {
|
||||||
default_branch: string;
|
default_branch: string;
|
||||||
active: boolean;
|
active: boolean;
|
||||||
has_webhook_secret: boolean;
|
has_webhook_secret: boolean;
|
||||||
|
labels: ForgejoRepoLabel[];
|
||||||
connection: ForgejoConnection;
|
connection: ForgejoConnection;
|
||||||
last_sync_at: string | null;
|
last_sync_at: string | null;
|
||||||
last_sync_error: string | null;
|
last_sync_error: string | null;
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue