Fix publishing of a service right after deleting it (#1326)

This commit is contained in:
Kamil Kisiela 2023-02-09 16:45:36 +01:00 committed by GitHub
parent de21913717
commit 99f7c66a44
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
10 changed files with 136 additions and 6 deletions

View file

@ -0,0 +1,5 @@
---
'@graphql-hive/cli': patch
---
Do not show "Skipping" when publishing schema to the modern model

View file

@ -114,3 +114,111 @@ describe.each`
});
});
});
describe.each`
projectType
${ProjectType.Stitching}
${ProjectType.Federation}
`('$projectType', ({ projectType }) => {
test.concurrent(
'should publish A, publish B, delete B, publish A and have A and B at the end',
async () => {
const { createOrg } = await initSeed().createOwner();
const { createProject } = await createOrg();
const { createToken } = await createProject(projectType);
const { publishSchema, deleteSchema, fetchVersions, fetchLatestValidSchema } =
await createToken({
targetScopes: [TargetAccessScope.RegistryRead, TargetAccessScope.RegistryWrite],
projectScopes: [],
organizationScopes: [],
});
const serviceA = /* GraphQL */ `
type Query {
topProduct: Product
}
type Product {
id: ID!
name: String
}
`;
const serviceB = /* GraphQL */ `
type Query {
topReview: Review
}
type Review {
id: ID!
title: String
}
`;
await publishSchema({
author: 'Kamil',
commit: 'push1',
sdl: serviceA,
service: 'service-a',
url: 'http://localhost:4001',
}).then(r => r.expectNoGraphQLErrors());
await expect(fetchVersions(2)).resolves.toHaveLength(1);
await publishSchema({
author: 'Kamil',
commit: 'push2',
sdl: serviceB,
service: 'service-b',
url: 'http://localhost:4002',
}).then(r => r.expectNoGraphQLErrors());
// We should have 2 versions (push, push)
await expect(fetchVersions(3)).resolves.toHaveLength(2);
await expect(deleteSchema('service-b').then(r => r.expectNoGraphQLErrors())).resolves.toEqual(
expect.objectContaining({
schemaDelete: {
__typename: 'SchemaDeleteSuccess',
},
}),
);
const versions = await fetchVersions(4);
// We should have 3 versions (push, push, delete)
expect(versions).toHaveLength(3);
// Most recent version should be a delete action
expect(versions[0].log).toEqual({
__typename: 'DeletedSchemaLog',
deletedService: 'service-b',
});
await publishSchema({
author: 'Kamil',
commit: 'push3',
sdl: serviceB,
service: 'service-b',
url: 'http://localhost:4002',
}).then(r => r.expectNoGraphQLErrors());
// We should have 4 versions (push, push, delete, push)
await expect(fetchVersions(5)).resolves.toHaveLength(4);
const latestValid = await fetchLatestValidSchema();
expect(latestValid.latestValidVersion).toBeDefined();
expect(latestValid.latestValidVersion?.log.__typename).toEqual('PushedSchemaLog');
expect(latestValid.latestValidVersion?.schemas.nodes).toHaveLength(2);
expect(latestValid.latestValidVersion?.schemas.nodes).toContainEqual(
expect.objectContaining({
commit: 'push1',
}),
);
expect(latestValid.latestValidVersion?.schemas.nodes).toContainEqual(
expect.objectContaining({
commit: 'push3',
}),
);
},
);
});

View file

@ -0,0 +1,9 @@
type User {
id: ID!
username: String!
email: String!
}
type Query {
users(ids: [ID!]!): [User]! @merge(keyField: "id") @canonical
}

View file

@ -38,8 +38,8 @@
"prepack": "rimraf lib && tsc -b && oclif manifest && oclif readme",
"schema:check:federation": "pnpm start schema:check examples/federation.graphql --service reviews",
"schema:check:single": "pnpm start schema:check examples/single.graphql",
"schema:check:stitching": "pnpm start schema:check examples/stitching.graphql --service posts",
"schema:publish:federation": "pnpm start schema:publish --service reviews examples/federation.reviews.graphql",
"schema:check:stitching": "pnpm start schema:check --service posts examples/stitching.posts.graphql",
"schema:publish:federation": "pnpm start schema:publish --service reviews --url reviews.com/graphql examples/federation.reviews.graphql",
"start": "./bin/dev",
"version": "oclif readme && git add README.md"
},

View file

@ -194,10 +194,12 @@ export default class SchemaPublish extends Command {
this.success('Published initial schema.');
} else if (result.schemaPublish.successMessage) {
this.success(result.schemaPublish.successMessage);
} else if (!changes?.total) {
} else if (changes && changes.total === 0) {
this.success('No changes. Skipping.');
} else {
renderChanges.call(this, changes);
if (changes) {
renderChanges.call(this, changes);
}
this.success('Schema published');
}

View file

@ -55,6 +55,11 @@ export class RegistryChecks {
constructor(private helper: SchemaHelper, private inspector: Inspector, private logger: Logger) {}
async checksum({ schemas, latestVersion }: { schemas: Schemas; latestVersion: LatestVersion }) {
this.logger.debug(
'Checksum check (before=%s, after=%s)',
latestVersion?.schemas.length ?? 0,
schemas.length,
);
const isInitial = latestVersion === null;
if (isInitial) {

View file

@ -325,7 +325,7 @@ export class SchemaPublisher {
await unlock();
}
},
ttl: 60,
ttl: 15,
span,
});
}

View file

@ -1,3 +1,4 @@
LOG_LEVEL=debug
POSTGRES_USER=postgres
POSTGRES_PASSWORD=postgres
POSTGRES_HOST=localhost

View file

@ -1732,7 +1732,7 @@ export async function createStorage(connection: string, maximumPoolSize: number)
FROM public.schema_versions as sv
LEFT JOIN public.targets as t ON (t.id = sv.target_id)
LEFT JOIN public.schema_log as sl ON (sl.id = sv.action_id)
WHERE t.id = ${target} AND t.project_id = ${project} AND sl.action = 'PUSH'
WHERE t.id = ${target} AND t.project_id = ${project}
ORDER BY sv.created_at DESC
LIMIT 1
`);