fix(ci): allow expected legacy parity failures (#1099)

Made-with: Cursor
This commit is contained in:
Gergő Magyar 2026-04-27 06:59:18 +01:00 • committed by GitHub
parent 2f0bd4fdb3
commit 4ea477e8e0
4 changed files with 98 additions and 3 deletions

View file

@ -11,7 +11,8 @@ name: Scope Resolution Parity
# TWICE on every PR:
#
# 1. `REGISTRY_PRIMARY_<LANG>=0` — legacy DAG path (guarantees we haven't
# broken the old path while migrating).
# broken the old path while migrating). Known legacy gaps may be skipped
# through the resolver test helper's expected-failure list.
# 2. `REGISTRY_PRIMARY_<LANG>=1` — registry-primary path (guarantees the
# new path carries the same behavior — the parity gate).
#

View file

@ -1,11 +1,12 @@
/**
* C#: heritage resolution via base_list + ambiguous namespace-import refusal
*/
import { describe, it, expect, beforeAll } from 'vitest';
import { describe, expect, beforeAll } from 'vitest';
import path from 'path';
import {
FIXTURES,
CROSS_FILE_FIXTURES,
createResolverParityIt,
getRelationships,
getNodesByLabel,
getNodesByLabelFull,
@ -14,6 +15,8 @@ import {
type PipelineResult,
} from './helpers.js';
const it = createResolverParityIt('csharp');
// ---------------------------------------------------------------------------
// Heritage: class + interface resolution via base_list
// ---------------------------------------------------------------------------

View file

@ -2,10 +2,54 @@
* Shared test helpers for language resolution integration tests.
*/
import path from 'path';
import { it as vitestIt } from 'vitest';
import { runPipelineFromRepo } from '../../../src/core/ingestion/pipeline.js';
import type { PipelineOptions } from '../../../src/core/ingestion/pipeline.js';
import type { PipelineResult } from '../../../src/types/pipeline.js';
import type { GraphRelationship } from '../../../src/core/graph/types.js';
import type { GraphRelationship } from 'gitnexus-shared';
const LEGACY_RESOLVER_PARITY_EXPECTED_FAILURES: Readonly<Record<string, ReadonlySet<string>>> = {
csharp: new Set([
'emits the using-import edge App/Program.cs -> Models/User.cs through the scope-resolution path',
]),
};
type ResolverParityEnv = Readonly<Record<string, string | undefined>>;
type VitestIt = typeof vitestIt;
type CallableIt = (name: string, ...args: unknown[]) => unknown;
export function resolverParityFlagName(languageSlug: string): string {
return `REGISTRY_PRIMARY_${languageSlug.toUpperCase().replace(/-/g, '_')}`;
}
export function isLegacyResolverParityRun(
languageSlug: string,
env: ResolverParityEnv = process.env,
): boolean {
const value = env[resolverParityFlagName(languageSlug)]?.trim().toLowerCase();
return value === '0' || value === 'false' || value === 'no';
}
export function isLegacyResolverParityExpectedFailure(
languageSlug: string,
testName: string,
env: ResolverParityEnv = process.env,
): boolean {
if (!isLegacyResolverParityRun(languageSlug, env)) return false;
return LEGACY_RESOLVER_PARITY_EXPECTED_FAILURES[languageSlug]?.has(testName) ?? false;
}
export function createResolverParityIt(languageSlug: string): VitestIt {
const wrapped = ((name: string, ...args: unknown[]) => {
const runner = isLegacyResolverParityExpectedFailure(languageSlug, name)
? vitestIt.skip
: vitestIt;
return (runner as unknown as CallableIt)(name, ...args);
}) as VitestIt;
Object.assign(wrapped, vitestIt);
return wrapped;
}
export const FIXTURES = path.resolve(__dirname, '..', '..', 'fixtures', 'lang-resolution');
export const CROSS_FILE_FIXTURES = path.resolve(

View file

@ -0,0 +1,47 @@
import { describe, expect, it } from 'vitest';
import {
isLegacyResolverParityExpectedFailure,
isLegacyResolverParityRun,
resolverParityFlagName,
} from '../../integration/resolvers/helpers.js';
const csharpNamespaceRootImportTest =
'emits the using-import edge App/Program.cs -> Models/User.cs through the scope-resolution path';
describe('resolver parity expected legacy failures', () => {
it('uses the same env var convention as the parity workflow', () => {
expect(resolverParityFlagName('csharp')).toBe('REGISTRY_PRIMARY_CSHARP');
expect(resolverParityFlagName('c-plus-plus')).toBe('REGISTRY_PRIMARY_C_PLUS_PLUS');
});
it('recognizes only legacy parity runs', () => {
expect(isLegacyResolverParityRun('csharp', { REGISTRY_PRIMARY_CSHARP: '0' })).toBe(true);
expect(isLegacyResolverParityRun('csharp', { REGISTRY_PRIMARY_CSHARP: 'false' })).toBe(true);
expect(isLegacyResolverParityRun('csharp', { REGISTRY_PRIMARY_CSHARP: '1' })).toBe(false);
expect(isLegacyResolverParityRun('csharp', {})).toBe(false);
});
it('matches configured expected failures only during the legacy run', () => {
expect(
isLegacyResolverParityExpectedFailure('csharp', csharpNamespaceRootImportTest, {
REGISTRY_PRIMARY_CSHARP: '0',
}),
).toBe(true);
expect(
isLegacyResolverParityExpectedFailure('csharp', csharpNamespaceRootImportTest, {
REGISTRY_PRIMARY_CSHARP: '1',
}),
).toBe(false);
expect(
isLegacyResolverParityExpectedFailure(
'csharp',
'detects exactly 3 classes and 2 interfaces',
{
REGISTRY_PRIMARY_CSHARP: '0',
},
),
).toBe(false);
});
});