diff --git a/.changeset/tasty-lemons-vanish.md b/.changeset/tasty-lemons-vanish.md new file mode 100644 index 000000000..74b8f580d --- /dev/null +++ b/.changeset/tasty-lemons-vanish.md @@ -0,0 +1,5 @@ +--- +'@graphql-hive/cli': patch +--- + +Do not show "Skipping" when publishing schema to the modern model diff --git a/integration-tests/tests/api/schema/composite.spec.ts b/integration-tests/tests/api/schema/composite.spec.ts index c22a94c40..4e2a7ccf5 100644 --- a/integration-tests/tests/api/schema/composite.spec.ts +++ b/integration-tests/tests/api/schema/composite.spec.ts @@ -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', + }), + ); + }, + ); +}); diff --git a/packages/libraries/cli/examples/stitching.graphql b/packages/libraries/cli/examples/stitching.posts.graphql similarity index 100% rename from packages/libraries/cli/examples/stitching.graphql rename to packages/libraries/cli/examples/stitching.posts.graphql diff --git a/packages/libraries/cli/examples/stitching.users.graphql b/packages/libraries/cli/examples/stitching.users.graphql new file mode 100644 index 000000000..2afa6f966 --- /dev/null +++ b/packages/libraries/cli/examples/stitching.users.graphql @@ -0,0 +1,9 @@ +type User { + id: ID! + username: String! + email: String! +} + +type Query { + users(ids: [ID!]!): [User]! @merge(keyField: "id") @canonical +} diff --git a/packages/libraries/cli/package.json b/packages/libraries/cli/package.json index 5273c6b4b..27939fb9f 100644 --- a/packages/libraries/cli/package.json +++ b/packages/libraries/cli/package.json @@ -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" }, diff --git a/packages/libraries/cli/src/commands/schema/publish.ts b/packages/libraries/cli/src/commands/schema/publish.ts index cc7eebe46..4aa4e2833 100644 --- a/packages/libraries/cli/src/commands/schema/publish.ts +++ b/packages/libraries/cli/src/commands/schema/publish.ts @@ -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'); } diff --git a/packages/services/api/src/modules/schema/providers/registry-checks.ts b/packages/services/api/src/modules/schema/providers/registry-checks.ts index f603e8d53..a60c561cc 100644 --- a/packages/services/api/src/modules/schema/providers/registry-checks.ts +++ b/packages/services/api/src/modules/schema/providers/registry-checks.ts @@ -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) { diff --git a/packages/services/api/src/modules/schema/providers/schema-publisher.ts b/packages/services/api/src/modules/schema/providers/schema-publisher.ts index 29fac5f48..4a435be9a 100644 --- a/packages/services/api/src/modules/schema/providers/schema-publisher.ts +++ b/packages/services/api/src/modules/schema/providers/schema-publisher.ts @@ -325,7 +325,7 @@ export class SchemaPublisher { await unlock(); } }, - ttl: 60, + ttl: 15, span, }); } diff --git a/packages/services/server/.env.template b/packages/services/server/.env.template index a056b3386..341dfc6aa 100644 --- a/packages/services/server/.env.template +++ b/packages/services/server/.env.template @@ -1,3 +1,4 @@ +LOG_LEVEL=debug POSTGRES_USER=postgres POSTGRES_PASSWORD=postgres POSTGRES_HOST=localhost diff --git a/packages/services/storage/src/index.ts b/packages/services/storage/src/index.ts index efa08173a..7e7484798 100644 --- a/packages/services/storage/src/index.ts +++ b/packages/services/storage/src/index.ts @@ -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 `);