remove compare to latest schema version feature flag (#7584)

This commit is contained in:
Laurin Quast 2026-01-28 08:25:56 +01:00 committed by GitHub
parent e203a7cf89
commit 0f0430f4f5
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
20 changed files with 1101 additions and 1545 deletions

View file

@ -0,0 +1,9 @@
---
'hive': minor
---
Enable automatic retrieval of schema changes by comparing with the latest composable version. This has already been the default for new projects created after April 2024.
Federation and schema stitching projects can now publish service schemas to the registry even if those schemas would break composition. This has also been the default behavior for new projects created after April 2024.
To ensure every version publishd to the schema registry is composable, we recommend to first check the schema against the registry **before** publishing.

View file

@ -1117,11 +1117,10 @@ function runArtifactsCDNTests(
'access versioned contract artifact with valid credentials',
async ({ expect }) => {
const { createOrg, ownerToken } = await initSeed().createOwner();
const { createProject, setFeatureFlag } = await createOrg();
const { createTargetAccessToken, createCdnAccess, target, setNativeFederation } =
await createProject(ProjectType.Federation);
await setFeatureFlag('compareToPreviousComposableVersion', true);
await setNativeFederation(true);
const { createProject } = await createOrg();
const { createTargetAccessToken, createCdnAccess, target } = await createProject(
ProjectType.Federation,
);
const writeToken = await createTargetAccessToken({});

View file

@ -1925,12 +1925,8 @@ describe.concurrent(
() => {
test.concurrent('native federation', async () => {
const { createOrg } = await initSeed().createOwner();
const { createProject, setFeatureFlag } = await createOrg();
const { createTargetAccessToken, setNativeFederation } = await createProject(
ProjectType.Federation,
);
await setFeatureFlag('compareToPreviousComposableVersion', true);
await setNativeFederation(true);
const { createProject } = await createOrg();
const { createTargetAccessToken } = await createProject(ProjectType.Federation);
const token = await createTargetAccessToken({});
@ -1976,11 +1972,10 @@ describe.concurrent(
test.concurrent('legacy fed composition', async () => {
const { createOrg } = await initSeed().createOwner();
const { createProject, setFeatureFlag } = await createOrg();
const { createProject } = await createOrg();
const { createTargetAccessToken, setNativeFederation } = await createProject(
ProjectType.Federation,
);
await setFeatureFlag('compareToPreviousComposableVersion', false);
await setNativeFederation(false);
const token = await createTargetAccessToken({});
@ -2020,58 +2015,6 @@ describe.concurrent(
}),
});
});
test.concurrent(
'legacy fed composition with compareToPreviousComposableVersion=true',
async () => {
const { createOrg } = await initSeed().createOwner();
const { createProject, setFeatureFlag } = await createOrg();
const { createTargetAccessToken, setNativeFederation } = await createProject(
ProjectType.Federation,
);
await setFeatureFlag('compareToPreviousComposableVersion', true);
await setNativeFederation(false);
const token = await createTargetAccessToken({});
// @key(fields:) is invalid - should trigger a composition error
const sdl = /* GraphQL */ `
type Query {
ping: String
pong: String
foo: User
}
type User @key(fields: "uuid") {
id: ID!
}
`;
// Publish schema with write rights
await token
.publishSchema({
sdl,
service: 'serviceA',
url: 'http://localhost:4000',
})
.then(r => r.expectNoGraphQLErrors());
const result = await token
.checkSchema(sdl, 'serviceA')
.then(r => r.expectNoGraphQLErrors());
expect(result.schemaCheck).toMatchObject({
valid: false,
__typename: 'SchemaCheckError',
changes: expect.objectContaining({
total: 0,
}),
errors: expect.objectContaining({
total: 1,
}),
});
},
);
},
);

View file

@ -32,12 +32,8 @@ const CreateContractMutation = graphql(`
test.concurrent('schema check with successful contract checks', async ({ expect }) => {
const { createOrg, ownerToken } = await initSeed().createOwner();
const { createProject, setFeatureFlag } = await createOrg();
const { createTargetAccessToken, target, setNativeFederation } = await createProject(
ProjectType.Federation,
);
await setFeatureFlag('compareToPreviousComposableVersion', true);
await setNativeFederation(true);
const { createProject } = await createOrg();
const { createTargetAccessToken, target } = await createProject(ProjectType.Federation);
// Create a token with write rights
const writeToken = await createTargetAccessToken({});
@ -99,12 +95,8 @@ test.concurrent('schema check with successful contract checks', async ({ expect
test.concurrent('schema check with failing contract composition', async ({ expect }) => {
const { createOrg, ownerToken } = await initSeed().createOwner();
const { createProject, setFeatureFlag } = await createOrg();
const { createTargetAccessToken, target, setNativeFederation } = await createProject(
ProjectType.Federation,
);
await setFeatureFlag('compareToPreviousComposableVersion', true);
await setNativeFederation(true);
const { createProject } = await createOrg();
const { createTargetAccessToken, target } = await createProject(ProjectType.Federation);
// Create a token with write rights
const writeToken = await createTargetAccessToken({});
@ -180,12 +172,8 @@ test.concurrent(
'schema check with failing contract composition (multiple contracts)',
async ({ expect }) => {
const { createOrg, ownerToken } = await initSeed().createOwner();
const { createProject, setFeatureFlag } = await createOrg();
const { createTargetAccessToken, target, setNativeFederation } = await createProject(
ProjectType.Federation,
);
await setFeatureFlag('compareToPreviousComposableVersion', true);
await setNativeFederation(true);
const { createProject } = await createOrg();
const { createTargetAccessToken, target } = await createProject(ProjectType.Federation);
// Create a token with write rights
const writeToken = await createTargetAccessToken({});
@ -381,12 +369,10 @@ test.concurrent(
'approve failed schema check that has breaking change in contract check -> updates the status to successful and attaches meta information to the breaking change',
async ({ expect }) => {
const { createOrg, ownerToken } = await initSeed().createOwner();
const { createProject, organization, setFeatureFlag } = await createOrg();
const { createTargetAccessToken, project, target, setNativeFederation } = await createProject(
const { createProject, organization } = await createOrg();
const { createTargetAccessToken, project, target } = await createProject(
ProjectType.Federation,
);
await setFeatureFlag('compareToPreviousComposableVersion', true);
await setNativeFederation(true);
// Create a token with write rights
const writeToken = await createTargetAccessToken({});
@ -547,8 +533,6 @@ test.concurrent(
const { createTargetAccessToken, project, target, setNativeFederation } = await createProject(
ProjectType.Federation,
);
await setFeatureFlag('compareToPreviousComposableVersion', true);
await setNativeFederation(true);
// Create a token with write rights
const writeToken = await createTargetAccessToken({});
@ -739,12 +723,10 @@ test.concurrent(
'approving a schema check with contextId containing breaking changes does not allow the changes for subsequent checks with a different contextId',
async ({ expect }) => {
const { createOrg, ownerToken } = await initSeed().createOwner();
const { createProject, organization, setFeatureFlag } = await createOrg();
const { createTargetAccessToken, project, target, setNativeFederation } = await createProject(
const { createProject, organization } = await createOrg();
const { createTargetAccessToken, project, target } = await createProject(
ProjectType.Federation,
);
await setFeatureFlag('compareToPreviousComposableVersion', true);
await setNativeFederation(true);
// Create a token with write rights
const writeToken = await createTargetAccessToken({});
@ -928,12 +910,10 @@ test.concurrent(
'subsequent schema check with shared contextId that contains new breaking changes that have not been approved fails',
async ({ expect }) => {
const { createOrg, ownerToken } = await initSeed().createOwner();
const { createProject, organization, setFeatureFlag } = await createOrg();
const { createTargetAccessToken, project, target, setNativeFederation } = await createProject(
const { createProject, organization } = await createOrg();
const { createTargetAccessToken, project, target } = await createProject(
ProjectType.Federation,
);
await setFeatureFlag('compareToPreviousComposableVersion', true);
await setNativeFederation(true);
// Create a token with write rights
const writeToken = await createTargetAccessToken({});
@ -1128,12 +1108,10 @@ test.concurrent(
'schema check that has no composition errors in contract check -> can be approved',
async ({ expect }) => {
const { createOrg, ownerToken } = await initSeed().createOwner();
const { createProject, organization, setFeatureFlag } = await createOrg();
const { createTargetAccessToken, project, target, setNativeFederation } = await createProject(
const { createProject, organization } = await createOrg();
const { createTargetAccessToken, project, target } = await createProject(
ProjectType.Federation,
);
await setFeatureFlag('compareToPreviousComposableVersion', true);
await setNativeFederation(true);
// Create a token with write rights
const writeToken = await createTargetAccessToken({});
@ -1237,12 +1215,10 @@ test.concurrent(
'schema check that has composition errors in contract check -> can not be approved',
async ({ expect }) => {
const { createOrg, ownerToken } = await initSeed().createOwner();
const { createProject, organization, setFeatureFlag } = await createOrg();
const { createProject, organization } = await createOrg();
const { createTargetAccessToken, project, target, setNativeFederation } = await createProject(
ProjectType.Federation,
);
await setFeatureFlag('compareToPreviousComposableVersion', true);
await setNativeFederation(true);
// Create a token with write rights
const writeToken = await createTargetAccessToken({});

View file

@ -67,12 +67,8 @@ test.concurrent(
'schema publish with successful initial contract composition',
async ({ expect }) => {
const { createOrg, ownerToken } = await initSeed().createOwner();
const { createProject, setFeatureFlag } = await createOrg();
const { createTargetAccessToken, target, setNativeFederation } = await createProject(
ProjectType.Federation,
);
await setFeatureFlag('compareToPreviousComposableVersion', true);
await setNativeFederation(true);
const { createProject } = await createOrg();
const { createTargetAccessToken, target } = await createProject(ProjectType.Federation);
// Create a token with write rights
const writeToken = await createTargetAccessToken({});
@ -158,12 +154,8 @@ test.concurrent(
test.concurrent('schema publish with failing initial contract composition', async ({ expect }) => {
const { createOrg, ownerToken } = await initSeed().createOwner();
const { createProject, setFeatureFlag } = await createOrg();
const { createTargetAccessToken, target, setNativeFederation } = await createProject(
ProjectType.Federation,
);
await setFeatureFlag('compareToPreviousComposableVersion', true);
await setNativeFederation(true);
const { createProject } = await createOrg();
const { createTargetAccessToken, target } = await createProject(ProjectType.Federation);
// Create a token with write rights
const writeToken = await createTargetAccessToken({});
@ -239,12 +231,8 @@ test.concurrent('schema publish with failing initial contract composition', asyn
test.concurrent('schema publish with succeeding contract composition', async ({ expect }) => {
const { createOrg, ownerToken } = await initSeed().createOwner();
const { createProject, setFeatureFlag } = await createOrg();
const { createTargetAccessToken, target, setNativeFederation } = await createProject(
ProjectType.Federation,
);
await setFeatureFlag('compareToPreviousComposableVersion', true);
await setNativeFederation(true);
const { createProject } = await createOrg();
const { createTargetAccessToken, target } = await createProject(ProjectType.Federation);
// Create a token with write rights
const writeToken = await createTargetAccessToken({});
@ -330,12 +318,8 @@ test.concurrent('schema publish with succeeding contract composition', async ({
test.concurrent('schema publish with failing contract composition', async ({ expect }) => {
const { createOrg, ownerToken } = await initSeed().createOwner();
const { createProject, setFeatureFlag } = await createOrg();
const { createTargetAccessToken, target, setNativeFederation } = await createProject(
ProjectType.Federation,
);
await setFeatureFlag('compareToPreviousComposableVersion', true);
await setNativeFederation(true);
const { createProject } = await createOrg();
const { createTargetAccessToken, target } = await createProject(ProjectType.Federation);
// Create a token with write rights
const writeToken = await createTargetAccessToken({});
@ -421,12 +405,8 @@ test.concurrent(
'schema delete with successful initial contract composition',
async ({ expect }) => {
const { createOrg, ownerToken } = await initSeed().createOwner();
const { createProject, setFeatureFlag } = await createOrg();
const { createTargetAccessToken, target, setNativeFederation } = await createProject(
ProjectType.Federation,
);
await setFeatureFlag('compareToPreviousComposableVersion', true);
await setNativeFederation(true);
const { createProject } = await createOrg();
const { createTargetAccessToken, target } = await createProject(ProjectType.Federation);
// Create a token with write rights
const writeToken = await createTargetAccessToken({});
@ -512,12 +492,8 @@ test.concurrent(
test.concurrent('schema delete with failing initial contract composition', async ({ expect }) => {
const { createOrg, ownerToken } = await initSeed().createOwner();
const { createProject, setFeatureFlag } = await createOrg();
const { createTargetAccessToken, target, setNativeFederation } = await createProject(
ProjectType.Federation,
);
await setFeatureFlag('compareToPreviousComposableVersion', true);
await setNativeFederation(true);
const { createProject } = await createOrg();
const { createTargetAccessToken, target } = await createProject(ProjectType.Federation);
// Create a token with write rights
const writeToken = await createTargetAccessToken({});
@ -594,12 +570,8 @@ test.concurrent('schema delete with failing initial contract composition', async
test.concurrent('schema delete with succeeding contract composition', async ({ expect }) => {
const { createOrg, ownerToken } = await initSeed().createOwner();
const { createProject, setFeatureFlag } = await createOrg();
const { createTargetAccessToken, target, setNativeFederation } = await createProject(
ProjectType.Federation,
);
await setFeatureFlag('compareToPreviousComposableVersion', true);
await setNativeFederation(true);
const { createProject } = await createOrg();
const { createTargetAccessToken, target } = await createProject(ProjectType.Federation);
// Create a token with write rights
const writeToken = await createTargetAccessToken({});
@ -684,12 +656,8 @@ test.concurrent('schema delete with succeeding contract composition', async ({ e
test.concurrent('schema delete with failing contract composition', async ({ expect }) => {
const { createOrg, ownerToken } = await initSeed().createOwner();
const { createProject, setFeatureFlag } = await createOrg();
const { createTargetAccessToken, target, setNativeFederation } = await createProject(
ProjectType.Federation,
);
await setFeatureFlag('compareToPreviousComposableVersion', true);
await setNativeFederation(true);
const { createProject } = await createOrg();
const { createTargetAccessToken, target } = await createProject(ProjectType.Federation);
// Create a token with write rights
const writeToken = await createTargetAccessToken({});
@ -768,11 +736,10 @@ test.concurrent(
'successful contracts schema can be fetched from the CDN with CDN access token',
async ({ expect }) => {
const { createOrg, ownerToken } = await initSeed().createOwner();
const { createProject, setFeatureFlag } = await createOrg();
const { createTargetAccessToken, createCdnAccess, target, setNativeFederation } =
await createProject(ProjectType.Federation);
await setFeatureFlag('compareToPreviousComposableVersion', true);
await setNativeFederation(true);
const { createProject } = await createOrg();
const { createTargetAccessToken, createCdnAccess, target } = await createProject(
ProjectType.Federation,
);
// Create a token with write rights
const writeToken = await createTargetAccessToken({});
@ -835,8 +802,6 @@ test.concurrent(
const { createProject, setFeatureFlag } = await createOrg();
const { createTargetAccessToken, createCdnAccess, target, setNativeFederation } =
await createProject(ProjectType.Federation);
await setFeatureFlag('compareToPreviousComposableVersion', true);
await setNativeFederation(true);
// Create a token with write rights
const writeToken = await createTargetAccessToken({});
@ -904,11 +869,10 @@ const DisabledContractMutation = graphql(`
test.concurrent('disable contract results in CDN artifacts being removed', async ({ expect }) => {
const { createOrg, ownerToken } = await initSeed().createOwner();
const { createProject, setFeatureFlag } = await createOrg();
const { createTargetAccessToken, createCdnAccess, target, setNativeFederation } =
await createProject(ProjectType.Federation);
await setFeatureFlag('compareToPreviousComposableVersion', true);
await setNativeFederation(true);
const { createProject } = await createOrg();
const { createTargetAccessToken, createCdnAccess, target } = await createProject(
ProjectType.Federation,
);
// Create a token with write rights
const writeToken = await createTargetAccessToken({});
@ -993,11 +957,10 @@ test.concurrent(
'disable contract delete succeeds if no version/CDN artifacts have been published yet',
async ({ expect }) => {
const { createOrg, ownerToken } = await initSeed().createOwner();
const { createProject, setFeatureFlag } = await createOrg();
const { createTargetAccessToken, createCdnAccess, target, setNativeFederation } =
await createProject(ProjectType.Federation);
await setFeatureFlag('compareToPreviousComposableVersion', true);
await setNativeFederation(true);
const { createProject } = await createOrg();
const { createTargetAccessToken, createCdnAccess, target } = await createProject(
ProjectType.Federation,
);
// Create a token with write rights
const writeToken = await createTargetAccessToken({});
@ -1051,15 +1014,8 @@ test.concurrent(
'disable contract delete succeeds if no version/CDN artifacts have been published yet',
async ({ expect }) => {
const { createOrg, ownerToken } = await initSeed().createOwner();
const { createProject, setFeatureFlag } = await createOrg();
const { createTargetAccessToken, target, setNativeFederation } = await createProject(
ProjectType.Federation,
);
await setFeatureFlag('compareToPreviousComposableVersion', true);
await setNativeFederation(true);
// Create a token with write rights
const writeToken = await createTargetAccessToken({});
const { createProject } = await createOrg();
const { target } = await createProject(ProjectType.Federation);
const createContractResult = await execute({
document: CreateContractMutation,

View file

@ -223,7 +223,7 @@ test.concurrent(
);
test.concurrent(
'composition error is persisted in the database when the super schema schema is not composable',
'composition error is persisted in the database when the supergraph is not composable',
async ({ expect }) => {
let storage: Awaited<ReturnType<typeof createStorage>> | undefined = undefined;
@ -263,6 +263,7 @@ test.concurrent(
url: 'http://localhost:4000/graphql',
})
.then(r => r.expectNoGraphQLErrors());
expect(publishService1Result.schemaPublish.__typename).toBe('SchemaPublishSuccess');
const publishService2Result = await readToken

View file

@ -4001,8 +4001,6 @@ test.concurrent(
const { createTargetAccessToken, setNativeFederation } = await createProject(
ProjectType.Federation,
);
await setNativeFederation(true);
await setFeatureFlag('compareToPreviousComposableVersion', true);
const readWriteToken = await createTargetAccessToken({});
@ -4146,8 +4144,6 @@ describe.concurrent(
const { createTargetAccessToken, setNativeFederation } = await createProject(
ProjectType.Federation,
);
await setFeatureFlag('compareToPreviousComposableVersion', true);
await setNativeFederation(true);
const token = await createTargetAccessToken({});
@ -4294,8 +4290,6 @@ describe.concurrent(
const { createTargetAccessToken, setNativeFederation } = await createProject(
ProjectType.Federation,
);
await setFeatureFlag('compareToPreviousComposableVersion', false);
await setNativeFederation(false);
const token = await createTargetAccessToken({});
@ -4427,149 +4421,6 @@ describe.concurrent(
linkToWebsite: result.schemaPublish.linkToWebsite,
});
});
test.concurrent(
'legacy fed composition with compareToPreviousComposableVersion=true',
async () => {
const { createOrg } = await initSeed().createOwner();
const { createProject, setFeatureFlag } = await createOrg();
const { createTargetAccessToken, setNativeFederation } = await createProject(
ProjectType.Federation,
);
await setFeatureFlag('compareToPreviousComposableVersion', true);
await setNativeFederation(false);
const token = await createTargetAccessToken({});
const validSdl = /* GraphQL */ `
type Query {
ping: String
pong: String
foo: User
}
type User @key(fields: "id") {
id: ID!
}
`;
// @key(fields:) is invalid - should trigger a composition error
const invalidSdl = /* GraphQL */ `
type Query {
ping: String
pong: String
foo: User
}
type User @key(fields: "uuid") {
id: ID!
}
`;
// Publish schema with write rights
const validPublish = await token
.publishSchema({
sdl: validSdl,
service: 'serviceA',
url: 'http://localhost:4000',
})
.then(r => r.expectNoGraphQLErrors());
expect(validPublish.schemaPublish).toMatchObject({
valid: true,
linkToWebsite: expect.any(String),
});
const invalidPublish = await token
.publishSchema({
sdl: invalidSdl,
service: 'serviceA',
url: 'http://localhost:4000',
})
.then(r => r.expectNoGraphQLErrors());
expect(invalidPublish.schemaPublish).toMatchObject({
valid: false,
linkToWebsite: expect.any(String),
});
const invalidSdlCheck = await token
.checkSchema(invalidSdl, 'serviceA')
.then(r => r.expectNoGraphQLErrors());
expect(invalidSdlCheck.schemaCheck).toMatchObject({
valid: false,
__typename: 'SchemaCheckError',
changes: expect.objectContaining({
total: 0,
}),
errors: expect.objectContaining({
total: 1,
}),
});
const validSdlCheck = await token
.checkSchema(validSdl, 'serviceA')
.then(r => r.expectNoGraphQLErrors());
expect(validSdlCheck.schemaCheck).toMatchObject({
valid: true,
__typename: 'SchemaCheckSuccess',
changes: expect.objectContaining({
total: 0,
}),
});
const result = await token
.publishSchema({
sdl: validSdl,
service: 'serviceA',
url: 'http://localhost:4000',
})
.then(r => r.expectNoGraphQLErrors());
expect(result.schemaPublish).toMatchObject({
valid: true,
linkToWebsite: expect.any(String),
});
if (
!('linkToWebsite' in result.schemaPublish) ||
!('linkToWebsite' in invalidPublish.schemaPublish) ||
!('linkToWebsite' in validPublish.schemaPublish)
) {
throw new Error('linkToWebsite not found');
}
// If the linkToWebsite is the same as one of the previous versions,
// the schema publish was ignored due to unchanged input schemas.
// It shouldn't be the case.
// That's what we're checking here.
expect(result.schemaPublish.linkToWebsite).not.toEqual(
invalidPublish.schemaPublish.linkToWebsite,
);
expect(result.schemaPublish.linkToWebsite).not.toEqual(
validPublish.schemaPublish.linkToWebsite,
);
const ignoredResult = await token
.publishSchema({
sdl: validSdl,
service: 'serviceA',
url: 'http://localhost:4000',
})
.then(r => r.expectNoGraphQLErrors());
// This time the schema publish should be ignored
// and link to the previous version
expect(ignoredResult.schemaPublish).toMatchObject({
valid: true,
linkToWebsite: result.schemaPublish.linkToWebsite,
});
},
);
},
);

View file

@ -175,10 +175,6 @@ describe('dev --remote', () => {
const { secret } = await createTargetAccessToken({});
const cli = createCLI({ readwrite: secret, readonly: secret });
// Once we ship native federation v2 composition by default, we can remove these two lines
await setFeatureFlag('compareToPreviousComposableVersion', true);
await setNativeFederation(true);
await cli.publish({
sdl: /* GraphQL */ `
extend schema @link(url: "https://specs.apollo.dev/federation/v2.3", import: ["@key"])
@ -255,10 +251,6 @@ describe('dev --remote', () => {
const { secret } = await createTargetAccessToken({});
const cli = createCLI({ readwrite: secret, readonly: secret });
// Once we ship native federation v2 composition by default, we can remove these two lines
await setFeatureFlag('compareToPreviousComposableVersion', true);
await setNativeFederation(true);
await cli.publish({
sdl: /* GraphQL */ `
extend schema @link(url: "https://specs.apollo.dev/federation/v2.3", import: ["@key"])

View file

@ -14,8 +14,6 @@ const options = ['targetWithNativeComposition', 'targetWithLegacyComposition'] a
describe('publish', () => {
describe.concurrent.each(options)('%s', caseName => {
const legacyComposition = isLegacyComposition(caseName);
test.concurrent('accepted: composable', async () => {
const {
cli: { publish },
@ -55,26 +53,23 @@ describe('publish', () => {
});
});
test.concurrent(
`${legacyComposition ? 'rejected' : 'accepted'}: not composable (graphql errors)`,
async () => {
const {
cli: { publish },
} = await prepare(caseName);
test.concurrent(`accepted: not composable (graphql errors)`, async () => {
const {
cli: { publish },
} = await prepare(caseName);
// non-composable
await publish({
sdl: /* GraphQL */ `
type Query {
topProduct: Product
}
`,
serviceName: 'products',
serviceUrl: 'http://products:3000/graphql',
expect: legacyComposition ? 'rejected' : 'latest',
});
},
);
// non-composable
await publish({
sdl: /* GraphQL */ `
type Query {
topProduct: Product
}
`,
serviceName: 'products',
serviceUrl: 'http://products:3000/graphql',
expect: 'latest',
});
});
test.concurrent('accepted: composable, previous version was not', async () => {
const {

View file

@ -44,26 +44,23 @@ describe('publish', () => {
});
});
test.concurrent(
`${legacyComposition ? 'rejected' : 'accepted'}: not composable (graphql errors)`,
async () => {
const {
cli: { publish },
} = await prepare(ffs, legacyComposition);
test.concurrent(`accepted: not composable (graphql errors)`, async () => {
const {
cli: { publish },
} = await prepare(ffs, legacyComposition);
// non-composable
await publish({
sdl: /* GraphQL */ `
type Query {
topProduct: Product
}
`,
serviceName: 'products',
serviceUrl: 'http://products:3000/graphql',
expect: legacyComposition ? 'rejected' : 'latest',
});
},
);
// non-composable
await publish({
sdl: /* GraphQL */ `
type Query {
topProduct: Product
}
`,
serviceName: 'products',
serviceUrl: 'http://products:3000/graphql',
expect: 'latest',
});
});
test.concurrent('accepted: composable, previous version was not', async () => {
const {

View file

@ -7,10 +7,6 @@ export type FeatureFlags = [string, FFValue][];
export const cases = [
['default' as const, [] as FeatureFlags],
[
'compareToPreviousComposableVersion' as const,
[['compareToPreviousComposableVersion', true]] as FeatureFlags,
],
['@apollo/federation' as const, [] as FeatureFlags],
] as const;

View file

@ -3,288 +3,118 @@ import { normalizeCliOutput } from '../../../scripts/serializers/cli-output';
import { createCLI } from '../../testkit/cli';
import { prepareProject } from '../../testkit/registry-models';
const cases = [
['default' as const, [] as [string, boolean][]],
[
'compareToPreviousComposableVersion' as const,
[['compareToPreviousComposableVersion', true]] as [string, boolean][],
],
] as Array<['default' | 'compareToPreviousComposableVersion', Array<[string, boolean]>]>;
describe('publish', () => {
describe.concurrent.each(cases)('%s', (caseName, ffs) => {
test.concurrent('accepted: composable', async () => {
const {
cli: { publish },
} = await prepare(ffs);
await publish({
sdl: `type Query { topProductName: String }`,
expect: 'latest-composable',
});
});
test.concurrent('accepted: composable, breaking changes', async () => {
const {
cli: { publish },
} = await prepare(ffs);
await publish({
sdl: /* GraphQL */ `
type Query {
topProductName: String
}
`,
expect: 'latest-composable',
});
await publish({
sdl: /* GraphQL */ `
type Query {
nooooo: String
}
`,
expect: 'latest-composable',
});
});
test.concurrent(
`${caseName === 'default' ? 'rejected' : 'accepted'}: not composable (graphql errors)`,
async () => {
const {
cli: { publish },
} = await prepare(ffs);
await publish({
sdl: /* GraphQL */ `
type Query {
topProduct: Product
}
`,
expect: caseName === 'default' ? 'rejected' : 'latest',
});
},
);
test.concurrent('accepted: composable, no changes', async () => {
const {
cli: { publish },
} = await prepare(ffs);
// composable
await publish({
sdl: /* GraphQL */ `
type Query {
topProduct: String
}
`,
metadata: { version: 'v1' },
expect: 'latest-composable',
});
// composable but no changes
await publish({
sdl: /* GraphQL */ `
type Query {
topProduct: String
}
`,
metadata: { version: 'v1' },
expect: 'ignored',
});
});
test.concurrent('accepted: composable, no changes but modified metadata', async () => {
const {
cli: { publish },
} = await prepare(ffs);
// composable
await publish({
sdl: /* GraphQL */ `
type Query {
topProduct: String
}
`,
metadata: { version: 'v1' },
expect: 'latest-composable',
});
// composable but no changes with modified metadata
await publish({
sdl: /* GraphQL */ `
type Query {
topProduct: String
}
`,
metadata: { version: 'v2' },
expect: 'latest-composable',
});
});
test.concurrent('CLI output', async ({ expect }) => {
const {
cli: { publish },
} = await prepare(ffs);
let output = normalizeCliOutput(
(await publish({
sdl: /* GraphQL */ `
type Query {
topProduct: Product
}
type Product {
id: ID!
name: String!
}
`,
expect: 'latest-composable',
})) ?? '',
);
expect(output).toEqual(expect.stringContaining(`v Published initial schema.`));
expect(output).toEqual(
expect.stringContaining(`i Available at $appUrl/$organization/$project/$target`),
);
output = normalizeCliOutput(
(await publish({
sdl: /* GraphQL */ `
type Query {
topProduct: Product
}
type Product {
id: ID!
name: String!
price: Int!
}
`,
expect: 'latest-composable',
})) ?? '',
);
expect(output).toEqual(expect.stringContaining(`v Schema published`));
expect(output).toEqual(
expect.stringContaining(
`i Available at $appUrl/$organization/$project/$target/history/$version`,
),
);
test.concurrent('accepted: composable', async () => {
const {
cli: { publish },
} = await prepare();
await publish({
sdl: `type Query { topProductName: String }`,
expect: 'latest-composable',
});
});
});
describe('check', () => {
describe.concurrent.each(cases)('%s', (_, ffs) => {
test.concurrent('accepted: composable, no breaking changes', async () => {
const {
cli: { publish, check },
} = await prepare(ffs);
await publish({
sdl: /* GraphQL */ `
type Query {
topProduct: String
}
`,
expect: 'latest-composable',
});
const message = await check({
sdl: /* GraphQL */ `
type Query {
topProduct: String
topProductName: String
}
`,
expect: 'approved',
});
expect(message).toMatch('topProductName');
test.concurrent('accepted: composable, breaking changes', async () => {
const {
cli: { publish },
} = await prepare();
await publish({
sdl: /* GraphQL */ `
type Query {
topProductName: String
}
`,
expect: 'latest-composable',
});
test.concurrent('accepted: no changes', async () => {
const {
cli: { publish, check },
} = await prepare(ffs);
await publish({
sdl: /* GraphQL */ `
type Query {
nooooo: String
}
`,
expect: 'latest-composable',
});
});
await publish({
sdl: /* GraphQL */ `
type Query {
topProduct: String
}
`,
expect: 'latest-composable',
});
test.concurrent(`accepted: not composable (graphql errors)`, async () => {
const {
cli: { publish },
} = await prepare();
await check({
sdl: /* GraphQL */ `
type Query {
topProduct: String
}
`,
expect: 'approved',
});
await publish({
sdl: /* GraphQL */ `
type Query {
topProduct: Product
}
`,
expect: 'rejected',
});
});
test.concurrent('accepted: composable, no changes', async () => {
const {
cli: { publish },
} = await prepare();
// composable
await publish({
sdl: /* GraphQL */ `
type Query {
topProduct: String
}
`,
metadata: { version: 'v1' },
expect: 'latest-composable',
});
test.concurrent('rejected: composable, breaking changes', async () => {
const {
cli: { publish, check },
} = await prepare(ffs);
// composable but no changes
await publish({
sdl: /* GraphQL */ `
type Query {
topProduct: String
}
`,
metadata: { version: 'v1' },
expect: 'ignored',
});
});
await publish({
sdl: /* GraphQL */ `
type Query {
topProduct: String
}
`,
expect: 'latest-composable',
});
test.concurrent('accepted: composable, no changes but modified metadata', async () => {
const {
cli: { publish },
} = await prepare();
const message = await check({
sdl: /* GraphQL */ `
type Query {
topProductName: String
}
`,
expect: 'rejected',
});
expect(message).toMatch('removed');
// composable
await publish({
sdl: /* GraphQL */ `
type Query {
topProduct: String
}
`,
metadata: { version: 'v1' },
expect: 'latest-composable',
});
test.concurrent('rejected: not composable, no breaking changes', async () => {
const {
cli: { publish, check },
} = await prepare(ffs);
await publish({
sdl: /* GraphQL */ `
type Query {
topProduct: String
}
`,
expect: 'latest-composable',
});
const message = await check({
sdl: /* GraphQL */ `
type Query {
topProduct: String
topProductName: Strin
}
`,
expect: 'rejected',
});
expect(message).toMatch('Strin');
// composable but no changes with modified metadata
await publish({
sdl: /* GraphQL */ `
type Query {
topProduct: String
}
`,
metadata: { version: 'v2' },
expect: 'latest-composable',
});
});
test.concurrent('rejected: not composable, breaking changes', async () => {
const {
cli: { publish, check },
} = await prepare(ffs);
test.concurrent('CLI output', async ({ expect }) => {
const {
cli: { publish },
} = await prepare();
await publish({
let output = normalizeCliOutput(
(await publish({
sdl: /* GraphQL */ `
type Query {
topProduct: Product
@ -292,84 +122,235 @@ describe('check', () => {
type Product {
id: ID!
name: String
name: String!
}
`,
expect: 'latest-composable',
});
})) ?? '',
);
const message = await check({
expect(output).toEqual(expect.stringContaining(`v Published initial schema.`));
expect(output).toEqual(
expect.stringContaining(`i Available at $appUrl/$organization/$project/$target`),
);
output = normalizeCliOutput(
(await publish({
sdl: /* GraphQL */ `
type Query {
product(id: ID!): Product
topProduct: Product
}
type Product {
id: ID!
name: Str
name: String!
price: Int!
}
`,
expect: 'rejected',
});
expect: 'latest-composable',
})) ?? '',
);
expect(message).toMatch('Str');
expect(output).toEqual(expect.stringContaining(`v Schema published`));
expect(output).toEqual(
expect.stringContaining(
`i Available at $appUrl/$organization/$project/$target/history/$version`,
),
);
});
});
describe('check', () => {
test.concurrent('accepted: composable, no breaking changes', async () => {
const {
cli: { publish, check },
} = await prepare();
await publish({
sdl: /* GraphQL */ `
type Query {
topProduct: String
}
`,
expect: 'latest-composable',
});
const message = await check({
sdl: /* GraphQL */ `
type Query {
topProduct: String
topProductName: String
}
`,
expect: 'approved',
});
expect(message).toMatch('topProductName');
});
test.concurrent('accepted: no changes', async () => {
const {
cli: { publish, check },
} = await prepare();
await publish({
sdl: /* GraphQL */ `
type Query {
topProduct: String
}
`,
expect: 'latest-composable',
});
await check({
sdl: /* GraphQL */ `
type Query {
topProduct: String
}
`,
expect: 'approved',
});
});
test.concurrent('rejected: composable, breaking changes', async () => {
const {
cli: { publish, check },
} = await prepare();
await publish({
sdl: /* GraphQL */ `
type Query {
topProduct: String
}
`,
expect: 'latest-composable',
});
const message = await check({
sdl: /* GraphQL */ `
type Query {
topProductName: String
}
`,
expect: 'rejected',
});
expect(message).toMatch('removed');
});
test.concurrent('rejected: not composable, no breaking changes', async () => {
const {
cli: { publish, check },
} = await prepare();
await publish({
sdl: /* GraphQL */ `
type Query {
topProduct: String
}
`,
expect: 'latest-composable',
});
const message = await check({
sdl: /* GraphQL */ `
type Query {
topProduct: String
topProductName: Strin
}
`,
expect: 'rejected',
});
expect(message).toMatch('Strin');
});
test.concurrent('rejected: not composable, breaking changes', async () => {
const {
cli: { publish, check },
} = await prepare();
await publish({
sdl: /* GraphQL */ `
type Query {
topProduct: Product
}
type Product {
id: ID!
name: String
}
`,
expect: 'latest-composable',
});
const message = await check({
sdl: /* GraphQL */ `
type Query {
product(id: ID!): Product
}
type Product {
id: ID!
name: Str
}
`,
expect: 'rejected',
});
expect(message).toMatch('Str');
});
});
describe('delete', () => {
describe.concurrent.each(cases)('%s', (_, ffs) => {
test.concurrent('not supported', async () => {
const { cli } = await prepare(ffs);
test.concurrent('not supported', async () => {
const { cli } = await prepare();
await cli.delete({
serviceName: 'test',
expect: 'rejected',
});
await cli.delete({
serviceName: 'test',
expect: 'rejected',
});
});
});
describe('others', () => {
describe.concurrent.each(cases)('%s', (_, ffs) => {
test.concurrent('metadata should always be published as an array', async () => {
const { cli, cdn } = await prepare(ffs);
test.concurrent('metadata should always be published as an array', async () => {
const { cli, cdn } = await prepare();
await cli.publish({
sdl: /* GraphQL */ `
type Query {
topProduct: String
}
`,
metadata: { version: 'v1' },
expect: 'latest-composable',
});
await expect(cdn.fetchMetadata()).resolves.toEqual(
expect.objectContaining({
status: 200,
body: { version: 'v1' }, // not an array
}),
);
await cli.publish({
sdl: /* GraphQL */ `
type Query {
topProduct: String
topProducts: [String]
}
`,
metadata: { version: 'v2' },
expect: 'latest-composable',
});
await expect(cdn.fetchMetadata()).resolves.toEqual(
expect.objectContaining({
status: 200,
body: { version: 'v2' }, // not an array
}),
);
await cli.publish({
sdl: /* GraphQL */ `
type Query {
topProduct: String
}
`,
metadata: { version: 'v1' },
expect: 'latest-composable',
});
await expect(cdn.fetchMetadata()).resolves.toEqual(
expect.objectContaining({
status: 200,
body: { version: 'v1' }, // not an array
}),
);
await cli.publish({
sdl: /* GraphQL */ `
type Query {
topProduct: String
topProducts: [String]
}
`,
metadata: { version: 'v2' },
expect: 'latest-composable',
});
await expect(cdn.fetchMetadata()).resolves.toEqual(
expect.objectContaining({
status: 200,
body: { version: 'v2' }, // not an array
}),
);
});
});

File diff suppressed because it is too large Load diff

View file

@ -15,7 +15,6 @@ import {
buildSchemaCheckFailureState,
ContractCheckInput,
ContractInput,
DeleteFailureReasonCode,
isContractChecksSuccessful,
PublishFailureReasonCode,
PublishIgnoreReasonCode /* Check */,
@ -116,7 +115,6 @@ export class CompositeModel {
contracts,
failDiffOnDangerousChange,
filterNestedChanges,
compareToLatestComposableVersion,
}: {
input: Pick<CompositeSchemaInput, 'sdl' | 'serviceName'> & {
// for a schema check the service url is optional
@ -144,7 +142,6 @@ export class CompositeModel {
approvedChanges: Map<string, SchemaChangeType>;
conditionalBreakingChangeDiffConfig: null | ConditionalBreakingChangeDiffConfig;
failDiffOnDangerousChange: null | boolean;
compareToLatestComposableVersion: boolean;
contracts: Array<
ContractInput & {
approvedChanges: Map<string, SchemaChangeType> | null;
@ -166,7 +163,6 @@ export class CompositeModel {
const schemaSwapResult = latest ? swapServices(latest.schemas, incoming) : null;
const schemas = schemaSwapResult ? schemaSwapResult.schemas : [incoming];
schemas.sort((a, b) => a.serviceName.localeCompare(b.serviceName));
const comparedVersion = compareToLatestComposableVersion ? latestComposable : latest;
const checksumCheck = await this.checks.checksum({
existing: schemaSwapResult?.existing
@ -207,7 +203,7 @@ export class CompositeModel {
});
const previousVersionSdl = await this.checks.retrievePreviousVersionSdl({
version: comparedVersion,
version: latestComposable,
organization,
project,
targetId: selector.targetId,
@ -318,7 +314,6 @@ export class CompositeModel {
contracts,
conditionalBreakingChangeDiffConfig,
failDiffOnDangerousChange,
compareToLatestComposableVersion,
}: {
input: {
sdl: string;
@ -344,7 +339,6 @@ export class CompositeModel {
contracts: Array<ContractInput> | null;
conditionalBreakingChangeDiffConfig: null | ConditionalBreakingChangeDiffConfig;
failDiffOnDangerousChange: null | boolean;
compareToLatestComposableVersion: boolean;
}): Promise<SchemaPublishResult> {
const latestSchemaVersion = latest;
const latestServiceVersion = latest?.schemas?.find(
@ -382,9 +376,6 @@ export class CompositeModel {
const schemas = schemaSwapResult?.schemas ?? [incoming];
schemas.sort((a, b) => a.serviceName.localeCompare(b.serviceName));
const schemaVersionToCompareAgainst = compareToLatestComposableVersion
? latestComposable
: latest;
const checksumCheck = await this.checks.checksum({
existing: schemaSwapResult?.existing
@ -452,24 +443,8 @@ export class CompositeModel {
};
}
if (
compositionCheck.status === 'failed' &&
compositionCheck.reason.errorsBySource.graphql.length > 0 &&
!compareToLatestComposableVersion
) {
return {
conclusion: SchemaPublishConclusion.Reject,
reasons: [
{
code: PublishFailureReasonCode.CompositionFailure,
compositionErrors: compositionCheck.reason.errorsBySource.graphql,
},
],
};
}
const previousVersionSdl = await this.checks.retrievePreviousVersionSdl({
version: schemaVersionToCompareAgainst,
version: latestComposable,
organization,
project,
targetId: target.id,
@ -491,7 +466,7 @@ export class CompositeModel {
const diffCheck = await this.checks.diff({
conditionalBreakingChangeConfig: conditionalBreakingChangeDiffConfig,
includeUrlChanges: {
schemasBefore: schemaVersionToCompareAgainst?.schemas ?? [],
schemasBefore: latestComposable?.schemas ?? [],
schemasAfter: schemas,
},
filterOutFederationChanges: project.type === ProjectType.FEDERATION,
@ -571,7 +546,6 @@ export class CompositeModel {
conditionalBreakingChangeDiffConfig,
contracts,
failDiffOnDangerousChange,
compareToLatestComposableVersion,
}: {
input: {
serviceName: string;
@ -597,7 +571,6 @@ export class CompositeModel {
contracts: Array<ContractInput> | null;
conditionalBreakingChangeDiffConfig: null | ConditionalBreakingChangeDiffConfig;
failDiffOnDangerousChange: null | boolean;
compareToLatestComposableVersion: boolean;
}): Promise<SchemaDeleteResult> {
const latestVersion = latest;
@ -623,7 +596,7 @@ export class CompositeModel {
});
const previousVersionSdl = await this.checks.retrievePreviousVersionSdl({
version: compareToLatestComposableVersion ? latestComposable : latest,
version: latestComposable,
organization,
project,
targetId: selector.target,
@ -665,23 +638,6 @@ export class CompositeModel {
getAffectedAppDeployments: getAffectedAppDeploymentsForDelete,
});
if (
compositionCheck.status === 'failed' &&
compositionCheck.reason.errorsBySource.graphql.length > 0
) {
if (!compareToLatestComposableVersion) {
return {
conclusion: SchemaDeleteConclusion.Reject,
reasons: [
{
code: DeleteFailureReasonCode.CompositionFailure,
compositionErrors: compositionCheck.reason.errorsBySource.graphql,
},
],
};
}
}
const { changes, breakingChanges } =
diffCheck.status === 'failed'
? {

View file

@ -92,9 +92,6 @@ export class SingleModel {
};
const schemas = [incoming] as [SingleSchemaInput];
const comparedVersion = organization.featureFlags.compareToPreviousComposableVersion
? latestComposable
: latest;
const checksumResult = await this.checks.checksum({
existing: latest
@ -126,7 +123,7 @@ export class SingleModel {
});
const previousVersionSdl = await this.checks.retrievePreviousVersionSdl({
version: comparedVersion,
version: latestComposable,
organization,
project,
targetId: selector.targetId,
@ -236,9 +233,6 @@ export class SingleModel {
const latestVersion = latest;
const schemas = [incoming] as [SingleSchemaInput];
const compareToPreviousComposableVersion =
organization.featureFlags.compareToPreviousComposableVersion;
const comparedVersion = compareToPreviousComposableVersion ? latestComposable : latest;
const checksumCheck = await this.checks.checksum({
existing: latest
@ -276,8 +270,23 @@ export class SingleModel {
contracts: null,
});
if (
compositionCheck.status === 'failed' &&
compositionCheck.reason.errorsBySource.graphql.length > 0
) {
return {
conclusion: SchemaPublishConclusion.Reject,
reasons: [
{
code: PublishFailureReasonCode.CompositionFailure,
compositionErrors: compositionCheck.reason.errorsBySource.graphql,
},
],
};
}
const previousVersionSdl = await this.checks.retrievePreviousVersionSdl({
version: comparedVersion,
version: latestComposable,
organization,
project,
targetId: target.id,
@ -331,23 +340,6 @@ export class SingleModel {
messages.push('Metadata has been updated');
}
if (
compositionCheck.status === 'failed' &&
compositionCheck.reason.errorsBySource.graphql.length > 0
) {
if (organization.featureFlags.compareToPreviousComposableVersion === false) {
return {
conclusion: SchemaPublishConclusion.Reject,
reasons: [
{
code: PublishFailureReasonCode.CompositionFailure,
compositionErrors: compositionCheck.reason.errorsBySource.graphql,
},
],
};
}
}
return {
conclusion: SchemaPublishConclusion.Publish,
state: {

View file

@ -1096,7 +1096,7 @@ export class SchemaManager {
};
}
async getVersionBeforeVersionId(args: {
async getComposableVersionBeforeVersionId(args: {
organization: string;
project: string;
target: string;
@ -1105,21 +1105,11 @@ export class SchemaManager {
}) {
this.logger.debug('Fetch version before version id. (args=%o)', args);
const [organization, project] = await Promise.all([
this.storage.getOrganization({
organizationId: args.organization,
}),
this.storage.getProject({
organizationId: args.organization,
projectId: args.project,
}),
]);
const schemaVersion = await this.storage.getVersionBeforeVersionId({
targetId: args.target,
beforeVersionId: args.beforeVersionId,
beforeVersionCreatedAt: args.beforeVersionCreatedAt,
onlyComposable: shouldUseLatestComposableVersion(args.target, project, organization),
onlyComposable: true,
});
if (!schemaVersion) {
@ -1362,17 +1352,3 @@ export class SchemaManager {
return null;
}
}
export function shouldUseLatestComposableVersion(
targetId: string,
project: Project,
organization: Organization,
) {
return (
organization.featureFlags.compareToPreviousComposableVersion ||
// If the project is a native federation project, we should compare to the latest composable version
(project.nativeFederation &&
// but only if the target is not forced to use the legacy composition
!organization.featureFlags.forceLegacyCompositionInTargets.includes(targetId))
);
}

View file

@ -61,7 +61,7 @@ import {
toCompositeSchemaInput,
toSingleSchemaInput,
} from './schema-helper';
import { SchemaManager, shouldUseLatestComposableVersion } from './schema-manager';
import { SchemaManager } from './schema-manager';
import { SchemaVersionHelper } from './schema-version-helper';
const schemaCheckCount = new promClient.Counter({
@ -719,11 +719,6 @@ export class SchemaPublisher {
conditionalBreakingChangeDiffConfig:
conditionalBreakingChangeConfiguration?.conditionalBreakingChangeDiffConfig ?? null,
failDiffOnDangerousChange,
compareToLatestComposableVersion: shouldUseLatestComposableVersion(
selector.targetId,
project,
organization,
),
filterNestedChanges: !input.schemaProposalId,
});
break;
@ -1398,12 +1393,6 @@ export class SchemaPublisher {
}),
]);
const compareToLatestComposableVersion = shouldUseLatestComposableVersion(
selector.targetId,
project,
organization,
);
if (!latestVersion || latestVersion.schemas.length === 0) {
throw new HiveError('Registry is empty');
}
@ -1476,18 +1465,8 @@ export class SchemaPublisher {
conditionalBreakingChangeConfiguration?.conditionalBreakingChangeDiffConfig ?? null,
contracts,
failDiffOnDangerousChange,
compareToLatestComposableVersion,
});
let diffSchemaVersionId: string | null = null;
if (compareToLatestComposableVersion && latestComposableVersion) {
diffSchemaVersionId = latestComposableVersion.version.id;
}
if (!compareToLatestComposableVersion && latestVersion) {
diffSchemaVersionId = latestVersion.version.id;
}
if (deleteResult.conclusion === SchemaDeleteConclusion.Accept) {
this.logger.debug('Delete accepted');
if (input.dryRun !== true) {
@ -1497,7 +1476,7 @@ export class SchemaPublisher {
targetId: selector.targetId,
serviceName: input.serviceName,
composable: deleteResult.state.composable,
diffSchemaVersionId,
diffSchemaVersionId: latestComposableVersion?.version.id ?? null,
changes: deleteResult.state.changes,
coordinatesDiff: deleteResult.state.coordinatesDiff,
contracts:
@ -1771,15 +1750,6 @@ export class SchemaPublisher {
})
: null;
const compareToLatestComposableVersion = shouldUseLatestComposableVersion(
target.id,
project,
organization,
);
const comparedSchemaVersion = compareToLatestComposableVersion
? latestComposable
: latestVersion;
const latestSchemaVersionContracts = latestVersion
? await this.contracts.getContractVersionsForSchemaVersion({
schemaVersionId: latestVersion.version.id,
@ -1867,7 +1837,6 @@ export class SchemaPublisher {
conditionalBreakingChangeDiffConfig:
conditionalBreakingChangeConfiguration?.conditionalBreakingChangeDiffConfig ?? null,
failDiffOnDangerousChange,
compareToLatestComposableVersion: compareToLatestComposableVersion,
});
break;
default: {
@ -2009,8 +1978,6 @@ export class SchemaPublisher {
const supergraph = publishResult.state.supergraph ?? null;
const diffSchemaVersionId = comparedSchemaVersion?.version.id ?? null;
this.logger.debug(`Assigning ${schemaLogIds.length} schemas to new version`);
const serviceName = input.service;
@ -2065,7 +2032,7 @@ export class SchemaPublisher {
},
changes,
coordinatesDiff: publishResult.state.coordinatesDiff,
diffSchemaVersionId,
diffSchemaVersionId: latestComposable?.version.id ?? null,
previousSchemaVersion: latestVersion?.version.id ?? null,
conditionalBreakingChangeMetadata: await this.getConditionalBreakingChangeMetadata({
conditionalBreakingChangeConfiguration,

View file

@ -275,7 +275,7 @@ export class SchemaVersionHelper {
return null;
}
return await this.schemaManager.getVersionBeforeVersionId({
return await this.schemaManager.getComposableVersionBeforeVersionId({
organization: schemaVersion.organizationId,
project: schemaVersion.projectId,
target: schemaVersion.targetId,

View file

@ -176,10 +176,6 @@ export interface Organization {
};
getStarted: OrganizationGetStarted;
featureFlags: {
/**
* @deprecated This feature flag is now a default for newly created organizations and projects.
*/
compareToPreviousComposableVersion: boolean;
/**
* Forces selected targets to use @apollo/federation library
* when native composition is enabled for a project.

View file

@ -4902,7 +4902,6 @@ const decodeCDNAccessTokenRecord = (result: unknown): CDNAccessToken => {
const FeatureFlagsModel = zod
.object({
compareToPreviousComposableVersion: zod.boolean().default(false),
forceLegacyCompositionInTargets: zod.array(zod.string()).default([]),
/** whether app deployments are enabled for the given organization */
appDeployments: zod.boolean().default(false),
@ -4916,7 +4915,6 @@ const FeatureFlagsModel = zod
.transform(
val =>
val ?? {
compareToPreviousComposableVersion: false,
forceLegacyCompositionInTargets: [],
appDeployments: false,
otelTracing: false,