Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Add the schema coordinate to all CompositionHints in composition-js #2658

Conversation

swcollard
Copy link
Contributor

@swcollard swcollard commented Jul 6, 2023

Overview

As part of pulling Composition Hints and all build messages into Apollo Studio and GraphOS we want to align on specifying errors, warnings, and lint errors around the schema coordinate. The easiest way to start aligning all those would be to include the schema coordinate in the Composition Hint. This PR adds the optional String to the CompositionHint class and implements setting the coordinate in all instances where CompositionHint objects are constructed.

Changes

  • Expand the CompositionHint class to include an optional String coordinate
  • In every instance of creating a CompositionHint object, include the coordinate or the string that seems closest to the coordinate?

Testing

Expanded existing unit tests to also verify the coordinate is correct

@swcollard swcollard requested a review from a team as a code owner July 6, 2023 14:29
@netlify
Copy link

netlify bot commented Jul 6, 2023

‼️ Deploy request for apollo-federation-docs rejected.

Name Link
🔨 Latest commit 50861949f6ca810df97a8fa05fc60faffbe3693f

@changeset-bot
Copy link

changeset-bot bot commented Jul 6, 2023

🦋 Changeset detected

Latest commit: 187e036

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 7 packages
Name Type
@apollo/composition Minor
@apollo/gateway Minor
@apollo/federation-internals Minor
@apollo/query-planner Minor
@apollo/query-graphs Minor
@apollo/subgraph Minor
apollo-federation-integration-testsuite Minor

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@codesandbox-ci
Copy link

codesandbox-ci bot commented Jul 6, 2023

This pull request is automatically built and testable in CodeSandbox.

To see build info of the built libraries, click here or the icon next to each commit SHA.

@swcollard swcollard force-pushed the swcollard/add-coordinate-to-CompositionHint branch from a1f07fe to c56a570 Compare July 6, 2023 20:44
@@ -390,6 +392,7 @@ export class ComposeDirectiveManager {
this.pushHint(new CompositionHint(
HINTS.DIRECTIVE_COMPOSITION_WARN,
`Composed directive "@${name}" is named differently in a subgraph that doesn't export it. Consistent naming will be required to export it.`,
name,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should this also be prepended with an @?

Comment on lines 676 to 677
const name = dest instanceof NamedSchemaElement ? `Element "${dest.coordinate}"` : 'The schema definition';
const coordinate = dest instanceof NamedSchemaElement ? dest.coordinate : undefined;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since we're already computing this value, we can just reuse it.

Suggested change
const name = dest instanceof NamedSchemaElement ? `Element "${dest.coordinate}"` : 'The schema definition';
const coordinate = dest instanceof NamedSchemaElement ? dest.coordinate : undefined;
const coordinate = dest instanceof NamedSchemaElement ? dest.coordinate : undefined;
const name = coordinate ? `Element "${coordinate}"` : 'The schema definition';

@@ -2468,6 +2489,7 @@ class Merger {
this.mismatchReporter.pushHint(new CompositionHint(
HINTS.MERGED_NON_REPEATABLE_DIRECTIVE_ARGUMENTS,
`Directive @${name} is applied to "${(dest as any)['coordinate'] ?? dest}" in multiple subgraphs with different arguments. Merging strategies used by arguments: ${info.argumentsMerger}`,
name,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Need an @ here as well?

@@ -2468,6 +2489,7 @@ class Merger {
this.mismatchReporter.pushHint(new CompositionHint(
HINTS.MERGED_NON_REPEATABLE_DIRECTIVE_ARGUMENTS,
`Directive @${name} is applied to "${(dest as any)['coordinate'] ?? dest}" in multiple subgraphs with different arguments. Merging strategies used by arguments: ${info.argumentsMerger}`,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe we can compute the coordinate like this instead (and reuse it here and below where we're doing the other as any cast)?

const coordinate = `${'coordinate' in dest && dest.coordinate ? dest.coordinate : dest}`;

@@ -143,6 +143,7 @@ export class ComposeDirectiveManager {
this.pushHint(new CompositionHint(
HINTS.DIRECTIVE_COMPOSITION_INFO,
`Non-composed core feature "${coreIdentity}" has major version mismatch across subgraphs`,
coreIdentity,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It looks like our testing story is a bit inconsistent, which is not your fault.

i.e. if I change this to, say, undefined, tests still pass. But if I remove the this.pushHint(...) there is a test that fails (which doesn't use the toRaiseHint matcher.

I'd like it if we addressed these inconsistencies so there's coverage for all of your additions. Let me know if you'd like me to help with that, since I think that's an "us" problem.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note: this is the only one I checked, so for now I'm not checking the others or leaving comments on them.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pretty sure if we get the testing story consistent it'll reveal the directive name errors that I pointed out above (or reveal that we're just lacking coverage on those particular hints altogether).

@trevor-scheer
Copy link
Member

Please add a minor changeset by running npx changeset and following the prompts

@@ -174,6 +175,7 @@ export class ComposeDirectiveManager {
this.pushHint(new CompositionHint(
HINTS.DIRECTIVE_COMPOSITION_INFO,
`Directive "@${directive.name}" should not be explicitly manually composed since it is a federation directive composed by default`,
`@${directive.name}`,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we should avoid manually crafting any coordinate when the coordinate property exists.

In fact, see my suggestion on the ctor of CompositionHint which would pretty much guarantee this by design.

@@ -235,6 +235,7 @@ export class CompositionHint {
constructor(
readonly definition: HintCodeDefinition,
readonly message: string,
readonly coordinate: string | undefined,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would suggest changing this argument to be the (main) element that is the target of the hint, so something like:

export class CompositionHint {
  public readonly nodes?: readonly SubgraphASTNode[];
  public readonly coordinate?: string;
  
  constructor(
    readonly definition: HintCodeDefinition,
    readonly message: string,
    element: NamedSchemaElement | undefined,
  ) {
    this.coordinate = element?.coordinate;
    ....
  }
  ...
}

Imo this has a bunch of advantages:

  • this is more precisely typed. string is not the most helpful type: it's really easy to pass something that isn't a valid coordinate and have this go undetected. Passing NamedSchemaElement makes it less error prone and guaranteed we will get a valid coordinate at the end of the day.
  • practically, this avoid having to repeat .coodinate on almost all callsite, which feel kinda nice.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the review! This makes sense to me, I will make this change and post a new revision

@@ -112,6 +113,7 @@ export class MismatchReporter {
message: string,
supergraphElement: TMismatched,
subgraphElements: (TMismatched | undefined)[],
coordinate: string | undefined,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same remarks as in CompositionHint: we should imo pass element: NamedSchemaElement | undefined.

In fact, it's worth double checking, but I suspect we can avoid the need of that argument, at least in most case, as supergraphElement is usually what we want here (when it is a NamedSchemaElement at least; and when it isn't, we want undefined). From a quick look, it seems that there is 2 special cases where that's not quite true, for hints on enum values and union members where supergraphElement is the type itself, but we ideally would want to pass the value/member itself. But I'd personally suggest adding an optional argument (say, targetedElement?: NamedSchemaElement and only pass it when it's not equal to supergraphElement (and default to the later when targetedElement is not provided).

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You were correct, I noticed that while going through and fixing unit tests. I have added the targetedElement?: NamedSchemaElement to this function and filled in it for the Enum value cases.

@pcmanus pcmanus changed the base branch from main to next July 11, 2023 14:45
@pcmanus pcmanus merged commit aac2893 into apollographql:next Jul 11, 2023
trevor-scheer added a commit that referenced this pull request Aug 25, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants