Skip to main content
Glama

gitea_workflow_escalate_priority

Automatically escalate issue priority based on aging rules: P3→P2 after 30 days, P2→P1 after 14 days, P1→P0 after 3 days, with security issues always at P0.

Instructions

Automatically escalate priority for aged issues. P3→P2 after 30 days, P2→P1 after 14 days, P1→P0 after 3 days. Security issues are always P0.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
ownerNoRepository owner. Uses context if not provided
repoNoRepository name. Uses context if not provided
dry_runNoPreview changes without applying (default: false)

Implementation Reference

  • The core handler function that implements the gitea_workflow_escalate_priority tool. It loads workflow config, fetches open issues, determines if priority escalation is needed based on issue age (P3->P2 after 30d, P2->P1 after 14d, P1->P0 after 3d) or security type, and applies label changes (remove old priority label, add new one) unless dry_run is true.
    export async function workflowEscalatePriority( ctx: WorkflowToolsContext, args: { owner?: string; repo?: string; config?: WorkflowConfig; dry_run?: boolean; } ): Promise<{ success: boolean; escalated: Array<{ number: number; title: string; from_priority: string; to_priority: string; reason: string; }>; error?: string; }> { logger.debug({ args: { ...args, config: args.config ? '[provided]' : undefined } }, 'Escalating priorities'); const { owner, repo } = ctx.contextManager.resolveOwnerRepo(args.owner, args.repo); const dryRun = args.dry_run ?? false; // 获取配置 let config = args.config; if (!config) { const loadResult = await workflowLoadConfig(ctx, { owner, repo }); if (!loadResult.success || !loadResult.config) { return { success: false, escalated: [], error: loadResult.error || '无法加载配置', }; } config = loadResult.config; } const prefixes = getLabelPrefixes(config); const escalated: Array<{ number: number; title: string; from_priority: string; to_priority: string; reason: string; }> = []; try { // 获取开放的 Issue const issues = await ctx.client.get<Issue[]>(`/repos/${owner}/${repo}/issues?state=open&limit=100`); // 获取标签 ID 映射 const repoLabels = await ctx.client.get<Array<{ id: number; name: string }>>( `/repos/${owner}/${repo}/labels` ); const labelIdMap = new Map(repoLabels.map((l) => [l.name, l.id])); const idToLabelMap = new Map(repoLabels.map((l) => [l.id, l.name])); // 定义升级映射 const upgradeMap: Record<string, { days: number; to: string }> = { P3: { days: 30, to: 'P2' }, P2: { days: 14, to: 'P1' }, P1: { days: 3, to: 'P0' }, }; for (const issue of issues) { const currentPriority = getIssuePriority(issue, prefixes); const issueTypeLabel = issue.labels.find((l) => matchLabel(prefixes.type, l.name) !== null); const issueType = issueTypeLabel ? matchLabel(prefixes.type, issueTypeLabel.name) : null; const ageDays = calculateIssueAgeDays(issue); let newPriority: string | null = null; let reason = ''; // 安全问题强制 P0 if (issueType === 'security' && currentPriority !== 'P0') { newPriority = 'P0'; reason = '安全问题自动升级为紧急'; } else if (currentPriority && upgradeMap[currentPriority]) { const upgrade = upgradeMap[currentPriority]; if (ageDays > upgrade.days) { newPriority = upgrade.to; reason = `超过 ${upgrade.days} 天未解决`; } } if (newPriority && currentPriority) { if (!dryRun) { // 移除旧优先级标签 const oldLabelId = labelIdMap.get(buildLabel(prefixes.priority, currentPriority)); if (oldLabelId) { try { await ctx.client.delete( `/repos/${owner}/${repo}/issues/${issue.number}/labels/${oldLabelId}` ); } catch { // 忽略删除失败 } } // 添加新优先级标签 const newLabelId = labelIdMap.get(buildLabel(prefixes.priority, newPriority)); if (newLabelId) { await ctx.client.post(`/repos/${owner}/${repo}/issues/${issue.number}/labels`, { labels: [newLabelId], }); } } escalated.push({ number: issue.number, title: issue.title, from_priority: currentPriority, to_priority: newPriority, reason, }); } } logger.info({ owner, repo, escalated: escalated.length, dry_run: dryRun }, 'Priorities escalated'); return { success: true, escalated, }; } catch (error) { const errorMessage = error instanceof Error ? error.message : String(error); logger.error({ owner, repo, error: errorMessage }, 'Failed to escalate priorities'); return { success: false, escalated: [], error: errorMessage, }; } }
  • MCP tool registration for 'gitea_workflow_escalate_priority', including title, description, Zod input schema (owner, repo, dry_run), and async handler wrapper that calls the workflowEscalatePriority implementation and formats the response.
    // 8. gitea_workflow_escalate_priority - 优先级升级 mcpServer.registerTool( 'gitea_workflow_escalate_priority', { title: '优先级升级', description: 'Automatically escalate priority for aged issues. P3→P2 after 30 days, P2→P1 after 14 days, P1→P0 after 3 days. Security issues are always P0.', inputSchema: z.object({ owner: z.string().optional().describe('Repository owner. Uses context if not provided'), repo: z.string().optional().describe('Repository name. Uses context if not provided'), dry_run: z.boolean().optional().describe('Preview changes without applying (default: false)'), }), }, async (args) => { try { const result = await WorkflowTools.workflowEscalatePriority( { client: ctx.client, contextManager: ctx.contextManager }, args ); return { content: [{ type: 'text' as const, text: JSON.stringify(result, null, 2) }], isError: !result.success, }; } catch (error: unknown) { const errorMessage = error instanceof Error ? error.message : String(error); return { content: [{ type: 'text' as const, text: `Error: ${errorMessage}` }], isError: true, }; } }
  • Zod input schema definition for the tool, specifying optional owner/repo (resolved from context) and dry_run boolean flag.
    inputSchema: z.object({ owner: z.string().optional().describe('Repository owner. Uses context if not provided'), repo: z.string().optional().describe('Repository name. Uses context if not provided'), dry_run: z.boolean().optional().describe('Preview changes without applying (default: false)'), }), },

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/SupenBysz/gitea-mcp-tool'

If you have feedback or need assistance with the MCP directory API, please join our Discord server