Skip to main content
Glama
branches-and-queue-scenario.test.ts5.24 kB
import { describe, expect, it } from '@jest/globals'; import type { ActionResult, BranchList, QueuedBuildList, TriggerBuildResult, } from '../types/tool-results'; import { type ToolBatchStepResult, callTool, callToolsBatch, callToolsBatchExpect, } from './lib/mcp-runner'; const SERIAL_WORKER = process.env['JEST_WORKER_ID'] === '1' || process.env['SERIAL_BUILD_TESTS'] === 'true'; const serialDescribe = SERIAL_WORKER ? describe : describe.skip; const hasTeamCityEnv = Boolean( (process.env['TEAMCITY_URL'] ?? process.env['TEAMCITY_SERVER_URL']) && (process.env['TEAMCITY_TOKEN'] ?? process.env['TEAMCITY_API_TOKEN']) ); const ts = Date.now(); const PROJECT_ID = `E2E_BRANCH_${ts}`; const PROJECT_NAME = `E2E Branch ${ts}`; const BT_ID = `E2E_BRANCH_BT_${ts}`; const BT_NAME = `E2E Branch BuildType ${ts}`; const BRANCH_NAME = 'feature/e2e'; let queuedId: string | undefined; serialDescribe('Branches and queue operations', () => { afterAll(async () => { try { await callTool('full', 'delete_project', { projectId: PROJECT_ID }); } catch (_err) { expect(true).toBe(true); } }); it('creates project, build config, and adds step (full)', async () => { if (!hasTeamCityEnv) return expect(true).toBe(true); const batch = await callToolsBatchExpect('full', [ { tool: 'create_project', args: { id: PROJECT_ID, name: PROJECT_NAME, }, }, { tool: 'create_build_config', args: { projectId: PROJECT_ID, id: BT_ID, name: BT_NAME, }, }, { tool: 'manage_build_steps', args: { buildTypeId: BT_ID, action: 'add', name: 'echo-step', type: 'simpleRunner', properties: { 'script.content': 'echo "branches scenario"' }, }, }, ]); const projectResult = batch[0]?.result as ActionResult | undefined; const buildConfigResult = batch[1]?.result as ActionResult | undefined; const stepResult = batch[2]?.result as ActionResult | undefined; expect(projectResult).toMatchObject({ success: true, action: 'create_project' }); expect(buildConfigResult).toMatchObject({ success: true, action: 'create_build_config' }); expect(stepResult).toMatchObject({ success: true, action: 'add_build_step' }); }, 60000); it('triggers a build on non-default branch (dev)', async () => { if (!hasTeamCityEnv) return expect(true).toBe(true); const trig = await callTool<TriggerBuildResult>('dev', 'trigger_build', { buildTypeId: BT_ID, branchName: BRANCH_NAME, }); expect(trig).toMatchObject({ success: true, action: 'trigger_build' }); expect(trig.branchName).toBe(BRANCH_NAME); }, 90000); it('triggers a build using teamcity.build.branch property (dev)', async () => { if (!hasTeamCityEnv) return expect(true).toBe(true); const trig = await callTool<TriggerBuildResult>('dev', 'trigger_build', { buildTypeId: BT_ID, properties: { 'teamcity.build.branch': `${BRANCH_NAME}-prop`, 'env.CUSTOM_FLAG': 'true', }, }); expect(trig).toMatchObject({ success: true, action: 'trigger_build' }); expect(trig.branchName).toBe(`${BRANCH_NAME}-prop`); }, 90000); it('lists branches for project and build type (dev)', async () => { if (!hasTeamCityEnv) return expect(true).toBe(true); const batch = await callToolsBatch('dev', [ { tool: 'list_branches', args: { projectId: PROJECT_ID }, }, { tool: 'list_branches', args: { buildTypeId: BT_ID }, }, ]); batch.results.forEach((step: ToolBatchStepResult, index: number) => { if (!step.ok) { const errorMsg = step.error ?? ''; if (errorMsg.includes('404') || errorMsg.length === 0) { expect(true).toBe(true); } else { throw new Error(`list_branches batch step ${index} failed: ${errorMsg}`); } return; } const payload = step.result as BranchList | undefined; expect(payload).toHaveProperty('branches'); }); }, 60000); it('lists queued builds and cancels one if present (dev cancel)', async () => { if (!hasTeamCityEnv) return expect(true).toBe(true); const queued = await callTool<QueuedBuildList>('dev', 'list_queued_builds', { pageSize: 10 }); expect(queued).toHaveProperty('items'); const first = (queued.items ?? [])[0]; if (first?.id != null) { queuedId = String(first.id); try { const canceled = await callTool('dev', 'cancel_queued_build', { buildId: queuedId }); expect(canceled).toMatchObject({ success: true, action: 'cancel_queued_build' }); } catch (_err) { // If build already started or permission denied, non-fatal expect(true).toBe(true); } } else { expect(true).toBe(true); } }, 60000); it('deletes project (full)', async () => { if (!hasTeamCityEnv) return expect(true).toBe(true); const res = await callTool('full', 'delete_project', { projectId: PROJECT_ID }); expect(res).toMatchObject({ success: true, action: 'delete_project' }); }, 60000); });

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/Daghis/teamcity-mcp'

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