feat: new git imports (desc, open, is_archived)
This commit is contained in:
parent
533f5079e1
commit
87802db0f4
|
|
@ -339,6 +339,10 @@ 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),
|
||||||
|
"description": repository.description,
|
||||||
|
"open_issues_count": repository.open_issues_count if repository.open_issues_count is not None else 0,
|
||||||
|
"is_archived": bool(repository.is_archived),
|
||||||
|
"topics": repository.topics if repository.topics is not None else [],
|
||||||
"labels": repository.labels if repository.labels is not None else [],
|
"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,
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,7 @@ from __future__ import annotations
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
from uuid import UUID, uuid4
|
from uuid import UUID, uuid4
|
||||||
|
|
||||||
|
import sqlalchemy as sa
|
||||||
from sqlalchemy import JSON, Column
|
from sqlalchemy import JSON, Column
|
||||||
from sqlmodel import Field, Index, SQLModel
|
from sqlmodel import Field, Index, SQLModel
|
||||||
|
|
||||||
|
|
@ -24,13 +25,15 @@ class ForgejoIssue(SQLModel, table=True):
|
||||||
forgejo_issue_number: int = Field(index=True)
|
forgejo_issue_number: int = Field(index=True)
|
||||||
|
|
||||||
title: str
|
title: str
|
||||||
|
body: str | None = Field(default=None, sa_column=Column(sa.Text, nullable=True))
|
||||||
body_preview: str | None = Field(default=None, max_length=1000)
|
body_preview: str | None = Field(default=None, max_length=1000)
|
||||||
state: str = Field(default="open") # open, closed, open
|
state: str = Field(default="open")
|
||||||
is_pull_request: bool = Field(default=False)
|
is_pull_request: bool = Field(default=False)
|
||||||
|
|
||||||
# JSON fields for complex data
|
# JSON fields for complex data
|
||||||
labels: list[dict[str, object]] = Field(default_factory=list, sa_column=Column(JSON))
|
labels: list[dict[str, object]] = Field(default_factory=list, sa_column=Column(JSON))
|
||||||
assignees: list[dict[str, object]] = Field(default_factory=list, sa_column=Column(JSON))
|
assignees: list[dict[str, object]] = Field(default_factory=list, sa_column=Column(JSON))
|
||||||
|
milestone: dict[str, object] | None = Field(default=None, sa_column=Column(JSON, nullable=True))
|
||||||
|
|
||||||
author: str
|
author: str
|
||||||
html_url: str
|
html_url: str
|
||||||
|
|
|
||||||
|
|
@ -29,6 +29,13 @@ 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)
|
||||||
|
description: str | None = Field(default=None)
|
||||||
|
open_issues_count: int = Field(default=0)
|
||||||
|
is_archived: bool = Field(default=False)
|
||||||
|
topics: list[str] = Field(
|
||||||
|
default_factory=list,
|
||||||
|
sa_column=Column(JSON, nullable=False, server_default="[]"),
|
||||||
|
)
|
||||||
labels: list[dict[str, object]] = Field(
|
labels: list[dict[str, object]] = Field(
|
||||||
default_factory=list,
|
default_factory=list,
|
||||||
sa_column=Column(JSON, nullable=False, server_default="[]"),
|
sa_column=Column(JSON, nullable=False, server_default="[]"),
|
||||||
|
|
|
||||||
|
|
@ -14,11 +14,13 @@ class ForgejoIssueBase(SQLModel):
|
||||||
|
|
||||||
forgejo_issue_number: int
|
forgejo_issue_number: int
|
||||||
title: str
|
title: str
|
||||||
|
body: str | None = None
|
||||||
body_preview: str | None = None
|
body_preview: str | None = None
|
||||||
state: str
|
state: str
|
||||||
is_pull_request: bool
|
is_pull_request: bool
|
||||||
labels: list[dict[str, Any]] = []
|
labels: list[dict[str, Any]] = []
|
||||||
assignees: list[dict[str, Any]] = []
|
assignees: list[dict[str, Any]] = []
|
||||||
|
milestone: dict[str, Any] | None = None
|
||||||
author: str
|
author: str
|
||||||
html_url: str
|
html_url: str
|
||||||
forgejo_created_at: datetime
|
forgejo_created_at: datetime
|
||||||
|
|
|
||||||
|
|
@ -108,6 +108,10 @@ class ForgejoRepositoryRead(ForgejoRepositoryBase):
|
||||||
connection_id: UUID
|
connection_id: UUID
|
||||||
connection: ForgejoRepositoryConnectionInfo
|
connection: ForgejoRepositoryConnectionInfo
|
||||||
has_webhook_secret: bool = False
|
has_webhook_secret: bool = False
|
||||||
|
description: str | None = None
|
||||||
|
open_issues_count: int = 0
|
||||||
|
is_archived: bool = False
|
||||||
|
topics: list[str] = Field(default_factory=list)
|
||||||
labels: list[dict[str, object]] = Field(default_factory=list)
|
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
|
||||||
|
|
|
||||||
|
|
@ -79,6 +79,7 @@ class IssueSyncService:
|
||||||
labels_data = []
|
labels_data = []
|
||||||
for label in (issue_data.get("labels") or []):
|
for label in (issue_data.get("labels") or []):
|
||||||
labels_data.append({
|
labels_data.append({
|
||||||
|
"id": label.get("id"),
|
||||||
"name": label.get("name", ""),
|
"name": label.get("name", ""),
|
||||||
"color": label.get("color", ""),
|
"color": label.get("color", ""),
|
||||||
"description": label.get("description", ""),
|
"description": label.get("description", ""),
|
||||||
|
|
@ -93,6 +94,24 @@ class IssueSyncService:
|
||||||
"avatar_url": assignee.get("avatar_url", ""),
|
"avatar_url": assignee.get("avatar_url", ""),
|
||||||
})
|
})
|
||||||
|
|
||||||
|
# Parse milestone
|
||||||
|
milestone_data = None
|
||||||
|
raw_milestone = issue_data.get("milestone")
|
||||||
|
if raw_milestone and isinstance(raw_milestone, dict):
|
||||||
|
milestone_data = {
|
||||||
|
"id": raw_milestone.get("id"),
|
||||||
|
"title": raw_milestone.get("title", ""),
|
||||||
|
"state": raw_milestone.get("state", "open"),
|
||||||
|
"description": raw_milestone.get("description") or None,
|
||||||
|
"due_on": raw_milestone.get("due_on") or None,
|
||||||
|
"closed_at": raw_milestone.get("closed_at") or None,
|
||||||
|
}
|
||||||
|
|
||||||
|
# Full body and preview
|
||||||
|
raw_body = issue_data.get("body") or ""
|
||||||
|
body_full = raw_body if raw_body else None
|
||||||
|
body_preview = raw_body[:1000] if raw_body else None
|
||||||
|
|
||||||
# Parse dates
|
# Parse dates
|
||||||
created_at = self._parse_iso_date(issue_data.get("created_at"))
|
created_at = self._parse_iso_date(issue_data.get("created_at"))
|
||||||
updated_at = self._parse_iso_date(issue_data.get("updated_at"))
|
updated_at = self._parse_iso_date(issue_data.get("updated_at"))
|
||||||
|
|
@ -107,11 +126,13 @@ class IssueSyncService:
|
||||||
repository_id=repository_id,
|
repository_id=repository_id,
|
||||||
forgejo_issue_number=forgejo_number,
|
forgejo_issue_number=forgejo_number,
|
||||||
title=issue_data.get("title", ""),
|
title=issue_data.get("title", ""),
|
||||||
body_preview=(issue_data.get("body") or "")[:1000],
|
body=body_full,
|
||||||
|
body_preview=body_preview,
|
||||||
state=state,
|
state=state,
|
||||||
is_pull_request=False,
|
is_pull_request=False,
|
||||||
labels=labels_data,
|
labels=labels_data,
|
||||||
assignees=assignees_data,
|
assignees=assignees_data,
|
||||||
|
milestone=milestone_data,
|
||||||
author=issue_data.get("user", {}).get("login", ""),
|
author=issue_data.get("user", {}).get("login", ""),
|
||||||
html_url=issue_data.get("html_url", ""),
|
html_url=issue_data.get("html_url", ""),
|
||||||
forgejo_created_at=created_at,
|
forgejo_created_at=created_at,
|
||||||
|
|
@ -123,10 +144,12 @@ class IssueSyncService:
|
||||||
created += 1
|
created += 1
|
||||||
else:
|
else:
|
||||||
existing.title = issue_data.get("title", "")
|
existing.title = issue_data.get("title", "")
|
||||||
existing.body_preview = (issue_data.get("body") or "")[:1000]
|
existing.body = body_full
|
||||||
|
existing.body_preview = body_preview
|
||||||
existing.state = state
|
existing.state = state
|
||||||
existing.labels = labels_data
|
existing.labels = labels_data
|
||||||
existing.assignees = assignees_data
|
existing.assignees = assignees_data
|
||||||
|
existing.milestone = milestone_data
|
||||||
existing.author = issue_data.get("user", {}).get("login", "")
|
existing.author = issue_data.get("user", {}).get("login", "")
|
||||||
existing.html_url = issue_data.get("html_url", "")
|
existing.html_url = issue_data.get("html_url", "")
|
||||||
existing.forgejo_created_at = created_at
|
existing.forgejo_created_at = created_at
|
||||||
|
|
@ -170,6 +193,25 @@ class IssueSyncService:
|
||||||
error=str(exc),
|
error=str(exc),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# Sync repository remote metadata (description, archived, topics, issue count)
|
||||||
|
try:
|
||||||
|
async with get_forgejo_client(connection) as client:
|
||||||
|
repo_meta = await client.get_repository(
|
||||||
|
owner=repository.owner,
|
||||||
|
repo=repository.repo,
|
||||||
|
)
|
||||||
|
repository.description = repo_meta.get("description") or None
|
||||||
|
repository.open_issues_count = int(repo_meta.get("open_issues_count") or 0)
|
||||||
|
repository.is_archived = bool(repo_meta.get("archived", False))
|
||||||
|
raw_topics = repo_meta.get("topics")
|
||||||
|
repository.topics = list(raw_topics) if isinstance(raw_topics, list) else []
|
||||||
|
except Exception as exc:
|
||||||
|
logger.warning(
|
||||||
|
"repo_metadata_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,71 @@
|
||||||
|
"""add body and milestone to issues; description, open_issues_count, is_archived, topics to repos
|
||||||
|
|
||||||
|
Revision ID: b2c3d4e5f6a7
|
||||||
|
Revises: a1b2c3d4e5f7
|
||||||
|
Create Date: 2026-05-19 00:00:00.000000
|
||||||
|
|
||||||
|
"""
|
||||||
|
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
import sqlalchemy as sa
|
||||||
|
from alembic import op
|
||||||
|
|
||||||
|
revision = "b2c3d4e5f6a7"
|
||||||
|
down_revision = "a1b2c3d4e5f7"
|
||||||
|
branch_labels = None
|
||||||
|
depends_on = None
|
||||||
|
|
||||||
|
|
||||||
|
def upgrade() -> None:
|
||||||
|
# forgejo_issues — full body text and milestone JSON
|
||||||
|
op.add_column(
|
||||||
|
"forgejo_issues",
|
||||||
|
sa.Column("body", sa.Text(), nullable=True),
|
||||||
|
)
|
||||||
|
op.add_column(
|
||||||
|
"forgejo_issues",
|
||||||
|
sa.Column("milestone", sa.JSON(), nullable=True),
|
||||||
|
)
|
||||||
|
|
||||||
|
# forgejo_repositories — remote metadata fields
|
||||||
|
op.add_column(
|
||||||
|
"forgejo_repositories",
|
||||||
|
sa.Column("description", sa.String(), nullable=True),
|
||||||
|
)
|
||||||
|
op.add_column(
|
||||||
|
"forgejo_repositories",
|
||||||
|
sa.Column(
|
||||||
|
"open_issues_count",
|
||||||
|
sa.Integer(),
|
||||||
|
nullable=False,
|
||||||
|
server_default="0",
|
||||||
|
),
|
||||||
|
)
|
||||||
|
op.add_column(
|
||||||
|
"forgejo_repositories",
|
||||||
|
sa.Column(
|
||||||
|
"is_archived",
|
||||||
|
sa.Boolean(),
|
||||||
|
nullable=False,
|
||||||
|
server_default="false",
|
||||||
|
),
|
||||||
|
)
|
||||||
|
op.add_column(
|
||||||
|
"forgejo_repositories",
|
||||||
|
sa.Column(
|
||||||
|
"topics",
|
||||||
|
sa.JSON(),
|
||||||
|
nullable=False,
|
||||||
|
server_default="[]",
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def downgrade() -> None:
|
||||||
|
op.drop_column("forgejo_repositories", "topics")
|
||||||
|
op.drop_column("forgejo_repositories", "is_archived")
|
||||||
|
op.drop_column("forgejo_repositories", "open_issues_count")
|
||||||
|
op.drop_column("forgejo_repositories", "description")
|
||||||
|
op.drop_column("forgejo_issues", "milestone")
|
||||||
|
op.drop_column("forgejo_issues", "body")
|
||||||
|
|
@ -44,6 +44,10 @@ export interface ForgejoRepository {
|
||||||
default_branch: string;
|
default_branch: string;
|
||||||
active: boolean;
|
active: boolean;
|
||||||
has_webhook_secret: boolean;
|
has_webhook_secret: boolean;
|
||||||
|
description: string | null;
|
||||||
|
open_issues_count: number;
|
||||||
|
is_archived: boolean;
|
||||||
|
topics: string[];
|
||||||
labels: ForgejoRepoLabel[];
|
labels: ForgejoRepoLabel[];
|
||||||
connection: ForgejoConnection;
|
connection: ForgejoConnection;
|
||||||
last_sync_at: string | null;
|
last_sync_at: string | null;
|
||||||
|
|
@ -258,17 +262,28 @@ export interface ForgejoIssueLabel {
|
||||||
description?: string | null;
|
description?: string | null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface ForgejoIssueMilestone {
|
||||||
|
id: number | null;
|
||||||
|
title: string;
|
||||||
|
state: string;
|
||||||
|
description: string | null;
|
||||||
|
due_on: string | null;
|
||||||
|
closed_at: string | null;
|
||||||
|
}
|
||||||
|
|
||||||
export interface ForgejoIssue {
|
export interface ForgejoIssue {
|
||||||
id: string;
|
id: string;
|
||||||
organization_id: string;
|
organization_id: string;
|
||||||
repository_id: string;
|
repository_id: string;
|
||||||
forgejo_issue_number: number;
|
forgejo_issue_number: number;
|
||||||
title: string;
|
title: string;
|
||||||
|
body: string | null;
|
||||||
body_preview: string | null;
|
body_preview: string | null;
|
||||||
state: string;
|
state: string;
|
||||||
is_pull_request: boolean;
|
is_pull_request: boolean;
|
||||||
labels: ForgejoIssueLabel[];
|
labels: ForgejoIssueLabel[];
|
||||||
assignees: Record<string, unknown>[];
|
assignees: Record<string, unknown>[];
|
||||||
|
milestone: ForgejoIssueMilestone | null;
|
||||||
author: string;
|
author: string;
|
||||||
html_url: string;
|
html_url: string;
|
||||||
forgejo_created_at: string;
|
forgejo_created_at: string;
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue