mirror of
https://github.com/abhigyanpatwari/GitNexus.git
synced 2026-10-05 02:43:32 +00:00
test(ci-setup): add holistic generated-artifact tests
Cross-cutting coverage the per-fix tests don't provide: - bash -n syntax check on the generated ACA deploy script (catches a template regression that produces invalid shell before an operator runs it; skipped where bash is unavailable). - --port upper-boundary: proxy port follows --port (65534 -> 65535) in the Caddyfile and MCP snippet, and a base --port of 65535 is rejected (its proxy port would exceed the valid range). - doc/workflow version consistency: workflows + Cursor config pin the same version while the manual re-index commands intentionally stay @latest. - GITNEXUS.md claims match the workflow (no "blocked at CI" / no "volume-sharing mechanism" overselling). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
52a73622c7
commit
3b3d71dba6
2 changed files with 66 additions and 0 deletions
|
|
@ -1,5 +1,9 @@
|
|||
import { describe, expect, it } from 'vitest';
|
||||
import yaml from 'js-yaml';
|
||||
import { spawnSync } from 'child_process';
|
||||
import { mkdtempSync, writeFileSync, rmSync } from 'fs';
|
||||
import os from 'os';
|
||||
import path from 'path';
|
||||
import { generateFiles } from '../../src/cli/ci-setup/templates.js';
|
||||
import type { CiSetupOptions, DetectResult } from '../../src/cli/ci-setup/types.js';
|
||||
|
||||
|
|
@ -190,6 +194,57 @@ describe('version pinning (U9)', () => {
|
|||
});
|
||||
});
|
||||
|
||||
describe('generated artifact integrity (U11)', () => {
|
||||
it('generated ACA deploy script is syntactically valid bash (bash -n)', () => {
|
||||
const bashAvailable = spawnSync('bash', ['-c', 'exit 0']).status === 0;
|
||||
if (!bashAvailable) return; // portability: skip where bash is unavailable
|
||||
const files = generateFiles(makeOpts({ deploy: 'azure-container-app' }), DEFAULT_DETECT);
|
||||
const script = files.find((f) => f.relativePath === 'gitnexus-aca-deploy.sh');
|
||||
expect(script).toBeDefined();
|
||||
const dir = mkdtempSync(path.join(os.tmpdir(), 'gn-aca-'));
|
||||
try {
|
||||
const p = path.join(dir, 'deploy.sh');
|
||||
writeFileSync(p, script?.content ?? '');
|
||||
const res = spawnSync('bash', ['-n', p], { encoding: 'utf8' });
|
||||
expect(res.status).toBe(0);
|
||||
} finally {
|
||||
rmSync(dir, { recursive: true, force: true });
|
||||
}
|
||||
});
|
||||
|
||||
it('proxy port follows --port at the upper boundary (65534 -> 65535)', () => {
|
||||
const files = generateFiles(
|
||||
makeOpts({ auth: 'token', deploy: 'docker', port: 65534 }),
|
||||
DEFAULT_DETECT,
|
||||
);
|
||||
const cf = files.find((f) => f.relativePath === 'Caddyfile');
|
||||
expect(cf?.content).toContain(':65535 {');
|
||||
const snip = files.find((f) => f.relativePath === '.claude/gitnexus-mcp-snippet.json');
|
||||
expect(snip?.content).toContain(':65535/api/mcp');
|
||||
});
|
||||
|
||||
it('workflows and docs pin the same version; manual re-index stays @latest', () => {
|
||||
const files = generateFiles(makeOpts({ version: '9.9.9', ci: 'both' }), DEFAULT_DETECT);
|
||||
const wf = files.find((f) => f.relativePath === '.github/workflows/gitnexus-ci.yml');
|
||||
const az = files.find((f) => f.relativePath === 'azure-pipelines-gitnexus.yml');
|
||||
const md = files.find((f) => f.relativePath === 'GITNEXUS.md');
|
||||
expect(wf?.content).toContain('gitnexus@9.9.9 analyze');
|
||||
expect(az?.content).toContain('gitnexus@9.9.9 analyze');
|
||||
expect(md?.content).toContain('"gitnexus@9.9.9"'); // Cursor persisted config
|
||||
expect(md?.content).toContain('npx gitnexus@latest analyze'); // manual re-index — intentional
|
||||
// automation must not leave an unpinned @latest
|
||||
expect(wf?.content).not.toContain('gitnexus@latest');
|
||||
expect(az?.content).not.toContain('gitnexus@latest');
|
||||
});
|
||||
|
||||
it('GITNEXUS.md staleness claims match the generated workflow behavior', () => {
|
||||
const md = gitnexusMd();
|
||||
// the workflow only verifies output exists; the doc must not claim staleness blocking
|
||||
expect(md).not.toContain('stale-index PRs are blocked at CI');
|
||||
expect(md).not.toContain('volume-sharing mechanism');
|
||||
});
|
||||
});
|
||||
|
||||
describe('generateFiles', () => {
|
||||
describe('GitHub Actions workflow', () => {
|
||||
it('generates with correct port in healthcheck', () => {
|
||||
|
|
|
|||
|
|
@ -187,6 +187,17 @@ describe('ciSetupCommand', () => {
|
|||
expect(exitSpy).toHaveBeenCalledWith(1);
|
||||
});
|
||||
|
||||
it('rejects a base --port whose proxy port would exceed 65535', async () => {
|
||||
const exitSpy = vi.spyOn(process, 'exit').mockImplementation((_code?: number) => {
|
||||
throw new Error('process.exit called');
|
||||
});
|
||||
const { ciSetupCommand } = await import('../../src/cli/ci-setup.js');
|
||||
await expect(
|
||||
ciSetupCommand({ ci: 'github-actions', deploy: 'docker', port: '65535', outputDir: tempDir }),
|
||||
).rejects.toThrow('process.exit called');
|
||||
expect(exitSpy).toHaveBeenCalledWith(1);
|
||||
});
|
||||
|
||||
it('--auth none generates no Caddyfile', async () => {
|
||||
const { ciSetupCommand } = await import('../../src/cli/ci-setup.js');
|
||||
await ciSetupCommand({
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue