-
-
Notifications
You must be signed in to change notification settings - Fork 205
Add patch package to apply diff changes to schemas #2893
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
base: master
Are you sure you want to change the base?
Conversation
newDirective: GraphQLDirective, | ||
): Change<typeof ChangeType.DirectiveDescriptionChanged> { | ||
return directiveDescriptionChangedFromMeta({ | ||
type: ChangeType.DirectiveDescriptionChanged, | ||
meta: { | ||
directiveName: oldDirective.name, | ||
oldDirectiveDescription: oldDirective.description ?? null, | ||
directiveName: newDirective.name, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In these cases, the type is being used to extract the name only. It doesn't matter if we pass the new or old directive, since the name is the same. However, since calling these functions onAdd
-- the old type can be null, which is why this was changed to pass the new type (newDirective)
|
||
{ | ||
const change = findFirstChangeByPath(changes, 'enumA.A'); | ||
expect(change.criticality.level).toEqual(CriticalityLevel.NonBreaking); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This test shows that enum additions also contain all nested changes within that enum, and that those changes are flagged as non-breaking.
@@ -218,6 +221,7 @@ export function fieldDeprecationRemovedFromMeta(args: FieldDeprecationRemovedCha | |||
return { | |||
type: ChangeType.FieldDeprecationRemoved, | |||
criticality: { | |||
// @todo: Add a reason for why is this dangerous... Why is it?? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
^ very curious why... It doesn't change behavior/how clients interact. "Dangerous" seems extreme.
parentType: type, | ||
field: newField, | ||
}), | ||
directiveUsageAdded( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should this filter out the deprecated directive since that's captured by another change?
@@ -0,0 +1,6 @@ | |||
--- | |||
'@graphql-inspector/core': major |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I could be convinced that this is a minor patch because the changes to the output's format doesnt break anything. But the actual content of the changes has changed drastically which is why I thought we should be safe and declare a major change.
return lastDividerIndex === -1 ? path : path.substring(0, lastDividerIndex); | ||
}; | ||
|
||
export const ignoreNestedAdditions: Rule = ({ changes }) => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This allows us to reduce noise when running the diff. If the parent was added during this change set, then the change will be excluded from the list.
See tests for what this looks like in practice.
expect(change.a.type).toEqual('DIRECTIVE_ARGUMENT_ADDED'); | ||
expect(change.a.message).toEqual(`Argument 'name' was added to directive 'a'`); | ||
expect(change.a?.type).toEqual('DIRECTIVE_ARGUMENT_ADDED'); | ||
expect(change.a?.criticality.level).toEqual(CriticalityLevel.NonBreaking); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In several places I reordered things because when tweaking behavior and testing, t was not providing me enough insights to understand what was wrong. Placing the "type" first let me know which change type was being returned.
@@ -21,13 +21,36 @@ describe('directive-usage', () => { | |||
`); | |||
|
|||
const changes = await diff(a, b); | |||
const change = findFirstChangeByPath(changes, 'Query.a.external'); | |||
const change = findFirstChangeByPath(changes, 'Query.a.@external'); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Adding an indicator for directives is necessary to distinguish them from arguments. This makes the paths more meaningful and useful as lookups.
@@ -690,7 +713,7 @@ describe('directive-usage', () => { | |||
`); | |||
|
|||
const changes = await diff(a, b); | |||
const change = findFirstChangeByPath(changes, 'Foo.external'); | |||
const change = findFirstChangeByPath(changes, '.@external'); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This indicates the directive is applied to the schema object. This .
is necessary to distinguish directive usages from directive definitions at the root level.
isVoid(oldValue?.deprecationReason) || | ||
oldValue?.deprecationReason === DEPRECATION_REASON_DEFAULT | ||
) { | ||
addChange(enumValueDeprecationReasonAdded(newEnum, oldValue, newValue)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thoughts on removing this in favor of only using the directive change for @deprecated
instead of a unique change type?
Description
This change began as one to only the adds fields that are necessary for recreating the patched schema using the input schema and changes array, but it has expanded to also add the patch functionality. I found this was necessary in order to verify that the changes provided sufficient data.
This PR modifies the several change types, and modifies the
onAdded
handlers to also execute equivalent logic toonMutual
. It also adds a new rule that can be added to filter out these additional changes, thus keeping changelogs to a minimum.The expansion of "onAdded" has a few down sides and an important up side.
Cons
onAdded
call. Because e.g. adding an interface to newly create object is completely safe, but adding an interface to an existing object is considered dangerous.Pro
The best alternative approach I could come up with is to add metadata to the "added" change events. This is doable, but requires essentially recreating all the parsing that is already done in
onMutual
, and then requires any logic using these events to also recreate logic for adding things to the schema, because for example a field could be added to a type via aFieldAdded
change OR within aTypeAdded
change. And the structures would not match.This approach would make the meta data very large also, because it would have to capture interfaces, directives, fields, etc..
However, it would prevent us from polluting the existing change set with more noise.
An additional change is that multiple changes are no longer returned for the same "node". e.g. When adding a deprecated directive with a reason, the reason field is on the added change, and a "deprecatedReasonAdded" change is no longer emitted.
Type of change
How Has This Been Tested?
See unit tests.
Checklist:
CONTRIBUTING doc and the
style guidelines of this project