125 lines
3.9 KiB
Python
125 lines
3.9 KiB
Python
from scripts.gitea_task_delegator import (
|
|
apply_assignment_plan,
|
|
build_assignment_plan,
|
|
classify_issue,
|
|
)
|
|
|
|
|
|
class FakeGiteaClient:
|
|
def __init__(self):
|
|
self.assignments = []
|
|
|
|
def assign_issue(self, issue_number, assignee):
|
|
payload = {"number": issue_number, "assignee": assignee}
|
|
self.assignments.append(payload)
|
|
return payload
|
|
|
|
|
|
def make_issue(number, title, body="", labels=None, assignees=None, pull_request=None):
|
|
return {
|
|
"number": number,
|
|
"title": title,
|
|
"body": body,
|
|
"labels": [{"name": name} for name in (labels or [])],
|
|
"assignees": list(assignees or []),
|
|
"pull_request": pull_request,
|
|
}
|
|
|
|
|
|
def test_classify_issue_routes_documentation_to_ezra():
|
|
issue = make_issue(
|
|
11,
|
|
"Codebase genome docs pass",
|
|
body="Need architecture analysis and documentation updates.",
|
|
labels=["documentation"],
|
|
)
|
|
|
|
recommendation = classify_issue(issue)
|
|
|
|
assert recommendation["assignee"] == "ezra"
|
|
assert recommendation["route"] == "documentation"
|
|
assert "documentation" in recommendation["matched_terms"]
|
|
|
|
|
|
def test_classify_issue_routes_build_and_test_work_to_bezalel():
|
|
issue = make_issue(
|
|
12,
|
|
"Fix failing CI tests",
|
|
body="Implementation and testing work needed for the build lane.",
|
|
labels=["bug"],
|
|
)
|
|
|
|
recommendation = classify_issue(issue)
|
|
|
|
assert recommendation["assignee"] == "bezalel"
|
|
assert recommendation["route"] == "implementation"
|
|
|
|
|
|
def test_classify_issue_routes_connectivity_work_to_allegro():
|
|
issue = make_issue(
|
|
13,
|
|
"Dispatch routing broken between hosts",
|
|
body="Need connectivity and coordination fixes for cross-host dispatch.",
|
|
labels=["ops"],
|
|
)
|
|
|
|
recommendation = classify_issue(issue)
|
|
|
|
assert recommendation["assignee"] == "allegro"
|
|
assert recommendation["route"] == "routing"
|
|
|
|
|
|
def test_classify_issue_routes_critical_policy_work_to_timmy():
|
|
issue = make_issue(
|
|
14,
|
|
"Critical sovereign policy decision",
|
|
body="Security-sensitive final decision required.",
|
|
labels=["critical"],
|
|
)
|
|
|
|
recommendation = classify_issue(issue)
|
|
|
|
assert recommendation["assignee"] == "timmy"
|
|
assert recommendation["route"] == "critical"
|
|
|
|
|
|
def test_build_assignment_plan_skips_assigned_prs_and_ambiguous_issues():
|
|
issues = [
|
|
make_issue(1, "Write architecture docs", labels=["documentation"]),
|
|
make_issue(2, "Already owned", labels=["bug"], assignees=[{"login": "bezalel"}]),
|
|
make_issue(3, "misc cleanup"),
|
|
make_issue(4, "Docs PR", labels=["documentation"], pull_request={"url": "https://example/pr/4"}),
|
|
]
|
|
|
|
plan = build_assignment_plan(issues)
|
|
|
|
assert [item["issue_number"] for item in plan["assignments"]] == [1]
|
|
assert plan["assignments"][0]["assignee"] == "ezra"
|
|
assert plan["skipped"] == [
|
|
{"issue_number": 2, "reason": "already_assigned"},
|
|
{"issue_number": 3, "reason": "no_confident_route"},
|
|
{"issue_number": 4, "reason": "pull_request"},
|
|
]
|
|
|
|
|
|
def test_apply_assignment_plan_supports_dry_run_and_apply_modes():
|
|
plan = {
|
|
"assignments": [
|
|
{"issue_number": 21, "assignee": "ezra", "route": "documentation", "confidence": 7},
|
|
{"issue_number": 22, "assignee": "allegro", "route": "routing", "confidence": 6},
|
|
],
|
|
"skipped": [],
|
|
}
|
|
client = FakeGiteaClient()
|
|
|
|
dry_run = apply_assignment_plan(plan, client, apply=False)
|
|
assert [item["action"] for item in dry_run] == ["would_assign", "would_assign"]
|
|
assert client.assignments == []
|
|
|
|
applied = apply_assignment_plan(plan, client, apply=True)
|
|
assert [item["action"] for item in applied] == ["assigned", "assigned"]
|
|
assert client.assignments == [
|
|
{"number": 21, "assignee": "ezra"},
|
|
{"number": 22, "assignee": "allegro"},
|
|
]
|