mirror of
https://github.com/abhigyanpatwari/GitNexus.git
synced 2026-09-07 08:26:11 +00:00
Wire extractors into the sync pipeline with service boundary detection. GroupService provides high-level API for all group operations. - Sync pipeline: orchestrates extraction (HTTP, gRPC, topics) with service boundary assignment and exact matching - GroupService: groupList, groupSync, groupContracts, groupQuery, groupStatus (groupImpact deferred to cross-repo follow-up PR) - CLI: group create/add/remove/list/sync/contracts/query/status - MCP tools: group_list, group_sync, group_contracts, group_query, group_status - Monorepo fixture: 3 services (auth/orders/gateway) connected via gRPC + Kafka + HTTP — all intra-repo cross-links discovered - Documentation: CLI commands and MCP tools added to both READMEs Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
79 lines
2.9 KiB
TypeScript
79 lines
2.9 KiB
TypeScript
/**
|
|
* Group sync integration — uses `extractorOverride` / parsed YAML only (no LadybugDB).
|
|
* Full pipeline with indexed fixture repos is a follow-up (needs `.gitnexus/lbug`).
|
|
*/
|
|
import { describe, it, expect } from 'vitest';
|
|
import * as path from 'node:path';
|
|
import * as fs from 'node:fs';
|
|
import { fileURLToPath } from 'node:url';
|
|
import { parseGroupConfig } from '../../../src/core/group/config-parser.js';
|
|
import { syncGroup } from '../../../src/core/group/sync.js';
|
|
import type { StoredContract } from '../../../src/core/group/types.js';
|
|
|
|
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
const FIXTURES_DIR = path.resolve(__dirname, '../../fixtures/group');
|
|
|
|
describe('Group sync integration', () => {
|
|
it('parses fixture group.yaml', () => {
|
|
const yamlContent = fs.readFileSync(path.join(FIXTURES_DIR, 'group.yaml'), 'utf-8');
|
|
const config = parseGroupConfig(yamlContent);
|
|
expect(config.name).toBe('test-group');
|
|
expect(config.repos['app/backend']).toBe('test-backend');
|
|
expect(config.repos['app/frontend']).toBe('test-frontend');
|
|
});
|
|
|
|
it('builds cross-links from fixture-shaped contracts via syncGroup', async () => {
|
|
const yamlContent = fs.readFileSync(path.join(FIXTURES_DIR, 'group.yaml'), 'utf-8');
|
|
const config = parseGroupConfig(yamlContent);
|
|
|
|
const mockContracts: StoredContract[] = [
|
|
{
|
|
contractId: 'http::GET::/api/users',
|
|
type: 'http',
|
|
role: 'provider',
|
|
symbolUid: 'uid-p1',
|
|
symbolRef: { filePath: 'src/routes/users.ts', name: 'list' },
|
|
symbolName: 'list',
|
|
confidence: 0.9,
|
|
meta: { method: 'GET', path: '/api/users' },
|
|
repo: 'app/backend',
|
|
},
|
|
{
|
|
contractId: 'http::GET::/api/users',
|
|
type: 'http',
|
|
role: 'consumer',
|
|
symbolUid: 'uid-c1',
|
|
symbolRef: { filePath: 'src/api/users.ts', name: 'fetchUsers' },
|
|
symbolName: 'fetchUsers',
|
|
confidence: 0.85,
|
|
meta: { method: 'GET', path: '/api/users' },
|
|
repo: 'app/frontend',
|
|
},
|
|
{
|
|
contractId: 'http::GET::/api/health',
|
|
type: 'http',
|
|
role: 'provider',
|
|
symbolUid: 'uid-h1',
|
|
symbolRef: { filePath: 'src/routes/health.ts', name: 'health' },
|
|
symbolName: 'health',
|
|
confidence: 0.9,
|
|
meta: { method: 'GET', path: '/api/health' },
|
|
repo: 'app/backend',
|
|
},
|
|
];
|
|
|
|
const result = await syncGroup(config, {
|
|
extractorOverride: async () => mockContracts,
|
|
skipWrite: true,
|
|
});
|
|
|
|
expect(result.crossLinks.length).toBeGreaterThanOrEqual(1);
|
|
const usersLink = result.crossLinks.find((l) => l.contractId.includes('/api/users'));
|
|
expect(usersLink).toBeDefined();
|
|
expect(usersLink!.matchType).toBe('exact');
|
|
expect(usersLink!.confidence).toBe(1.0);
|
|
|
|
const healthUnmatched = result.unmatched.some((c) => c.contractId.includes('/api/health'));
|
|
expect(healthUnmatched).toBe(true);
|
|
});
|
|
});
|