feat: initial commit — Billo Release Agent (LangGraph)

LangGraph-based release automation agent with:
- PR discovery (webhook + polling)
- AI code review via Claude Code CLI (subscription-based)
- Auto-create Jira tickets for PRs without ticket ID
- Jira ticket lifecycle management (code review -> staging -> done)
- CI/CD pipeline trigger, polling, and approval gates
- Slack interactive messages with approval buttons
- Per-repo semantic versioning
- PostgreSQL persistence (threads, staging, releases)
- FastAPI API (webhooks, approvals, status, manual triggers)
- Docker Compose deployment

1069 tests, 95%+ coverage.
This commit is contained in:
Yaojia Wang
2026-03-24 17:38:23 +01:00
commit f5c2733cfb
104 changed files with 19721 additions and 0 deletions

44
tests/graph/conftest.py Normal file
View File

@@ -0,0 +1,44 @@
"""Shared fixtures for graph tests.
Provides build_mock_clients() to create ToolClients with AsyncMock fields
so individual node functions can be tested without compiling the full graph.
"""
from unittest.mock import AsyncMock, MagicMock
import pytest
from release_agent.graph.dependencies import ToolClients
def build_mock_clients() -> ToolClients:
"""Return a ToolClients instance whose fields are all AsyncMock/MagicMock."""
azdo = AsyncMock()
jira = AsyncMock()
slack = AsyncMock()
reviewer = AsyncMock()
return ToolClients(azdo=azdo, jira=jira, slack=slack, reviewer=reviewer)
def build_config(clients: ToolClients | None = None, staging_store=None) -> dict:
"""Return a LangGraph-style config dict with clients and staging_store."""
if clients is None:
clients = build_mock_clients()
return {
"configurable": {
"clients": clients,
"staging_store": staging_store,
}
}
@pytest.fixture()
def mock_clients() -> ToolClients:
"""Pytest fixture returning fresh mock ToolClients."""
return build_mock_clients()
@pytest.fixture()
def config(mock_clients: ToolClients):
"""Pytest fixture returning a config dict with mock clients."""
return build_config(mock_clients)