Compare commits
1 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| a5dac03e7f |
+272
@@ -1788,6 +1788,278 @@ server.tool(
|
||||
},
|
||||
);
|
||||
|
||||
// ── Organization Branch Protection (org-governance) ──────────────────────
|
||||
|
||||
// Shared field schema for org branch protection rulesets (create + edit).
|
||||
// rule_name is supplied separately (body field on create, path param on edit).
|
||||
const OrgBranchProtectionFields = {
|
||||
priority: z.number().optional().describe('Rule priority (lower applies first)'),
|
||||
enable_push: z.boolean().optional().describe('Allow push to matching branches'),
|
||||
enable_push_whitelist: z.boolean().optional().describe('Restrict push to whitelisted teams'),
|
||||
push_whitelist_teams: z.array(z.string()).optional().describe('Teams allowed to push'),
|
||||
enable_force_push: z.boolean().optional().describe('Allow force push'),
|
||||
enable_force_push_allowlist: z.boolean().optional().describe('Restrict force push to allowlisted teams'),
|
||||
force_push_allowlist_teams: z.array(z.string()).optional().describe('Teams allowed to force push'),
|
||||
enable_delete: z.boolean().optional().describe('Allow branch deletion'),
|
||||
enable_delete_allowlist: z.boolean().optional().describe('Restrict deletion to allowlisted teams'),
|
||||
delete_allowlist_teams: z.array(z.string()).optional().describe('Teams allowed to delete branches'),
|
||||
enable_merge_whitelist: z.boolean().optional().describe('Restrict merges to whitelisted teams'),
|
||||
merge_whitelist_teams: z.array(z.string()).optional().describe('Teams allowed to merge'),
|
||||
enable_status_check: z.boolean().optional().describe('Require status checks to pass'),
|
||||
status_check_contexts: z.array(z.string()).optional().describe('Required status check names'),
|
||||
required_approvals: z.number().optional().describe('Required PR approvals (0 = none)'),
|
||||
enable_approvals_whitelist: z.boolean().optional().describe('Restrict approvals to whitelisted teams'),
|
||||
approvals_whitelist_teams: z.array(z.string()).optional().describe('Teams whose approvals count'),
|
||||
block_on_rejected_reviews: z.boolean().optional().describe('Block merge on rejected reviews'),
|
||||
block_on_official_review_requests: z.boolean().optional().describe('Block merge on pending official review requests'),
|
||||
block_on_outdated_branch: z.boolean().optional().describe('Block merge when branch is behind base'),
|
||||
dismiss_stale_approvals: z.boolean().optional().describe('Dismiss approvals when new commits are pushed'),
|
||||
ignore_stale_approvals: z.boolean().optional().describe('Ignore stale approvals when counting'),
|
||||
require_signed_commits: z.boolean().optional().describe('Require signed commits'),
|
||||
protected_file_patterns: z.string().optional().describe('Protected file path patterns (glob, semicolon-separated)'),
|
||||
unprotected_file_patterns: z.string().optional().describe('Unprotected file path patterns (glob, semicolon-separated)'),
|
||||
block_admin_merge_override: z.boolean().optional().describe('Prevent admins from overriding merge restrictions'),
|
||||
};
|
||||
|
||||
server.tool(
|
||||
'gitea_org_branch_protections_list',
|
||||
'List org-level branch protection rulesets (requires org owner)',
|
||||
{ org: z.string().describe('Organization name'), ...ConnectionParam },
|
||||
async ({ org, connection }) => formatResponse(await clientFor(connection).get(`/orgs/${org}/branch_protections`)),
|
||||
);
|
||||
|
||||
server.tool(
|
||||
'gitea_org_branch_protection_get',
|
||||
'Get a single org-level branch protection ruleset by rule name (requires org owner)',
|
||||
{
|
||||
org: z.string().describe('Organization name'),
|
||||
rule_name: z.string().describe('Rule name / branch pattern (e.g. "main", "release/*")'),
|
||||
...ConnectionParam,
|
||||
},
|
||||
async ({ org, rule_name, connection }) => formatResponse(await clientFor(connection).get(`/orgs/${org}/branch_protections/${rule_name}`)),
|
||||
);
|
||||
|
||||
server.tool(
|
||||
'gitea_org_branch_protection_create',
|
||||
'Create an org-level branch protection ruleset applied across the org (requires org owner)',
|
||||
{
|
||||
org: z.string().describe('Organization name'),
|
||||
rule_name: z.string().describe('Rule name / branch pattern (e.g. "main", "release/*")'),
|
||||
...OrgBranchProtectionFields,
|
||||
...ConnectionParam,
|
||||
},
|
||||
async ({ org, rule_name, connection, ...fields }) => {
|
||||
const body: Record<string, unknown> = { rule_name };
|
||||
for (const [k, v] of Object.entries(fields)) {
|
||||
if (v !== undefined) body[k] = v;
|
||||
}
|
||||
return formatResponse(await clientFor(connection).post(`/orgs/${org}/branch_protections`, body));
|
||||
},
|
||||
);
|
||||
|
||||
server.tool(
|
||||
'gitea_org_branch_protection_edit',
|
||||
'Edit an org-level branch protection ruleset (only provided fields change; requires org owner)',
|
||||
{
|
||||
org: z.string().describe('Organization name'),
|
||||
rule_name: z.string().describe('Rule name / branch pattern of the ruleset to edit'),
|
||||
...OrgBranchProtectionFields,
|
||||
...ConnectionParam,
|
||||
},
|
||||
async ({ org, rule_name, connection, ...fields }) => {
|
||||
const body: Record<string, unknown> = {};
|
||||
for (const [k, v] of Object.entries(fields)) {
|
||||
if (v !== undefined) body[k] = v;
|
||||
}
|
||||
return formatResponse(await clientFor(connection).patch(`/orgs/${org}/branch_protections/${rule_name}`, body));
|
||||
},
|
||||
);
|
||||
|
||||
server.tool(
|
||||
'gitea_org_branch_protection_delete',
|
||||
'Delete an org-level branch protection ruleset by rule name (requires org owner)',
|
||||
{
|
||||
org: z.string().describe('Organization name'),
|
||||
rule_name: z.string().describe('Rule name / branch pattern of the ruleset to delete'),
|
||||
...ConnectionParam,
|
||||
},
|
||||
async ({ org, rule_name, connection }) => formatResponse(await clientFor(connection).delete(`/orgs/${org}/branch_protections/${rule_name}`)),
|
||||
);
|
||||
|
||||
// ── Organization Tag Protection (org-governance) ─────────────────────────
|
||||
|
||||
server.tool(
|
||||
'gitea_org_tag_protections_list',
|
||||
'List org-level tag protection rules (requires org owner)',
|
||||
{ org: z.string().describe('Organization name'), ...ConnectionParam },
|
||||
async ({ org, connection }) => formatResponse(await clientFor(connection).get(`/orgs/${org}/tag_protections`)),
|
||||
);
|
||||
|
||||
server.tool(
|
||||
'gitea_org_tag_protection_get',
|
||||
'Get a single org-level tag protection rule by id (requires org owner)',
|
||||
{
|
||||
org: z.string().describe('Organization name'),
|
||||
id: z.number().describe('Tag protection rule ID'),
|
||||
...ConnectionParam,
|
||||
},
|
||||
async ({ org, id, connection }) => formatResponse(await clientFor(connection).get(`/orgs/${org}/tag_protections/${id}`)),
|
||||
);
|
||||
|
||||
server.tool(
|
||||
'gitea_org_tag_protection_create',
|
||||
'Create an org-level tag protection rule (requires org owner)',
|
||||
{
|
||||
org: z.string().describe('Organization name'),
|
||||
name_pattern: z.string().describe('Tag name pattern to protect (glob, e.g. "v*")'),
|
||||
whitelist_teams: z.array(z.string()).optional().describe('Teams allowed to create/delete matching tags'),
|
||||
...ConnectionParam,
|
||||
},
|
||||
async ({ org, name_pattern, whitelist_teams, connection }) => {
|
||||
const body: Record<string, unknown> = { name_pattern };
|
||||
if (whitelist_teams !== undefined) body.whitelist_teams = whitelist_teams;
|
||||
return formatResponse(await clientFor(connection).post(`/orgs/${org}/tag_protections`, body));
|
||||
},
|
||||
);
|
||||
|
||||
server.tool(
|
||||
'gitea_org_tag_protection_edit',
|
||||
'Edit an org-level tag protection rule (only provided fields change; requires org owner)',
|
||||
{
|
||||
org: z.string().describe('Organization name'),
|
||||
id: z.number().describe('Tag protection rule ID'),
|
||||
name_pattern: z.string().optional().describe('Tag name pattern to protect (glob, e.g. "v*")'),
|
||||
whitelist_teams: z.array(z.string()).optional().describe('Teams allowed to create/delete matching tags'),
|
||||
...ConnectionParam,
|
||||
},
|
||||
async ({ org, id, name_pattern, whitelist_teams, connection }) => {
|
||||
const body: Record<string, unknown> = {};
|
||||
if (name_pattern !== undefined) body.name_pattern = name_pattern;
|
||||
if (whitelist_teams !== undefined) body.whitelist_teams = whitelist_teams;
|
||||
return formatResponse(await clientFor(connection).patch(`/orgs/${org}/tag_protections/${id}`, body));
|
||||
},
|
||||
);
|
||||
|
||||
server.tool(
|
||||
'gitea_org_tag_protection_delete',
|
||||
'Delete an org-level tag protection rule by id (requires org owner)',
|
||||
{
|
||||
org: z.string().describe('Organization name'),
|
||||
id: z.number().describe('Tag protection rule ID'),
|
||||
...ConnectionParam,
|
||||
},
|
||||
async ({ org, id, connection }) => formatResponse(await clientFor(connection).delete(`/orgs/${org}/tag_protections/${id}`)),
|
||||
);
|
||||
|
||||
// ── Organization Push Policy (singleton, org-governance) ─────────────────
|
||||
|
||||
server.tool(
|
||||
'gitea_org_push_policy_get',
|
||||
'Get the organization push policy (requires org owner)',
|
||||
{ org: z.string().describe('Organization name'), ...ConnectionParam },
|
||||
async ({ org, connection }) => formatResponse(await clientFor(connection).get(`/orgs/${org}/push_policy`)),
|
||||
);
|
||||
|
||||
server.tool(
|
||||
'gitea_org_push_policy_edit',
|
||||
'Edit the organization push policy (only provided fields change; requires org owner)',
|
||||
{
|
||||
org: z.string().describe('Organization name'),
|
||||
branch_name_pattern: z.string().optional().describe('Allowed branch name pattern (glob)'),
|
||||
tag_name_pattern: z.string().optional().describe('Allowed tag name pattern (glob)'),
|
||||
require_secret_block: z.boolean().optional().describe('Block pushes containing detected secrets'),
|
||||
max_file_size: z.number().optional().describe('Maximum allowed pushed file size in bytes (0 = unlimited)'),
|
||||
blocked_file_patterns: z.string().optional().describe('File path patterns to block on push (glob, semicolon-separated)'),
|
||||
...ConnectionParam,
|
||||
},
|
||||
async ({ org, connection, ...fields }) => {
|
||||
const body: Record<string, unknown> = {};
|
||||
for (const [k, v] of Object.entries(fields)) {
|
||||
if (v !== undefined) body[k] = v;
|
||||
}
|
||||
return formatResponse(await clientFor(connection).patch(`/orgs/${org}/push_policy`, body));
|
||||
},
|
||||
);
|
||||
|
||||
server.tool(
|
||||
'gitea_org_push_policy_delete',
|
||||
'Delete (reset) the organization push policy (requires org owner)',
|
||||
{ org: z.string().describe('Organization name'), ...ConnectionParam },
|
||||
async ({ org, connection }) => formatResponse(await clientFor(connection).delete(`/orgs/${org}/push_policy`)),
|
||||
);
|
||||
|
||||
// ── Organization Repo Defaults (singleton, org-governance) ───────────────
|
||||
|
||||
server.tool(
|
||||
'gitea_org_repo_defaults_get',
|
||||
'Get the organization default repository settings (requires org owner)',
|
||||
{ org: z.string().describe('Organization name'), ...ConnectionParam },
|
||||
async ({ org, connection }) => formatResponse(await clientFor(connection).get(`/orgs/${org}/repo_defaults`)),
|
||||
);
|
||||
|
||||
server.tool(
|
||||
'gitea_org_repo_defaults_edit',
|
||||
'Edit the organization default repository settings (only provided fields change; requires org owner)',
|
||||
{
|
||||
org: z.string().describe('Organization name'),
|
||||
force_private: z.boolean().optional().describe('Force all new repos to be private'),
|
||||
apply_pr_defaults: z.boolean().optional().describe('Apply the PR merge defaults below to new repos'),
|
||||
allow_merge: z.boolean().optional().describe('Allow merge commits'),
|
||||
allow_rebase: z.boolean().optional().describe('Allow rebase merging'),
|
||||
allow_rebase_merge: z.boolean().optional().describe('Allow rebase with merge commit'),
|
||||
allow_squash: z.boolean().optional().describe('Allow squash merging'),
|
||||
allow_fast_forward_only: z.boolean().optional().describe('Allow fast-forward-only merging'),
|
||||
default_merge_style: z.string().optional().describe('Default merge style (merge, rebase, rebase-merge, squash, fast-forward-only)'),
|
||||
delete_branch_after_merge: z.boolean().optional().describe('Delete head branch after merge by default'),
|
||||
...ConnectionParam,
|
||||
},
|
||||
async ({ org, connection, ...fields }) => {
|
||||
const body: Record<string, unknown> = {};
|
||||
for (const [k, v] of Object.entries(fields)) {
|
||||
if (v !== undefined) body[k] = v;
|
||||
}
|
||||
return formatResponse(await clientFor(connection).patch(`/orgs/${org}/repo_defaults`, body));
|
||||
},
|
||||
);
|
||||
|
||||
server.tool(
|
||||
'gitea_org_repo_defaults_delete',
|
||||
'Delete (reset) the organization default repository settings (requires org owner)',
|
||||
{ org: z.string().describe('Organization name'), ...ConnectionParam },
|
||||
async ({ org, connection }) => formatResponse(await clientFor(connection).delete(`/orgs/${org}/repo_defaults`)),
|
||||
);
|
||||
|
||||
// ── Organization Email Domain Policy (singleton, org-governance) ─────────
|
||||
|
||||
server.tool(
|
||||
'gitea_org_email_domain_policy_get',
|
||||
'Get the organization email domain policy (requires org owner)',
|
||||
{ org: z.string().describe('Organization name'), ...ConnectionParam },
|
||||
async ({ org, connection }) => formatResponse(await clientFor(connection).get(`/orgs/${org}/email_domain_policy`)),
|
||||
);
|
||||
|
||||
server.tool(
|
||||
'gitea_org_email_domain_policy_edit',
|
||||
'Edit the organization email domain policy (only provided fields change; requires org owner)',
|
||||
{
|
||||
org: z.string().describe('Organization name'),
|
||||
allowed_domains: z.string().optional().describe('Allowed member email domains (comma-separated, e.g. "example.com,foo.org")'),
|
||||
...ConnectionParam,
|
||||
},
|
||||
async ({ org, allowed_domains, connection }) => {
|
||||
const body: Record<string, unknown> = {};
|
||||
if (allowed_domains !== undefined) body.allowed_domains = allowed_domains;
|
||||
return formatResponse(await clientFor(connection).patch(`/orgs/${org}/email_domain_policy`, body));
|
||||
},
|
||||
);
|
||||
|
||||
server.tool(
|
||||
'gitea_org_email_domain_policy_delete',
|
||||
'Delete (reset) the organization email domain policy (requires org owner)',
|
||||
{ org: z.string().describe('Organization name'), ...ConnectionParam },
|
||||
async ({ org, connection }) => formatResponse(await clientFor(connection).delete(`/orgs/${org}/email_domain_policy`)),
|
||||
);
|
||||
|
||||
// ── Start Server ────────────────────────────────────────────────────────
|
||||
|
||||
async function main(): Promise<void> {
|
||||
|
||||
Reference in New Issue
Block a user