fix(git): default branch convention main -> master

This commit is contained in:
Renn F
2026-06-03 19:18:42 +02:00
parent 2bb83c96a3
commit 5afe87716c
5 changed files with 149 additions and 7 deletions
@@ -0,0 +1,41 @@
"""Flip the projects.default_branch server-side default from 'main' to 'master'.
The repositories this system drives use ``master`` as their primary branch, but
the column's default was inherited from the ``main`` convention. Existing rows
already hold ``master``, so this only changes the default applied to future
inserts that omit the column.
Revision ID: 022_default_branch_master
Revises: 021_task_board_review_complete
Create Date: 2026-06-03
"""
from __future__ import annotations
import sqlalchemy as sa
from alembic import op
revision = "022_default_branch_master"
down_revision = "021_task_board_review_complete"
branch_labels = None
depends_on = None
def upgrade() -> None:
op.alter_column(
"projects",
"default_branch",
existing_type=sa.String(length=100),
existing_nullable=False,
server_default="master",
)
def downgrade() -> None:
op.alter_column(
"projects",
"default_branch",
existing_type=sa.String(length=100),
existing_nullable=False,
server_default="main",
)
+1 -1
View File
@@ -417,7 +417,7 @@ class ProjectTable(Base):
# Git Configuration
git_url: Mapped[str] = mapped_column(String(500), nullable=False)
default_branch: Mapped[str] = mapped_column(
String(100), nullable=False, default="main"
String(100), nullable=False, default="master"
)
protected_branches: Mapped[list[str]] = mapped_column(
ARRAY(String), default=lambda: ["main", "master"]
+3 -3
View File
@@ -289,7 +289,7 @@ class GitService(BaseService):
project_slug=project_slug,
agent_id=agent_id,
git_url=project.git_url,
default_branch=project.default_branch or "main",
default_branch=project.default_branch or "master",
)
else:
workspace = await workspace_service.resolve_workspace(
@@ -713,13 +713,13 @@ class GitService(BaseService):
return await self._project_default_branch(project_slug)
async def _project_default_branch(self, project_slug: str) -> str:
"""Return the project's configured default branch, or 'main'."""
"""Return the project's configured default branch, or 'master'."""
project_service = get_project_service(self.session)
project = await project_service.get_by_slug(project_slug)
return (
str(project.default_branch)
if project and project.default_branch
else "main"
else "master"
)
async def _checkout_base_with_fallback(
+3 -3
View File
@@ -773,7 +773,7 @@ class TaskService(BaseService):
if not parent_branch:
default_branch = (
str(project.default_branch) if project.default_branch else "main"
str(project.default_branch) if project.default_branch else "master"
)
self.log.info(
"No ancestor branch found, using project default",
@@ -1326,9 +1326,9 @@ class TaskService(BaseService):
# Determine target branch:
# - For subtasks: merge into parent task's branch
# - For parent tasks: merge into default branch (main)
# - For parent tasks: merge into default branch (master)
default_branch = project.default_branch
target_branch: str = str(default_branch) if default_branch else "main"
target_branch: str = str(default_branch) if default_branch else "master"
if task.parent_task_id:
# Get parent task's branch
parent_id = cast("UUID", task.parent_task_id)
@@ -0,0 +1,101 @@
"""Default branch convention resolves to ``master`` (user-repo convention).
Driven by the real Postgres ``db_session`` fixture so the ORM column default
is exercised by the same SQLAlchemy flush path production uses.
"""
from __future__ import annotations
from types import SimpleNamespace
from typing import TYPE_CHECKING
from uuid import uuid4
import pytest
from roboco.db.tables import AgentTable, ProjectTable
from roboco.models import AgentRole, AgentStatus, Team
from roboco.services.git import GitService
from roboco.services.task import TaskService
if TYPE_CHECKING:
from sqlalchemy.ext.asyncio import AsyncSession
async def _seed_creator(db_session: AsyncSession) -> AgentTable:
agent = AgentTable(
id=uuid4(),
name="System",
slug=f"system-{uuid4().hex[:8]}",
role=AgentRole.SYSTEM,
team=None,
status=AgentStatus.ACTIVE,
model_config={},
system_prompt="system",
capabilities=[],
permissions={},
metrics={},
)
db_session.add(agent)
await db_session.flush()
return agent
@pytest.mark.asyncio
async def test_project_default_branch_defaults_to_master(
db_session: AsyncSession,
) -> None:
"""A project inserted without a ``default_branch`` resolves to ``master``."""
creator = await _seed_creator(db_session)
project = ProjectTable(
id=uuid4(),
name="No Branch Project",
slug=f"proj-{uuid4().hex[:8]}",
git_url="https://github.com/example/no-branch.git",
assigned_cell=Team.BACKEND,
created_by=creator.id,
)
db_session.add(project)
await db_session.flush()
await db_session.refresh(project)
assert project.default_branch == "master"
@pytest.mark.asyncio
async def test_resolve_parent_branch_falls_back_to_master(
db_session: AsyncSession,
) -> None:
"""The parent-branch resolver falls back to ``master`` when the project
default is falsy."""
svc = TaskService(db_session)
task = SimpleNamespace(id=uuid4(), parent_task_id=None)
project = SimpleNamespace(default_branch="")
branch = await svc._resolve_parent_branch(task, project)
assert branch == "master"
@pytest.mark.asyncio
async def test_git_project_default_branch_falls_back_to_master(
db_session: AsyncSession,
) -> None:
"""The git default-branch lookup falls back to ``master`` when the stored
project default is falsy."""
creator = await _seed_creator(db_session)
slug = f"proj-{uuid4().hex[:8]}"
project = ProjectTable(
id=uuid4(),
name="Falsy Branch Project",
slug=slug,
git_url="https://github.com/example/falsy-branch.git",
default_branch="",
assigned_cell=Team.BACKEND,
created_by=creator.id,
)
db_session.add(project)
await db_session.flush()
svc = GitService(db_session)
branch = await svc._project_default_branch(slug)
assert branch == "master"