Skip to main content
Glama
index.ts6.76 kB
/** * TeamCity integration module * Main entry point for TeamCity API operations */ import { TeamCityAPI } from '@/api-client'; import { info, warn } from '@/utils/logger'; import { type TeamCityClientAdapter, createAdapterFromTeamCityAPI } from './client-adapter'; import { type TeamCityFullConfig, loadTeamCityConfig, mergeConfig, toApiClientConfig, validateConfig, } from './config'; // Re-export all public types and utilities export * from './client-adapter'; export * from './auth'; export * from './errors'; export * from './circuit-breaker'; export * from './pagination'; export * from './config'; // Re-export configuration export * from '@/teamcity-client/configuration'; /** * Global TeamCity client instance */ let globalClient: TeamCityClientAdapter | null = null; /** * Initialize global TeamCity client */ export async function initializeTeamCity( config?: Partial<TeamCityFullConfig> ): Promise<TeamCityClientAdapter> { const envConfig = loadTeamCityConfig(); const fullConfig = config ? mergeConfig(envConfig, config) : envConfig; const validation = validateConfig(fullConfig); if (!validation.isValid) { throw new Error(`Invalid TeamCity configuration: ${validation.errors.join(', ')}`); } const apiConfig = toApiClientConfig(fullConfig); const api = TeamCityAPI.getInstance(apiConfig); globalClient = createAdapterFromTeamCityAPI(api, { fullConfig, apiConfig, }); const isConnected = await api.testConnection(); if (!isConnected) { warn('Failed to connect to TeamCity server', { baseUrl: apiConfig.baseUrl, }); } else { info('Successfully connected to TeamCity server', { baseUrl: apiConfig.baseUrl, }); } return globalClient; } /** * Get global TeamCity client instance */ export function getTeamCityClient(): TeamCityClientAdapter { if (!globalClient) { throw new Error('TeamCity client not initialized. Call initializeTeamCity() first.'); } return globalClient; } /** * Create a new TeamCity client instance */ export function createTeamCityClient(config?: Partial<TeamCityFullConfig>): TeamCityClientAdapter { const envConfig = loadTeamCityConfig(); const fullConfig = config ? mergeConfig(envConfig, config) : envConfig; const validation = validateConfig(fullConfig); if (!validation.isValid) { throw new Error(`Invalid TeamCity configuration: ${validation.errors.join(', ')}`); } const apiConfig = toApiClientConfig(fullConfig); const api = TeamCityAPI.getInstance(apiConfig); return createAdapterFromTeamCityAPI(api, { fullConfig, apiConfig, }); } /** * Reset global TeamCity client (for testing) */ export function resetTeamCityClient(): void { globalClient = null; TeamCityAPI.reset(); } /** * Example usage and helper functions */ interface BuildData { id?: string; number?: number; status?: string; state?: string; branchName?: string; buildType?: { id: string; name: string; }; } interface TestOccurrence { id?: string; name?: string; status?: string; ignored?: boolean; details?: string; } /** * Get all builds for a project */ export async function getProjectBuilds(projectId: string): Promise<BuildData[]> { const client = getTeamCityClient(); const { builds } = client.modules; const response = await builds.getAllBuilds( `project:${projectId}`, // locator as string undefined // fields ); // Map Build[] to BuildData[] const buildList = response.data.build ?? []; return buildList.map( (build: { id?: string | number; number?: string | number; status?: string; state?: string; buildTypeId?: string; branchName?: string; }) => ({ id: build.id != null ? String(build.id) : undefined, number: typeof build.number === 'string' ? parseInt(build.number, 10) : build.number, status: build.status, state: build.state, buildTypeId: build.buildTypeId, branchName: build.branchName, }) ); } /** * Trigger a new build */ export async function triggerBuild( buildTypeId: string, branchName?: string, comment?: string ): Promise<BuildData> { const client = getTeamCityClient(); const { buildQueue } = client.modules; const buildRequest = { buildType: { id: buildTypeId }, branchName, comment: comment !== undefined && comment !== null && comment !== '' ? { text: comment } : undefined, }; const response = await buildQueue.addBuildToQueue( undefined, // moveToTop buildRequest // body ); // Map Build to BuildData const build = response.data; return { id: build.id != null ? String(build.id) : undefined, number: build.number != null ? parseInt(build.number) : undefined, status: build.status, state: build.state, branchName: build.branchName, buildType: build.buildTypeId != null ? { id: build.buildTypeId, name: '' } : undefined, }; } /** * Cancel a running build */ export async function cancelBuild(buildId: number, comment?: string): Promise<void> { const client = getTeamCityClient(); const { builds } = client.modules; await builds.cancelBuild( `id:${buildId}`, // buildLocator undefined, // fields { comment: comment ?? 'Cancelled via MCP' } // body ); } /** * Get build status */ export async function getBuildStatus(buildId: number): Promise<{ state: string; status: string; statusText: string; }> { const client = getTeamCityClient(); const { builds } = client.modules; const response = await builds.getBuild( `id:${buildId}`, // buildLocator 'state,status,statusText' // fields ); return { state: response.data.state ?? 'unknown', status: response.data.status ?? 'unknown', statusText: response.data.statusText ?? '', }; } /** * Get test results for a build */ export async function getBuildTestResults(buildId: number): Promise<{ total: number; passed: number; failed: number; ignored: number; failures: TestOccurrence[]; }> { const client = getTeamCityClient(); const { tests } = client.modules; const response = await tests.getAllTestOccurrences(`build:${buildId}`); const occurrences = response.data.testOccurrence ?? []; const failures = occurrences.filter((t: TestOccurrence) => t.status === 'FAILURE'); return { total: occurrences.length, passed: occurrences.filter((t: TestOccurrence) => t.status === 'SUCCESS').length, failed: failures.length, ignored: occurrences.filter((t: TestOccurrence) => t.ignored === true).length, failures, }; } /** * Get build log */ export async function getBuildLog(buildId: number): Promise<string> { const client = getTeamCityClient(); return client.getBuildLog(String(buildId)); }

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