76 lines
4.1 KiB
Python
76 lines
4.1 KiB
Python
"""Branch je Chat und seine Commits (→ Git-Workflow: Chat = Branch, Mensch erstellt den PR).
|
|
|
|
Die KI committet frei auf den Branch ihres Chats. Die Commits liegen im Klon der
|
|
Plattform, bis ein Mensch „Branch pushen“ oder „Pull Request erstellen“ wählt.
|
|
Je Commit sind die Änderungen gespeichert, damit sich der Branch nach einem Verlust
|
|
des Klons exakt nachbauen lässt (fester Zeitpunkt, gleicher Inhalt → gleicher Commit).
|
|
"""
|
|
|
|
import uuid
|
|
from datetime import datetime
|
|
from typing import Any
|
|
|
|
from sqlalchemy import JSON, BigInteger, ForeignKey, Identity, Index, String, Text, Uuid, text
|
|
from sqlalchemy.orm import Mapped, mapped_column
|
|
|
|
from app.core.database import Base, now
|
|
|
|
OPEN, MERGED, DECLINED = "OPEN", "MERGED", "DECLINED"
|
|
|
|
|
|
class ChatBranch(Base):
|
|
__tablename__ = "chat_branches"
|
|
# Je Chat und Quelle höchstens ein aktiver Branch; nach Merge oder Ablehnung beginnt ein neuer
|
|
__table_args__ = (Index("uq_chat_branches_active", "chat_session_id", "source_id", unique=True,
|
|
postgresql_where=text("closed IS NULL")),)
|
|
|
|
id: Mapped[int] = mapped_column(primary_key=True)
|
|
workspace_id: Mapped[int] = mapped_column(ForeignKey("workspaces.id", ondelete="CASCADE"), index=True)
|
|
chat_session_id: Mapped[int] = mapped_column(ForeignKey("chat_sessions.id", ondelete="CASCADE"), index=True)
|
|
source_id: Mapped[int] = mapped_column(ForeignKey("data_sources.id", ondelete="CASCADE"), index=True)
|
|
name: Mapped[str] = mapped_column(String(250)) # ai/c<chat>-<titel>
|
|
target: Mapped[str] = mapped_column(String(250)) # Ziel-Branch der Quelle beim Anlegen
|
|
base: Mapped[str] = mapped_column(String(40)) # Ausgangs-Commit
|
|
head: Mapped[str] = mapped_column(String(40)) # aktueller Stand in der Plattform
|
|
pushed: Mapped[str | None] = mapped_column(String(40)) # zuletzt übertragener Stand
|
|
pr_id: Mapped[str | None] = mapped_column(String(40))
|
|
pr_url: Mapped[str | None] = mapped_column(Text)
|
|
pr_state: Mapped[str] = mapped_column(String(20), default="") # OPEN | MERGED | DECLINED
|
|
pr_draft: Mapped[bool] = mapped_column(default=False)
|
|
# Zuletzt gesehener Stand aus Bitbucket: Version, Kommentare, Reviewer
|
|
pr_info: Mapped[dict[str, Any]] = mapped_column(JSON, default=dict)
|
|
pr_checked: Mapped[datetime | None]
|
|
closed: Mapped[datetime | None] # PR gemergt oder abgelehnt: keine weiteren Commits
|
|
created_by: Mapped[int | None] = mapped_column(ForeignKey("users.id", ondelete="SET NULL"))
|
|
created: Mapped[datetime] = mapped_column(default=now)
|
|
updated: Mapped[datetime] = mapped_column(default=now)
|
|
|
|
@property
|
|
def ref(self) -> str:
|
|
"""Lokale Referenz im Klon; hält die Commits gegen Aufräumen durch git gc fest."""
|
|
return f"refs/aiw/branch-{self.id}"
|
|
|
|
@property
|
|
def unpushed(self) -> bool:
|
|
return self.head != self.pushed and self.head != self.base
|
|
|
|
|
|
class BranchCommit(Base):
|
|
__tablename__ = "branch_commits"
|
|
|
|
id: Mapped[int] = mapped_column(BigInteger, Identity(), primary_key=True)
|
|
branch_id: Mapped[int] = mapped_column(ForeignKey("chat_branches.id", ondelete="CASCADE"), index=True)
|
|
sha: Mapped[str] = mapped_column(String(40))
|
|
parent: Mapped[str] = mapped_column(String(40))
|
|
# Merge-Commit „Mit Ziel-Branch abgleichen“: zweiter Elternteil (Stand des Ziel-Branches); changes sind
|
|
# dann die Konfliktlösungen
|
|
merged: Mapped[str | None] = mapped_column(String(40))
|
|
message: Mapped[str] = mapped_column(Text)
|
|
# Geprüfte Änderungen und Zeitpunkt: daraus entsteht der Commit erneut
|
|
changes: Mapped[list[dict[str, Any]]] = mapped_column(JSON)
|
|
date: Mapped[str] = mapped_column(String(40))
|
|
files: Mapped[list[str]] = mapped_column(JSON, default=list)
|
|
# Hinweise der statischen Prüfung (Syntax), z. B. "a.py:3: Python-Syntaxfehler: …"; der Commit entsteht trotzdem
|
|
warnings: Mapped[list[str]] = mapped_column(JSON, default=list, server_default="[]")
|
|
run_id: Mapped[uuid.UUID | None] = mapped_column(Uuid, ForeignKey("task_runs.id", ondelete="SET NULL"))
|
|
created: Mapped[datetime] = mapped_column(default=now)
|