Files
gitea-platform-mcp/tests/unit/test_labels_milestones.py
a-limasov-ii db5a43b19a refactor: make gitea a self-contained Cline skill
Relocate the script into the skill (skills/gitea/scripts/gitea_mcp.py) and add a
PEP 723 dependency block, so `uv run scripts/gitea_mcp.py` provisions deps with no
install step and the skill folder is portable (drop into ~/.cline/skills/). Drop
the non-standard `metadata` frontmatter — Cline only recognizes name + description.

- .mcp.json points at the relocated script and runs with --no-project (PEP 723)
- SKILL.md uses relative scripts/ paths; metadata block removed
- find_config walks up the tree to locate config.json (skill root or plugin root)
- tests import gitea_mcp via pytest pythonpath; README/CLAUDE paths updated

Tests: 119 passed, 92% coverage. Standalone list-tools verified via uv --no-project.
2026-06-24 14:35:28 +03:00

106 lines
3.4 KiB
Python

import json
import pytest
import httpx
import respx
from gitea_mcp import (
list_labels, create_label, add_issue_labels, list_milestones, create_milestone,
)
BASE = "https://gitea.test/api/v1"
@respx.mock
def test_list_labels():
route = respx.get(f"{BASE}/repos/owner/repo/labels").mock(
return_value=httpx.Response(200, json=[{"id": 1, "name": "bug", "color": "#ee0701"}])
)
result = list_labels("owner", "repo")
assert route.called
assert result[0]["name"] == "bug"
@respx.mock
def test_create_label():
route = respx.post(f"{BASE}/repos/owner/repo/labels").mock(
return_value=httpx.Response(201, json={"id": 5, "name": "enhancement"})
)
result = create_label("owner", "repo", "enhancement", "#84b6eb")
assert route.called
body = json.loads(route.calls[0].request.content)
assert body["name"] == "enhancement"
assert body["color"] == "#84b6eb"
@respx.mock
def test_create_label_with_description():
route = respx.post(f"{BASE}/repos/owner/repo/labels").mock(
return_value=httpx.Response(201, json={"id": 6})
)
create_label("owner", "repo", "wontfix", "#ffffff", description="Not going to fix")
body = json.loads(route.calls[0].request.content)
assert body["description"] == "Not going to fix"
@respx.mock
def test_create_label_error():
respx.post(f"{BASE}/repos/owner/repo/labels").mock(
return_value=httpx.Response(422, json={"message": "validation failed"})
)
with pytest.raises(RuntimeError, match="422"):
create_label("owner", "repo", "bad", "notacolor")
@respx.mock
def test_add_issue_labels():
route = respx.post(f"{BASE}/repos/owner/repo/issues/3/labels").mock(
return_value=httpx.Response(200, json=[{"id": 1}])
)
result = add_issue_labels("owner", "repo", 3, [1, 2])
assert route.called
body = json.loads(route.calls[0].request.content)
assert body["labels"] == [1, 2]
@respx.mock
def test_list_milestones():
route = respx.get(f"{BASE}/repos/owner/repo/milestones").mock(
return_value=httpx.Response(200, json=[{"id": 1, "title": "v1.0"}])
)
result = list_milestones("owner", "repo")
assert route.called
assert result[0]["title"] == "v1.0"
assert dict(route.calls[0].request.url.params)["state"] == "open"
@respx.mock
def test_list_milestones_closed():
route = respx.get(f"{BASE}/repos/owner/repo/milestones").mock(
return_value=httpx.Response(200, json=[])
)
list_milestones("owner", "repo", state="closed")
assert dict(route.calls[0].request.url.params)["state"] == "closed"
@respx.mock
def test_create_milestone():
route = respx.post(f"{BASE}/repos/owner/repo/milestones").mock(
return_value=httpx.Response(201, json={"id": 2, "title": "v2.0"})
)
result = create_milestone("owner", "repo", "v2.0")
assert route.called
body = json.loads(route.calls[0].request.content)
assert body["title"] == "v2.0"
assert "description" not in body
assert "due_on" not in body
@respx.mock
def test_create_milestone_with_due_date():
route = respx.post(f"{BASE}/repos/owner/repo/milestones").mock(
return_value=httpx.Response(201, json={"id": 3})
)
create_milestone("owner", "repo", "v3.0", description="Major release", due_on="2025-12-31T00:00:00Z")
body = json.loads(route.calls[0].request.content)
assert body["description"] == "Major release"
assert body["due_on"] == "2025-12-31T00:00:00Z"