Skip to content

Commit a98583d

Browse files
fix: retain stitching sdl directives on schema definition nodes (#8094)
Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
1 parent e596ac5 commit a98583d

8 files changed

Lines changed: 89 additions & 125 deletions

File tree

.changeset/easy-emus-move.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'hive': patch
3+
---
4+
5+
Include directives in output SDL for schema stitching projects
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
directive @public on SCHEMA | OBJECT
2+
3+
type Query @public {
4+
isAnExample: Boolean
5+
}

integration-tests/tests/cli/__snapshots__/schema.spec.ts.snap

Lines changed: 0 additions & 123 deletions
Original file line numberDiff line numberDiff line change
@@ -92,14 +92,6 @@ stdout--------------------------------------------:
9292
ℹ Available at http://__URL__
9393
`;
9494

95-
exports[`FEDERATION > can update a service without providing a url if previously published > schemaPublish (initial) 1`] = `
96-
:::::::::::::::: CLI SUCCESS OUTPUT :::::::::::::::::
97-
98-
stdout--------------------------------------------:
99-
✔ Published initial schema.
100-
ℹ Available at http://__URL__
101-
`;
102-
10395
exports[`FEDERATION > can update the service url and show it in comparison query > schemaPublish (initial) 1`] = `
10496
:::::::::::::::: CLI SUCCESS OUTPUT :::::::::::::::::
10597
@@ -361,103 +353,6 @@ stdout--------------------------------------------:
361353
ℹ Available at http://__URL__
362354
`;
363355

364-
exports[`SINGLE > can update a service without providing a url if previously published > schema publish initial 1`] = `
365-
:::::::::::::::: CLI SUCCESS OUTPUT :::::::::::::::::
366-
367-
stdout--------------------------------------------:
368-
✔ Published initial schema.
369-
ℹ Available at http://__URL__
370-
`;
371-
372-
exports[`SINGLE > can update a service without providing a url if previously published > schema publish same url 1`] = ``;
373-
374-
exports[`SINGLE > can update a service without providing a url if previously published > schemaPublish (initial) 1`] = `
375-
:::::::::::::::: CLI SUCCESS OUTPUT :::::::::::::::::
376-
377-
stdout--------------------------------------------:
378-
✔ Published initial schema.
379-
ℹ Available at http://__URL__
380-
`;
381-
382-
exports[`SINGLE > check validates the service name > onlyNumbers 1`] = `
383-
:::::::::::::::: CLI FAILURE OUTPUT :::::::::::::::
384-
exitCode------------------------------------------:
385-
1
386-
stderr--------------------------------------------:
387-
__NONE__
388-
stdout--------------------------------------------:
389-
✖ Detected 1 error
390-
391-
- Invalid service name. Service name must be 64 characters or less, must start with a letter, and can only contain alphanumeric characters, dash (-), underscore (_), or forward slash (/).
392-
393-
394-
`;
395-
396-
exports[`SINGLE > check validates the service name > specialCharacters 1`] = `
397-
:::::::::::::::: CLI FAILURE OUTPUT :::::::::::::::
398-
exitCode------------------------------------------:
399-
1
400-
stderr--------------------------------------------:
401-
__NONE__
402-
stdout--------------------------------------------:
403-
✖ Detected 1 error
404-
405-
- Invalid service name. Service name must be 64 characters or less, must start with a letter, and can only contain alphanumeric characters, dash (-), underscore (_), or forward slash (/).
406-
407-
408-
`;
409-
410-
exports[`SINGLE > check validates the service name > success 1`] = `
411-
:::::::::::::::: CLI SUCCESS OUTPUT :::::::::::::::::
412-
413-
stdout--------------------------------------------:
414-
✔ Schema registry is empty, nothing to compare your schema with.
415-
View full report:
416-
http://__URL__
417-
`;
418-
419-
exports[`SINGLE > publish validates the service name > onlyNumbers 1`] = `
420-
:::::::::::::::: CLI FAILURE OUTPUT :::::::::::::::
421-
exitCode------------------------------------------:
422-
2
423-
stderr--------------------------------------------:
424-
› Error: Schema publish failed. [300]
425-
› > See https://__URL__ for
426-
› a complete list of error codes and recommended fixes.
427-
› To disable this message set HIVE_NO_ERROR_TIP=1
428-
stdout--------------------------------------------:
429-
✖ Detected 1 error
430-
431-
- Invalid service name. Service name must be 64 characters or less, must start with a letter, and can only contain alphanumeric characters, dash (-), underscore (_), or forward slash (/).
432-
433-
434-
`;
435-
436-
exports[`SINGLE > publish validates the service name > specialCharacters 1`] = `
437-
:::::::::::::::: CLI FAILURE OUTPUT :::::::::::::::
438-
exitCode------------------------------------------:
439-
2
440-
stderr--------------------------------------------:
441-
› Error: Schema publish failed. [300]
442-
› > See https://__URL__ for
443-
› a complete list of error codes and recommended fixes.
444-
› To disable this message set HIVE_NO_ERROR_TIP=1
445-
stdout--------------------------------------------:
446-
✖ Detected 1 error
447-
448-
- Invalid service name. Service name must be 64 characters or less, must start with a letter, and can only contain alphanumeric characters, dash (-), underscore (_), or forward slash (/).
449-
450-
451-
`;
452-
453-
exports[`SINGLE > publish validates the service name > success 1`] = `
454-
:::::::::::::::: CLI SUCCESS OUTPUT :::::::::::::::::
455-
456-
stdout--------------------------------------------:
457-
✔ Published initial schema.
458-
ℹ Available at http://__URL__
459-
`;
460-
461356
exports[`SINGLE > publishing invalid schema SDL provides meaningful feedback for the user. > schemaPublish 1`] = `
462357
:::::::::::::::: CLI FAILURE OUTPUT :::::::::::::::
463358
exitCode------------------------------------------:
@@ -629,24 +524,6 @@ stdout--------------------------------------------:
629524
ℹ Available at http://__URL__
630525
`;
631526

632-
exports[`STITCHING > can update a service without providing a url if previously published > schema publish initial 1`] = `
633-
:::::::::::::::: CLI SUCCESS OUTPUT :::::::::::::::::
634-
635-
stdout--------------------------------------------:
636-
✔ Published initial schema.
637-
ℹ Available at http://__URL__
638-
`;
639-
640-
exports[`STITCHING > can update a service without providing a url if previously published > schema publish same url 1`] = ``;
641-
642-
exports[`STITCHING > can update a service without providing a url if previously published > schemaPublish (initial) 1`] = `
643-
:::::::::::::::: CLI SUCCESS OUTPUT :::::::::::::::::
644-
645-
stdout--------------------------------------------:
646-
✔ Published initial schema.
647-
ℹ Available at http://__URL__
648-
`;
649-
650527
exports[`STITCHING > can update the service url and show it in comparison query > schemaPublish (initial) 1`] = `
651528
:::::::::::::::: CLI SUCCESS OUTPUT :::::::::::::::::
652529

integration-tests/tests/cli/schema.spec.ts

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -526,6 +526,47 @@ describe.each([ProjectType.Stitching, ProjectType.Federation, ProjectType.Single
526526
},
527527
);
528528

529+
test
530+
/** federation relies on composeDirective which we don't test here */
531+
.skipIf(projectType === ProjectType.Federation)
532+
.concurrent(
533+
'schema:fetch sdl includes directives on the schema definition',
534+
async ({ expect }) => {
535+
const { createOrg } = await initSeed().createOwner();
536+
const { inviteAndJoinMember, createProject } = await createOrg();
537+
await inviteAndJoinMember();
538+
const { createTargetAccessToken } = await createProject(projectType);
539+
const { secret, latestSchema } = await createTargetAccessToken({});
540+
541+
const cli = createCLI({
542+
readonly: secret,
543+
readwrite: secret,
544+
});
545+
546+
await schemaPublish([
547+
'--registry.accessToken',
548+
secret,
549+
'--author',
550+
'Kamil',
551+
'--commit',
552+
'abc123',
553+
...serviceNameArgs,
554+
...serviceUrlArgs,
555+
'fixtures/schema-with-directives.graphql',
556+
]);
557+
558+
const schema = await latestSchema();
559+
const fetchCmd = cli.fetch({
560+
type: 'sdl',
561+
commit: 'abc123',
562+
});
563+
expect(schema.latestVersion?.sdl).toIncludeSubstringWithoutWhitespace(
564+
'type Query @public',
565+
);
566+
await expect(fetchCmd).resolves.toIncludeSubstringWithoutWhitespace('type Query @public');
567+
},
568+
);
569+
529570
test.concurrent(
530571
'schema:fetch can fetch a latest schema with target:registry:read access',
531572
async ({ expect }) => {

packages/services/schema/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
"@graphql-tools/merge": "9.1.1",
1414
"@graphql-tools/stitch": "9.4.29",
1515
"@graphql-tools/stitching-directives": "3.1.38",
16+
"@graphql-tools/utils": "11.1.0",
1617
"@hive/service-common": "workspace:*",
1718
"@sentry/node": "7.120.2",
1819
"@theguild/federation-composition": "0.22.3",

packages/services/schema/src/composition/stitching.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,13 @@ import {
55
GraphQLSchema,
66
Kind,
77
parse,
8-
printSchema,
98
validateSchema,
109
} from 'graphql';
1110
import { validateSDL } from 'graphql/validation/validate.js';
1211
import { stitchSchemas } from '@graphql-tools/stitch';
1312
import { stitchingDirectives } from '@graphql-tools/stitching-directives';
1413
import { errorWithSource, toValidationError } from '../lib/errors';
14+
import { printCleanSchema } from '../lib/print-clean-schema';
1515
import { trimDescriptions } from '../lib/trim-descriptions';
1616
import type { ComposeAndValidateInput } from '../types';
1717
import type { CompositionErrorType } from './shared';
@@ -86,7 +86,7 @@ export async function composeStitching(args: ComposeStitchingArgs) {
8686
}),
8787
),
8888
});
89-
sdl = printSchema(stitchedSchema);
89+
sdl = printCleanSchema(stitchedSchema);
9090
} catch (error) {
9191
errors.push(toValidationError(error, 'composition'));
9292
}
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
import { GraphQLSchema, Kind, print } from 'graphql';
2+
import { getDocumentNodeFromSchema } from '@graphql-tools/utils';
3+
4+
/** Prints the SDL but excludes the schema definition if it is the standard definition */
5+
export function printCleanSchema(schema: GraphQLSchema): string {
6+
const documentNode = getDocumentNodeFromSchema(schema);
7+
8+
const filteredDefinitions = documentNode.definitions.filter(node => {
9+
if (node.kind === Kind.SCHEMA_DEFINITION) {
10+
const hasDirectives = node.directives && node.directives.length > 0;
11+
const hasDescription = !!node.description;
12+
13+
const isStandardDefinition = node.operationTypes.every(op => {
14+
if (op.operation === 'query' && op.type.name.value === 'Query') return true;
15+
if (op.operation === 'mutation' && op.type.name.value === 'Mutation') return true;
16+
if (op.operation === 'subscription' && op.type.name.value === 'Subscription') return true;
17+
return false;
18+
});
19+
20+
// Omit the block only if it has no directives/descriptions and uses standard names
21+
if (!hasDirectives && !hasDescription && isStandardDefinition) {
22+
return false;
23+
}
24+
}
25+
return true;
26+
});
27+
28+
return print({
29+
...documentNode,
30+
definitions: filteredDefinitions,
31+
});
32+
}

pnpm-lock.yaml

Lines changed: 3 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)