-
Notifications
You must be signed in to change notification settings - Fork 2k
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
Replace 'find{Breaking,Dangerous}Changes' with generic 'findSchemaChanges' #2181
Conversation
* Given two schemas, returns an Array containing descriptions of all the types | ||
* of potentially breaking change and dangerous change | ||
*/ | ||
export function findSchemaChanges( |
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.
@wtrocki Totally reasonable 👍
Moreover, I think it's confusing to have multiple functions that basically do the same so
I think findSchemaChanges
should be a function to rule them all.
Since we working on new major release 15.0.0
I think its good time to remove findDangerousChanges
and findBreakingChanges
. And merge BreakingChange | DangerousChange
into single SchemaChange
type.
Can you please do that?
Also, don't forget to update TS typings in tstypes
folder.
Another thing all public APIs should be exported through src/index.js
and src/utilities/index.js
.
https://github.com/graphql/graphql-js/blob/master/src/README.md
Working on this now |
f945e03
to
fb0fc76
Compare
fb0fc76
to
3ed6115
Compare
What is the policy on documenting breaking changes/providing migration paths? |
@wtrocki These functions are used mostly in the build scripts and CLI tools so migration path should be pretty easy. We have a script that generates changelog that will list all breaking changes. Would be great if you write a small note about this change and how to implement |
export type DangerousChange = { | ||
type: $Keys<typeof DangerousChangeType>, | ||
export type SchemaChange = { | ||
type: $Keys<typeof BreakingChangeType> | $Keys<typeof DangerousChangeType>, |
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.
It's better to create common SchemaChangeType
:
export const SchemaChangeType = Object.freeze({
...BreakingChangeType,
... DangerousChangeType,
});
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.
Perfect. I was thinking about it
@@ -281,12 +280,22 @@ describe('findBreakingChanges', () => { | |||
} | |||
`); | |||
|
|||
expect(findBreakingChanges(oldSchema, newSchema)).to.deep.equal([ | |||
expect(findSchemaChanges(oldSchema, newSchema)).to.deep.equal([ |
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.
@wtrocki Since you effectively merging tests for findBreakingChanges
and findDangerousChanges
please adjust tests accordingly.
For example, rename this one to should detect if a field is added to an input type
and remove the duplicating test:
graphql-js/src/utilities/__tests__/findBreakingChanges-test.js
Lines 1026 to 1047 in 06ef5db
it('should detect if an optional field was added to an input', () => { | |
const oldSchema = buildSchema(` | |
input InputType1 { | |
field1: String | |
} | |
`); | |
const newSchema = buildSchema(` | |
input InputType1 { | |
field1: String | |
field2: Int | |
} | |
`); | |
expect(findDangerousChanges(oldSchema, newSchema)).to.deep.equal([ | |
{ | |
type: DangerousChangeType.OPTIONAL_INPUT_FIELD_ADDED, | |
description: | |
'An optional field field2 on input type InputType1 was added.', | |
}, | |
]); | |
}); |
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.
@wtrocki Please do the same for other tests where you modify snapshot.
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.
Leaving comment on commit, as I disagree a bit with this premise, I think.
I want to add a note of warning: the purpose of "findBreakingChanges" is to find only those changes to the schema that could potentially break old versions of clients that are shipped and can never be updated. A function called This is OK, and even desireable to have. But I believe we should keep If the intention continues to be finding only those changes that may cause problems, we should have |
@mjmahone Thanks for review 👍 It's exactly the plan since we already expose constants for both breaking and dangerous changes: graphql-js/src/utilities/findBreakingChanges.js Lines 38 to 63 in 06ef5db
So it's just a matter of writing one-liner like this: import { BreakingChangeType, findSchemaChanges } from 'graphql';
function findBreakingChanges(oldSchema, newSchema) {
return findSchemaChanges(oldSchema, newSchema)
.filter(({type}) => type in BreakingChangeType);
} Also both constant is already part of public API and exposed through main Lines 403 to 405 in 06ef5db
And there is no plans to ever remove those constants. @mjmahone @Neitsch Does this migration path address your concerns? |
The awesome point from @mjmahone
My initial intention was to expose a single function that can be used to perform option nr 2 by calling a single function, so people can get both at the same time with a single method call and then decide on their own what they define as dangerous etc. As far I checked both enums do not comprehensively represent all possible changes that can happen so option nr1 will require separate method anyway. I have done some research how such implementation could look like and found out that there is already a community package that does both: With a generic change interface: With all of that in mind using
WDYT about:
function findBreakingChanges(oldSchema, newSchema) {
return findSchemaChanges(oldSchema, newSchema)
.filter(({type}) => type in BreakingChangeType);
}
return findSchemaChanges(oldSchema, newSchema, {types: BeakingChangeTypes}) |
@wtrocki So the idea is that we need to merge other types of schema changes in future, e.g. #1127. Classifying all changes into non-overlapping categories can be tricky so instead, we can simply do: export const SchemaChangeType = Object.freeze({
...BreakingChangeType,
... DangerousChangeType,
TYPE_ADDED: 'TYPE_ADDED',
// All other type of changes
});
For very big schemas it preferable to get all changes in single iteration and it will look awkward: const changes = findSchemaChanges(oldSchema, newSchema, {types: {
...BeakingChangeTypes,
...DangerousChangeTypes,
}})
for (const change of changes) {
if (change in BreakingChangeTypes) {
reportError(change);
} else if (change in DangerousChangeTypes) {
reportWarning(change);
}
} |
I will wait for consensus and then apply the required changes. |
I'm a big fan of this having an almost identical API as In short: I'm happy with adding a |
@@ -104,10 +104,8 @@ export { assertValidName, isValidNameError } from './assertValidName'; | |||
export { | |||
BreakingChangeType, | |||
DangerousChangeType, | |||
findBreakingChanges, |
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.
A lot of tooling currently relies on only getting the schema changes. I think all the code changes from above are great, but until we make findSchemaChanges
more flexible, we should keep these utility functions, to avoid forcing people to rewrite their code significantly in order to upgrade.
@mjmahone So just to clarify you oppose exposing Personally I think there is no big difference in filtering after But I'm totally ok with an alternative implementation if code size/performance will stay the same. |
Alternative to #2181 This adds a new `findSchemaChanges` export and deprecates the breaking and dangerous alternative to be removed in v18. While adding safe-schema-changes I noticed that we lack directive arg validation here, we should probably add these to breaking/dangerous changes in the future.
Implemented in #4235 |
Motivation
Currently to find potentially Breaking and Dangerous changes developers need to call 2 separate methods and execute logic twice. This change simply exposes the underlying method that will give access to both with single execution logic.