Dev #72
No files matched your search
@@ -0,0 +1,224 @@
|
|||||||
|
"""Scenarios: issues (labels, milestones, time tracking, reactions) and pull requests."""
|
||||||
|
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
import time
|
||||||
|
|
||||||
|
from tests.integration.conftest import McpSession, RegularUser, RepoRef, b64
|
||||||
|
from tests.integration.harness import GiteaInstance
|
||||||
|
|
||||||
|
|
||||||
|
async def test_issue_lifecycle(
|
||||||
|
mcp: McpSession, regular_user: RegularUser, fresh_repo: RepoRef
|
||||||
|
) -> None:
|
||||||
|
repo = fresh_repo.args
|
||||||
|
watcher = regular_user.login
|
||||||
|
|
||||||
|
issue = await mcp.ok(
|
||||||
|
"gitea_issue_create_issue",
|
||||||
|
status=201,
|
||||||
|
body={"title": "Broken widget", "body": "It does not widget."},
|
||||||
|
**repo,
|
||||||
|
)
|
||||||
|
index = issue.data["number"]
|
||||||
|
assert issue.data["state"] == "open"
|
||||||
|
|
||||||
|
# Comments.
|
||||||
|
comment = await mcp.ok(
|
||||||
|
"gitea_issue_create_comment", status=201, index=index, body={"body": "first"}, **repo
|
||||||
|
)
|
||||||
|
comment_id = comment.data["id"]
|
||||||
|
edited = await mcp.ok(
|
||||||
|
"gitea_issue_edit_comment", id=comment_id, body={"body": "first, edited"}, **repo
|
||||||
|
)
|
||||||
|
assert edited.data["body"] == "first, edited"
|
||||||
|
comments = await mcp.ok("gitea_issue_get_comments", index=index, **repo)
|
||||||
|
assert [item["body"] for item in comments.data] == ["first, edited"]
|
||||||
|
|
||||||
|
# Labels: create, add, remove.
|
||||||
|
label = await mcp.ok(
|
||||||
|
"gitea_issue_create_label",
|
||||||
|
status=201,
|
||||||
|
body={"name": "bug", "color": "#d73a4a", "description": "something is broken"},
|
||||||
|
**repo,
|
||||||
|
)
|
||||||
|
label_id = label.data["id"]
|
||||||
|
added = await mcp.ok("gitea_issue_add_label", index=index, body={"labels": [label_id]}, **repo)
|
||||||
|
assert [item["name"] for item in added.data] == ["bug"]
|
||||||
|
assert (await mcp.ok("gitea_issue_get_labels", index=index, **repo)).data
|
||||||
|
await mcp.ok("gitea_issue_remove_label", index=index, id=label_id, **repo)
|
||||||
|
assert (await mcp.ok("gitea_issue_get_labels", index=index, **repo)).data == []
|
||||||
|
await mcp.ok("gitea_issue_replace_labels", index=index, body={"labels": [label_id]}, **repo)
|
||||||
|
await mcp.ok("gitea_issue_clear_labels", index=index, **repo)
|
||||||
|
|
||||||
|
# Milestone.
|
||||||
|
milestone = await mcp.ok(
|
||||||
|
"gitea_issue_create_milestone", status=201, body={"title": "v1"}, **repo
|
||||||
|
)
|
||||||
|
await mcp.ok(
|
||||||
|
"gitea_issue_edit_issue", index=index, body={"milestone": milestone.data["id"]}, **repo
|
||||||
|
)
|
||||||
|
assert (await mcp.ok("gitea_issue_get_issue", index=index, **repo)).data["milestone"][
|
||||||
|
"title"
|
||||||
|
] == "v1"
|
||||||
|
|
||||||
|
# Pin and unpin.
|
||||||
|
await mcp.ok("gitea_issue_pin_issue", index=index, **repo)
|
||||||
|
pinned = await mcp.ok("gitea_issue_list_pinned_issues", **repo)
|
||||||
|
assert [item["number"] for item in pinned.data] == [index]
|
||||||
|
await mcp.ok("gitea_issue_unpin_issue", index=index, **repo)
|
||||||
|
assert (await mcp.ok("gitea_issue_list_pinned_issues", **repo)).data == []
|
||||||
|
|
||||||
|
# Subscriptions.
|
||||||
|
await mcp.ok(
|
||||||
|
"gitea_issue_add_subscription", status=(200, 201), index=index, user=watcher, **repo
|
||||||
|
)
|
||||||
|
subscribers = await mcp.ok("gitea_issue_subscriptions", index=index, **repo)
|
||||||
|
assert watcher in [item["login"] for item in subscribers.data]
|
||||||
|
await mcp.ok("gitea_issue_delete_subscription", index=index, user=watcher, **repo)
|
||||||
|
assert (await mcp.ok("gitea_issue_subscriptions", index=index, **repo)).data == []
|
||||||
|
|
||||||
|
# Time tracking and the stopwatch.
|
||||||
|
await mcp.ok("gitea_issue_add_time", index=index, body={"time": 3600}, **repo)
|
||||||
|
times = await mcp.ok("gitea_issue_tracked_times", index=index, **repo)
|
||||||
|
assert [item["time"] for item in times.data] == [3600]
|
||||||
|
await mcp.ok("gitea_issue_delete_time", index=index, id=times.data[0]["id"], **repo)
|
||||||
|
assert (await mcp.ok("gitea_issue_tracked_times", index=index, **repo)).data == []
|
||||||
|
await mcp.ok("gitea_issue_start_stopwatch", status=201, index=index, **repo)
|
||||||
|
running = await mcp.ok("gitea_user_get_stopwatches")
|
||||||
|
assert index in [item["issue_index"] for item in running.data]
|
||||||
|
await mcp.ok("gitea_issue_stop_stopwatch", status=201, index=index, **repo)
|
||||||
|
assert (await mcp.ok("gitea_issue_tracked_times", index=index, **repo)).data
|
||||||
|
|
||||||
|
# Reactions.
|
||||||
|
await mcp.ok(
|
||||||
|
"gitea_issue_post_issue_reaction",
|
||||||
|
status=(200, 201),
|
||||||
|
index=index,
|
||||||
|
body={"content": "+1"},
|
||||||
|
**repo,
|
||||||
|
)
|
||||||
|
reactions = await mcp.ok("gitea_issue_get_issue_reactions", index=index, **repo)
|
||||||
|
assert [item["content"] for item in reactions.data] == ["+1"]
|
||||||
|
await mcp.ok("gitea_issue_delete_issue_reaction", index=index, body={"content": "+1"}, **repo)
|
||||||
|
|
||||||
|
# Search finds the issue (indexing is asynchronous, so poll briefly).
|
||||||
|
deadline = time.monotonic() + 20
|
||||||
|
hits: list[int] = []
|
||||||
|
while time.monotonic() < deadline and index not in hits:
|
||||||
|
found = await mcp.ok("gitea_issue_list_issues", q="widget", **repo)
|
||||||
|
hits = [item["number"] for item in found.data]
|
||||||
|
if index not in hits:
|
||||||
|
time.sleep(0.5)
|
||||||
|
assert index in hits
|
||||||
|
assert (await mcp.ok("gitea_issue_search_issues", q="Broken widget")).data is not None
|
||||||
|
|
||||||
|
# Close.
|
||||||
|
closed = await mcp.ok("gitea_issue_edit_issue", index=index, body={"state": "closed"}, **repo)
|
||||||
|
assert closed.data["state"] == "closed"
|
||||||
|
assert (await mcp.ok("gitea_issue_get_issue", index=index, **repo)).data["state"] == "closed"
|
||||||
|
await mcp.ok("gitea_issue_delete_comment", id=comment_id, **repo)
|
||||||
|
await mcp.ok("gitea_issue_delete_label", id=label_id, **repo)
|
||||||
|
await mcp.ok("gitea_issue_delete_milestone", id=str(milestone.data["id"]), **repo)
|
||||||
|
|
||||||
|
|
||||||
|
async def test_pull_request_review_and_merge(
|
||||||
|
mcp: McpSession, gitea: GiteaInstance, regular_user: RegularUser, fresh_repo: RepoRef
|
||||||
|
) -> None:
|
||||||
|
repo = fresh_repo.args
|
||||||
|
reviewer = regular_user.login
|
||||||
|
await mcp.ok(
|
||||||
|
"gitea_repo_add_collaborator",
|
||||||
|
collaborator=reviewer,
|
||||||
|
body={"permission": "write"},
|
||||||
|
**repo,
|
||||||
|
)
|
||||||
|
try:
|
||||||
|
# A branch with a change, pushed through the contents API.
|
||||||
|
await mcp.ok(
|
||||||
|
"gitea_repo_create_branch",
|
||||||
|
status=201,
|
||||||
|
body={"new_branch_name": "feat/greeting", "old_branch_name": "main"},
|
||||||
|
**repo,
|
||||||
|
)
|
||||||
|
await mcp.ok(
|
||||||
|
"gitea_repo_create_file",
|
||||||
|
status=201,
|
||||||
|
filepath="greeting.txt",
|
||||||
|
body={
|
||||||
|
"content": b64("hello pull request\n"),
|
||||||
|
"message": "add greeting",
|
||||||
|
"branch": "feat/greeting",
|
||||||
|
},
|
||||||
|
**repo,
|
||||||
|
)
|
||||||
|
pull = await mcp.ok(
|
||||||
|
"gitea_pull_create_pull_request",
|
||||||
|
status=201,
|
||||||
|
body={"title": "Add greeting", "base": "main", "head": "feat/greeting"},
|
||||||
|
**repo,
|
||||||
|
)
|
||||||
|
index = pull.data["number"]
|
||||||
|
assert pull.data["state"] == "open"
|
||||||
|
assert not pull.data["merged"]
|
||||||
|
|
||||||
|
files = await mcp.ok("gitea_pull_get_pull_request_files", index=index, **repo)
|
||||||
|
assert [item["filename"] for item in files.data] == ["greeting.txt"]
|
||||||
|
commits = await mcp.ok("gitea_pull_get_pull_request_commits", index=index, **repo)
|
||||||
|
assert len(commits.data) == 1
|
||||||
|
|
||||||
|
diff = await mcp.ok(
|
||||||
|
"gitea_pull_download_pull_diff_or_patch", index=index, diffType="diff", **repo
|
||||||
|
)
|
||||||
|
assert isinstance(diff.data, str)
|
||||||
|
assert "+hello pull request" in diff.data
|
||||||
|
|
||||||
|
# Requested reviewer, then a pending review with an inline comment (as the
|
||||||
|
# reviewer, through sudo), submitted as an approval.
|
||||||
|
await mcp.ok(
|
||||||
|
"gitea_pull_create_pull_review_requests",
|
||||||
|
status=201,
|
||||||
|
index=index,
|
||||||
|
body={"reviewers": [reviewer]},
|
||||||
|
**repo,
|
||||||
|
)
|
||||||
|
pending = await mcp.ok(
|
||||||
|
"gitea_pull_create_pull_review",
|
||||||
|
sudo=reviewer,
|
||||||
|
index=index,
|
||||||
|
body={
|
||||||
|
"body": "looks fine",
|
||||||
|
"comments": [{"path": "greeting.txt", "new_position": 1, "body": "nice"}],
|
||||||
|
},
|
||||||
|
**repo,
|
||||||
|
)
|
||||||
|
assert pending.identity["sudo"] == reviewer
|
||||||
|
review_id = pending.data["id"]
|
||||||
|
assert pending.data["state"] == "PENDING"
|
||||||
|
submitted = await mcp.ok(
|
||||||
|
"gitea_pull_submit_pull_review",
|
||||||
|
sudo=reviewer,
|
||||||
|
index=index,
|
||||||
|
id=review_id,
|
||||||
|
body={"event": "APPROVED", "body": "approved"},
|
||||||
|
**repo,
|
||||||
|
)
|
||||||
|
assert submitted.data["state"] == "APPROVED"
|
||||||
|
reviews = await mcp.ok("gitea_pull_list_pull_reviews", index=index, **repo)
|
||||||
|
assert "APPROVED" in [item["state"] for item in reviews.data]
|
||||||
|
comments = await mcp.ok(
|
||||||
|
"gitea_pull_get_pull_review_comments", index=index, id=review_id, **repo
|
||||||
|
)
|
||||||
|
assert [item["body"] for item in comments.data] == ["nice"]
|
||||||
|
|
||||||
|
# Not merged yet, then merged.
|
||||||
|
await mcp.fail("gitea_pull_pull_request_is_merged", 404, index=index, **repo)
|
||||||
|
await mcp.ok("gitea_pull_merge_pull_request", index=index, body={"do": "merge"}, **repo)
|
||||||
|
await mcp.ok("gitea_pull_pull_request_is_merged", index=index, **repo)
|
||||||
|
merged = await mcp.ok("gitea_pull_get_pull_request", index=index, **repo)
|
||||||
|
assert merged.data["merged"] is True
|
||||||
|
assert merged.data["state"] == "closed"
|
||||||
|
readme = await mcp.ok("gitea_repo_get_contents", filepath="greeting.txt", **repo)
|
||||||
|
assert readme.data["path"] == "greeting.txt"
|
||||||
|
finally:
|
||||||
|
gitea.api("DELETE", f"/repos/{fresh_repo.owner}/{fresh_repo.name}/collaborators/{reviewer}")
|
||||||
@@ -0,0 +1,265 @@
|
|||||||
|
"""Scenarios: releases and attachments, Action secrets and variables, webhooks."""
|
||||||
|
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
import secrets
|
||||||
|
from typing import Any
|
||||||
|
|
||||||
|
import pytest
|
||||||
|
|
||||||
|
from tests.integration.conftest import McpSession, RepoRef, b64, drop_org
|
||||||
|
from tests.integration.harness import GiteaInstance
|
||||||
|
|
||||||
|
HOOK_CONFIG = {"url": "http://127.0.0.1:9/hook", "content_type": "json"}
|
||||||
|
|
||||||
|
|
||||||
|
async def test_release_with_attachment(
|
||||||
|
mcp: McpSession, gitea: GiteaInstance, fresh_repo: RepoRef
|
||||||
|
) -> None:
|
||||||
|
repo = fresh_repo.args
|
||||||
|
release = await mcp.ok(
|
||||||
|
"gitea_release_create_release",
|
||||||
|
status=201,
|
||||||
|
body={
|
||||||
|
"tag_name": "v1.0.0",
|
||||||
|
"target_commitish": "main",
|
||||||
|
"name": "One point oh",
|
||||||
|
"body": "first release",
|
||||||
|
},
|
||||||
|
**repo,
|
||||||
|
)
|
||||||
|
release_id = release.data["id"]
|
||||||
|
assert release.data["tag_name"] == "v1.0.0"
|
||||||
|
assert (await mcp.ok("gitea_release_get_latest_release", **repo)).data["id"] == release_id
|
||||||
|
assert (await mcp.ok("gitea_release_get_release_by_tag", tag="v1.0.0", **repo)).data["id"] == (
|
||||||
|
release_id
|
||||||
|
)
|
||||||
|
|
||||||
|
# Upload an attachment through the file argument (base64), then list and download it.
|
||||||
|
payload = b"release asset " + secrets.token_bytes(24)
|
||||||
|
asset = await mcp.ok(
|
||||||
|
"gitea_release_create_release_attachment",
|
||||||
|
status=201,
|
||||||
|
id=release_id,
|
||||||
|
name="notes.bin",
|
||||||
|
attachment={
|
||||||
|
"filename": "notes.bin",
|
||||||
|
"content_base64": b64(payload),
|
||||||
|
"content_type": "application/octet-stream",
|
||||||
|
},
|
||||||
|
**repo,
|
||||||
|
)
|
||||||
|
attachment_id = asset.data["id"]
|
||||||
|
assert asset.data["name"] == "notes.bin"
|
||||||
|
assert asset.data["size"] == len(payload)
|
||||||
|
listed = await mcp.ok("gitea_release_list_release_attachments", id=release_id, **repo)
|
||||||
|
assert [item["name"] for item in listed.data] == ["notes.bin"]
|
||||||
|
meta = await mcp.ok(
|
||||||
|
"gitea_release_get_release_attachment", id=release_id, attachment_id=attachment_id, **repo
|
||||||
|
)
|
||||||
|
download = gitea.request("GET", meta.data["browser_download_url"].removeprefix(gitea.base_url))
|
||||||
|
assert download.status_code == 200
|
||||||
|
assert download.content == payload
|
||||||
|
|
||||||
|
renamed = await mcp.ok(
|
||||||
|
"gitea_release_edit_release_attachment",
|
||||||
|
status=(200, 201),
|
||||||
|
id=release_id,
|
||||||
|
attachment_id=attachment_id,
|
||||||
|
body={"name": "renamed.bin"},
|
||||||
|
**repo,
|
||||||
|
)
|
||||||
|
assert renamed.data["name"] == "renamed.bin"
|
||||||
|
edited = await mcp.ok(
|
||||||
|
"gitea_release_edit_release",
|
||||||
|
id=release_id,
|
||||||
|
body={"name": "Renamed", "draft": False},
|
||||||
|
**repo,
|
||||||
|
)
|
||||||
|
assert edited.data["name"] == "Renamed"
|
||||||
|
assert [r["id"] for r in (await mcp.ok("gitea_release_list_releases", **repo)).data] == [
|
||||||
|
release_id
|
||||||
|
]
|
||||||
|
|
||||||
|
await mcp.ok(
|
||||||
|
"gitea_release_delete_release_attachment",
|
||||||
|
id=release_id,
|
||||||
|
attachment_id=attachment_id,
|
||||||
|
**repo,
|
||||||
|
)
|
||||||
|
assert (
|
||||||
|
await mcp.ok("gitea_release_list_release_attachments", id=release_id, **repo)
|
||||||
|
).data == []
|
||||||
|
await mcp.ok("gitea_release_delete_release", id=release_id, **repo)
|
||||||
|
await mcp.fail("gitea_release_get_release", 404, id=release_id, **repo)
|
||||||
|
|
||||||
|
# A second release is removed through its tag.
|
||||||
|
await mcp.ok(
|
||||||
|
"gitea_release_create_release",
|
||||||
|
status=201,
|
||||||
|
body={"tag_name": "v1.1.0", "target_commitish": "main"},
|
||||||
|
**repo,
|
||||||
|
)
|
||||||
|
await mcp.ok("gitea_release_delete_release_by_tag", tag="v1.1.0", **repo)
|
||||||
|
|
||||||
|
|
||||||
|
def _names(result: Any) -> list[str]:
|
||||||
|
return [item["name"] for item in result.data]
|
||||||
|
|
||||||
|
|
||||||
|
async def test_secrets_and_variables_never_leak_values(
|
||||||
|
mcp: McpSession, gitea: GiteaInstance, fresh_repo: RepoRef
|
||||||
|
) -> None:
|
||||||
|
repo = fresh_repo.args
|
||||||
|
org = gitea.unique("it-secrets")
|
||||||
|
values = [f"S3cr3t-{secrets.token_hex(12)}" for _ in range(4)]
|
||||||
|
repo_secret, org_secret, user_secret, probe = values
|
||||||
|
try:
|
||||||
|
await mcp.ok("gitea_org_create", status=201, body={"username": org})
|
||||||
|
|
||||||
|
# Repository, organization and user-level secrets: set, list (names only), delete.
|
||||||
|
await mcp.ok(
|
||||||
|
"gitea_actions_update_repo_secret",
|
||||||
|
secretname="REPO_KEY",
|
||||||
|
body={"data": repo_secret, "description": "repo key"},
|
||||||
|
**repo,
|
||||||
|
)
|
||||||
|
await mcp.ok(
|
||||||
|
"gitea_actions_update_repo_secret",
|
||||||
|
secretname="REPO_KEY",
|
||||||
|
body={"data": repo_secret + "x"},
|
||||||
|
**repo,
|
||||||
|
)
|
||||||
|
listed = await mcp.ok("gitea_actions_repo_list_secrets", **repo)
|
||||||
|
assert _names(listed) == ["REPO_KEY"]
|
||||||
|
assert set(listed.data[0]) <= {"name", "description", "created_at"}
|
||||||
|
await mcp.ok(
|
||||||
|
"gitea_actions_update_org_secret",
|
||||||
|
org=org,
|
||||||
|
secretname="ORG_KEY",
|
||||||
|
body={"data": org_secret},
|
||||||
|
)
|
||||||
|
org_listed = await mcp.ok("gitea_actions_org_list_secrets", org=org)
|
||||||
|
assert _names(org_listed) == ["ORG_KEY"]
|
||||||
|
assert set(org_listed.data[0]) <= {"name", "description", "created_at"}
|
||||||
|
await mcp.ok(
|
||||||
|
"gitea_actions_update_user_secret", secretname="USER_KEY", body={"data": user_secret}
|
||||||
|
)
|
||||||
|
|
||||||
|
# A failing call carrying a secret must not echo it either.
|
||||||
|
denied = await mcp.fail(
|
||||||
|
"gitea_actions_update_repo_secret",
|
||||||
|
404,
|
||||||
|
owner=gitea.admin_login,
|
||||||
|
repo="does-not-exist-" + secrets.token_hex(3),
|
||||||
|
secretname="NOPE",
|
||||||
|
body={"data": probe},
|
||||||
|
)
|
||||||
|
assert probe not in denied.text
|
||||||
|
|
||||||
|
await mcp.ok("gitea_actions_delete_repo_secret", secretname="REPO_KEY", **repo)
|
||||||
|
await mcp.ok("gitea_actions_delete_org_secret", org=org, secretname="ORG_KEY")
|
||||||
|
await mcp.ok("gitea_actions_delete_user_secret", secretname="USER_KEY")
|
||||||
|
assert (await mcp.ok("gitea_actions_repo_list_secrets", **repo)).data == []
|
||||||
|
|
||||||
|
# Variables are not secret: create, get, update, list, delete at every level.
|
||||||
|
scopes: list[tuple[str, dict[str, str]]] = [
|
||||||
|
("repo", repo),
|
||||||
|
("org", {"org": org}),
|
||||||
|
("user", {}),
|
||||||
|
]
|
||||||
|
for level, scope in scopes:
|
||||||
|
create = f"gitea_actions_create_{level}_variable"
|
||||||
|
await mcp.ok(
|
||||||
|
create,
|
||||||
|
status=(200, 201, 204),
|
||||||
|
variablename="GREETING",
|
||||||
|
body={"value": "one"},
|
||||||
|
**scope,
|
||||||
|
)
|
||||||
|
got = await mcp.ok(
|
||||||
|
f"gitea_actions_get_{level}_variable", variablename="GREETING", **scope
|
||||||
|
)
|
||||||
|
assert got.data["data"] == "one"
|
||||||
|
await mcp.ok(
|
||||||
|
f"gitea_actions_update_{level}_variable",
|
||||||
|
variablename="GREETING",
|
||||||
|
body={"value": "two"},
|
||||||
|
**scope,
|
||||||
|
)
|
||||||
|
changed = await mcp.ok(
|
||||||
|
f"gitea_actions_get_{level}_variable", variablename="GREETING", **scope
|
||||||
|
)
|
||||||
|
assert changed.data["data"] == "two"
|
||||||
|
names = await mcp.ok(f"gitea_actions_get_{level}_variables_list", **scope)
|
||||||
|
assert "GREETING" in _names(names)
|
||||||
|
await mcp.ok(f"gitea_actions_delete_{level}_variable", variablename="GREETING", **scope)
|
||||||
|
await mcp.fail(
|
||||||
|
f"gitea_actions_get_{level}_variable", 404, variablename="GREETING", **scope
|
||||||
|
)
|
||||||
|
finally:
|
||||||
|
drop_org(gitea, org)
|
||||||
|
gitea.api("DELETE", "/user/actions/secrets/USER_KEY")
|
||||||
|
|
||||||
|
# No secret value in any tool result, and none in the audit log.
|
||||||
|
for value in values:
|
||||||
|
assert all(value not in text for text in mcp.texts)
|
||||||
|
assert value not in mcp.audit_text()
|
||||||
|
audited = [entry["tool_name"] for entry in mcp.audit_entries()]
|
||||||
|
assert "gitea_actions_update_repo_secret" in audited
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize("level", ["repo", "org", "user", "admin"])
|
||||||
|
async def test_webhook_lifecycle(
|
||||||
|
mcp: McpSession, gitea: GiteaInstance, fresh_repo: RepoRef, level: str
|
||||||
|
) -> None:
|
||||||
|
org = gitea.unique("it-hooks")
|
||||||
|
scope: dict[str, str] = {}
|
||||||
|
prefix = f"gitea_hook_{level}"
|
||||||
|
try:
|
||||||
|
if level == "repo":
|
||||||
|
scope = fresh_repo.args
|
||||||
|
elif level == "org":
|
||||||
|
await mcp.ok("gitea_org_create", status=201, body={"username": org})
|
||||||
|
scope = {"org": org}
|
||||||
|
if level == "admin":
|
||||||
|
create, get, listing, edit, delete = (
|
||||||
|
"gitea_admin_create_hook",
|
||||||
|
"gitea_admin_get_hook",
|
||||||
|
"gitea_admin_list_hooks",
|
||||||
|
"gitea_admin_edit_hook",
|
||||||
|
"gitea_admin_delete_hook",
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
create, get, listing, edit, delete = (
|
||||||
|
f"{prefix}_create_hook",
|
||||||
|
f"{prefix}_get_hook",
|
||||||
|
f"{prefix}_list_hooks",
|
||||||
|
f"{prefix}_edit_hook",
|
||||||
|
f"{prefix}_delete_hook",
|
||||||
|
)
|
||||||
|
hook = await mcp.ok(
|
||||||
|
create,
|
||||||
|
status=201,
|
||||||
|
body={"type": "gitea", "config": HOOK_CONFIG, "events": ["push"], "active": True},
|
||||||
|
**scope,
|
||||||
|
)
|
||||||
|
hook_id = hook.data["id"]
|
||||||
|
assert hook.data["type"] == "gitea"
|
||||||
|
# Hooks created through /admin/hooks count as "default" hooks, so list both kinds.
|
||||||
|
query = {"type": "all"} if level == "admin" else {}
|
||||||
|
hooks = await mcp.ok(listing, **scope, **query)
|
||||||
|
assert hook_id in [item["id"] for item in hooks.data]
|
||||||
|
assert (await mcp.ok(get, id=hook_id, **scope)).data["config"]["url"] == HOOK_CONFIG["url"]
|
||||||
|
edited = await mcp.ok(
|
||||||
|
edit, id=hook_id, body={"active": False, "events": ["push", "issues"]}, **scope
|
||||||
|
)
|
||||||
|
assert edited.data["active"] is False
|
||||||
|
assert "issues" in edited.data["events"]
|
||||||
|
if level == "repo":
|
||||||
|
await mcp.ok("gitea_hook_repo_test_hook", id=hook_id, **scope)
|
||||||
|
await mcp.ok(delete, id=hook_id, **scope)
|
||||||
|
await mcp.fail(get, 404, id=hook_id, **scope)
|
||||||
|
finally:
|
||||||
|
if level == "org":
|
||||||
|
drop_org(gitea, org)
|
||||||
Reference in new issue
Block a user