Files
gitea-platform-mcp/tests/unit/test_commits.py
T
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

95 lines
3.1 KiB
Python

import pytest
import httpx
import respx
from gitea_mcp import list_commits, get_commit, compare_branches, list_repo_contributors
BASE = "https://gitea.test/api/v1"
@respx.mock
def test_list_commits_defaults():
route = respx.get(f"{BASE}/repos/owner/repo/commits").mock(
return_value=httpx.Response(200, json=[{"sha": "abc123"}])
)
result = list_commits("owner", "repo")
assert route.called
params = dict(route.calls[0].request.url.params)
assert params["limit"] == "20"
assert params["page"] == "1"
assert "sha" not in params
assert "path" not in params
@respx.mock
def test_list_commits_on_branch_and_path():
route = respx.get(f"{BASE}/repos/owner/repo/commits").mock(
return_value=httpx.Response(200, json=[])
)
list_commits("owner", "repo", sha="develop", path="server/gitea_mcp.py")
params = dict(route.calls[0].request.url.params)
assert params["sha"] == "develop"
assert params["path"] == "server/gitea_mcp.py"
@respx.mock
def test_get_commit():
route = respx.get(f"{BASE}/repos/owner/repo/git/commits/abc123").mock(
return_value=httpx.Response(200, json={"sha": "abc123", "commit": {"message": "fix bug"}})
)
result = get_commit("owner", "repo", "abc123")
assert route.called
assert result["sha"] == "abc123"
params = dict(route.calls[0].request.url.params)
assert params["stat"] == "true"
assert params["files"] == "true"
@respx.mock
def test_get_commit_without_stat():
route = respx.get(f"{BASE}/repos/owner/repo/git/commits/deadbeef").mock(
return_value=httpx.Response(200, json={"sha": "deadbeef"})
)
get_commit("owner", "repo", "deadbeef", stat=False, files=False)
params = dict(route.calls[0].request.url.params)
assert params["stat"] == "false"
assert params["files"] == "false"
@respx.mock
def test_get_commit_not_found():
respx.get(f"{BASE}/repos/owner/repo/git/commits/notacommit").mock(
return_value=httpx.Response(404, json={"message": "not found"})
)
with pytest.raises(RuntimeError, match="404"):
get_commit("owner", "repo", "notacommit")
@respx.mock
def test_compare_branches():
route = respx.get(f"{BASE}/repos/owner/repo/compare/main...develop").mock(
return_value=httpx.Response(200, json={"total_commits": 3, "commits": []})
)
result = compare_branches("owner", "repo", "main", "develop")
assert route.called
assert result["total_commits"] == 3
@respx.mock
def test_compare_branches_with_slashes():
route = respx.get(f"{BASE}/repos/owner/repo/compare/release%2F1.0...feature%2Fnew").mock(
return_value=httpx.Response(200, json={"total_commits": 1})
)
result = compare_branches("owner", "repo", "release/1.0", "feature/new")
assert route.called
@respx.mock
def test_list_repo_contributors():
route = respx.get(f"{BASE}/repos/owner/repo/contributors").mock(
return_value=httpx.Response(200, json=[{"login": "alice", "contributions": 42}])
)
result = list_repo_contributors("owner", "repo")
assert route.called
assert result[0]["login"] == "alice"
assert dict(route.calls[0].request.url.params)["limit"] == "20"