Skip to content

Commit 302b3a6

Browse files
committed
Detect directive argument changes
Replicates graphql/graphql-js@2ed951c
1 parent d5ec1c5 commit 302b3a6

2 files changed

Lines changed: 219 additions & 1 deletion

File tree

‎src/graphql/utilities/find_schema_changes.py‎

Lines changed: 60 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -223,7 +223,66 @@ def find_directive_changes(
223223
for arg_name in args_diff.removed
224224
)
225225

226-
for old_arg, new_arg in args_diff.persisted.values():
226+
for arg_name, (old_arg, new_arg) in args_diff.persisted.items():
227+
is_safe = is_change_safe_for_input_object_field_or_field_arg(
228+
old_arg.type, new_arg.type
229+
)
230+
if not is_safe:
231+
schema_changes.append(
232+
BreakingChange(
233+
BreakingChangeType.ARG_CHANGED_KIND,
234+
f"Argument @{old_directive.name}({arg_name}:)"
235+
f" has changed type from"
236+
f" {old_arg.type} to {new_arg.type}.",
237+
)
238+
)
239+
elif old_arg.default_value is not Undefined:
240+
if new_arg.default_value is Undefined:
241+
schema_changes.append(
242+
DangerousChange(
243+
DangerousChangeType.ARG_DEFAULT_VALUE_CHANGE,
244+
f"@{old_directive.name}({arg_name}:)"
245+
f" defaultValue was removed.",
246+
)
247+
)
248+
else:
249+
# Since we are looking only for client's observable changes
250+
# we should compare default values in the same representation
251+
# as they are represented inside introspection.
252+
old_value_str = stringify_value(old_arg.default_value, old_arg.type)
253+
new_value_str = stringify_value(new_arg.default_value, new_arg.type)
254+
255+
if old_value_str != new_value_str:
256+
schema_changes.append(
257+
DangerousChange(
258+
DangerousChangeType.ARG_DEFAULT_VALUE_CHANGE,
259+
f"@{old_directive.name}({arg_name}:)"
260+
f" has changed defaultValue"
261+
f" from {old_value_str} to {new_value_str}.",
262+
)
263+
)
264+
elif (
265+
new_arg.default_value is not Undefined
266+
and old_arg.default_value is Undefined
267+
):
268+
new_value_str = stringify_value(new_arg.default_value, new_arg.type)
269+
schema_changes.append(
270+
SafeChange(
271+
SafeChangeType.ARG_DEFAULT_VALUE_ADDED,
272+
f"@{old_directive.name}({arg_name}:)"
273+
f" added a defaultValue {new_value_str}.",
274+
)
275+
)
276+
elif str(old_arg.type) != str(new_arg.type):
277+
schema_changes.append(
278+
SafeChange(
279+
SafeChangeType.ARG_CHANGED_KIND_SAFE,
280+
f"Argument @{old_directive.name}({arg_name}:)"
281+
f" has changed type from"
282+
f" {old_arg.type} to {new_arg.type}.",
283+
)
284+
)
285+
227286
if old_arg.description != new_arg.description:
228287
schema_changes.append(
229288
SafeChange(

‎tests/utilities/test_find_schema_changes.py‎

Lines changed: 159 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
from graphql.utilities import (
2+
BreakingChangeType,
3+
DangerousChangeType,
24
SafeChangeType,
35
build_schema,
46
find_schema_changes,
@@ -185,6 +187,163 @@ def should_detect_if_a_directive_was_added():
185187
(SafeChangeType.DIRECTIVE_ADDED, "Directive @Foo was added."),
186188
]
187189

190+
def should_detect_if_a_changes_argument_safely():
191+
old_schema = build_schema(
192+
"""
193+
directive @Foo(foo: String!) on FIELD_DEFINITION
194+
195+
type Query {
196+
foo: String
197+
}
198+
"""
199+
)
200+
201+
new_schema = build_schema(
202+
"""
203+
directive @Foo(foo: String) on FIELD_DEFINITION
204+
205+
type Query {
206+
foo: String
207+
}
208+
"""
209+
)
210+
assert find_schema_changes(old_schema, new_schema) == [
211+
(
212+
SafeChangeType.ARG_CHANGED_KIND_SAFE,
213+
"Argument @Foo(foo:) has changed type from String! to String.",
214+
),
215+
]
216+
217+
def should_detect_if_a_default_value_is_added_to_an_argument():
218+
old_schema = build_schema(
219+
"""
220+
directive @Foo(foo: String) on FIELD_DEFINITION
221+
222+
type Query {
223+
foo: String
224+
}
225+
"""
226+
)
227+
228+
new_schema = build_schema(
229+
"""
230+
directive @Foo(foo: String = "Foo") on FIELD_DEFINITION
231+
232+
type Query {
233+
foo: String
234+
}
235+
"""
236+
)
237+
assert find_schema_changes(old_schema, new_schema) == [
238+
(
239+
SafeChangeType.ARG_DEFAULT_VALUE_ADDED,
240+
'@Foo(foo:) added a defaultValue "Foo".',
241+
),
242+
]
243+
244+
def should_detect_if_a_default_value_is_removed_from_an_argument():
245+
new_schema = build_schema(
246+
"""
247+
directive @Foo(foo: String) on FIELD_DEFINITION
248+
249+
type Query {
250+
foo: String
251+
}
252+
"""
253+
)
254+
255+
old_schema = build_schema(
256+
"""
257+
directive @Foo(foo: String = "Foo") on FIELD_DEFINITION
258+
259+
type Query {
260+
foo: String
261+
}
262+
"""
263+
)
264+
assert find_schema_changes(old_schema, new_schema) == [
265+
(
266+
DangerousChangeType.ARG_DEFAULT_VALUE_CHANGE,
267+
"@Foo(foo:) defaultValue was removed.",
268+
),
269+
]
270+
271+
def should_detect_if_a_default_value_is_changed_in_an_argument():
272+
old_schema = build_schema(
273+
"""
274+
directive @Foo(foo: String = "Bar") on FIELD_DEFINITION
275+
276+
type Query {
277+
foo: String
278+
}
279+
"""
280+
)
281+
282+
new_schema = build_schema(
283+
"""
284+
directive @Foo(foo: String = "Foo") on FIELD_DEFINITION
285+
286+
type Query {
287+
foo: String
288+
}
289+
"""
290+
)
291+
assert find_schema_changes(old_schema, new_schema) == [
292+
(
293+
DangerousChangeType.ARG_DEFAULT_VALUE_CHANGE,
294+
'@Foo(foo:) has changed defaultValue from "Bar" to "Foo".',
295+
),
296+
]
297+
298+
def should_detect_if_a_directive_argument_does_a_breaking_change():
299+
old_schema = build_schema(
300+
"""
301+
directive @Foo(foo: String) on FIELD_DEFINITION
302+
303+
type Query {
304+
foo: String
305+
}
306+
"""
307+
)
308+
309+
new_schema = build_schema(
310+
"""
311+
directive @Foo(foo: String!) on FIELD_DEFINITION
312+
313+
type Query {
314+
foo: String
315+
}
316+
"""
317+
)
318+
assert find_schema_changes(old_schema, new_schema) == [
319+
(
320+
BreakingChangeType.ARG_CHANGED_KIND,
321+
"Argument @Foo(foo:) has changed type from String to String!.",
322+
),
323+
]
324+
325+
def should_not_detect_if_a_directive_argument_default_value_does_not_change():
326+
old_schema = build_schema(
327+
"""
328+
directive @Foo(foo: String = "FOO") on FIELD_DEFINITION
329+
330+
type Query {
331+
foo: String
332+
}
333+
"""
334+
)
335+
336+
new_schema = build_schema(
337+
"""
338+
directive @Foo(foo: String = "FOO") on FIELD_DEFINITION
339+
340+
type Query {
341+
foo: String
342+
}
343+
"""
344+
)
345+
assert find_schema_changes(old_schema, new_schema) == []
346+
188347
def should_detect_if_a_directive_changes_description():
189348
old_schema = build_schema(
190349
"""

0 commit comments

Comments
 (0)