graphql-schema_comparator 0.5.0 → 1.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: 2bd04f7cdf16f7bc67fb74e219478457b180e022
4
- data.tar.gz: eb021f9745da0a4fed5fb2cedfb5a848ca1685b0
2
+ SHA256:
3
+ metadata.gz: 3ae1770b6fad8e77502e03cb613fbc5bf5546bc96d535e2af0f622c2794102c0
4
+ data.tar.gz: 5edcad6f5ce2fea8a2e83c79279e4bee868d5e3507af254176931341d7d46506
5
5
  SHA512:
6
- metadata.gz: 7a6d826fd10f0bb42eebcc9546c77d40b32242d5c6888181e5dab77b7c1f9d4ce8d4be192ef750209d98d7230ee81aa0121645f6c1482b6fc1d80e9d5287f02e
7
- data.tar.gz: f43508482f55b5b88b1627b5b9d12ce6800512a2386cb66785348f01951d25384d1142d62370dc7d339530d0593998200005ced1a4ae01402a24940676bbc62d
6
+ metadata.gz: e10aae6486a79da4eb4e9fb6e3787ac166d5d54848bf2eea37b8885839c83efe8de97af8dc84fa732d7c1582567050b0469fba5d546a85b9183b6ccdcb4582a2
7
+ data.tar.gz: 1a879654fecfb43824872cf9c4907d4edaa221645d6d91a062b7f933cb0cf0ce43587e6d840451f7027b9da8aed99c45fd8d0af84bc3403901c6a93eb2764cb4
@@ -0,0 +1,20 @@
1
+ name: Tests
2
+
3
+ on:
4
+ push
5
+
6
+ jobs:
7
+ test:
8
+ runs-on: ubuntu-latest
9
+ strategy:
10
+ fail-fast: false
11
+ matrix:
12
+ ruby: [2.4, 2.7, '3.0']
13
+ steps:
14
+ - uses: actions/checkout@v2
15
+ - uses: ruby/setup-ruby@v1
16
+ with:
17
+ bundler-cache: true
18
+ ruby-version: ${{ matrix.ruby }}
19
+ - run: bundle install
20
+ - run: bundle exec rake
data/CHANGELOG.md CHANGED
@@ -1,8 +1,39 @@
1
1
  # Changelog
2
2
 
3
+ ## 1.0.1 (May 26 2021)
4
+
5
+ ### Bug Fix
6
+
7
+ - Fix comparing directives (#36)
8
+
9
+ ## 1.0.0 (January 23 2020)
10
+
11
+ ### Breaking Changes
12
+
13
+ - Add support for graphql-ruby 1.10.0+ (#28)
14
+ - Starting from 1.0.0 a minimum of graphql-ruby 1.10 is required
15
+
16
+ ## 0.6.1 (May 21rst 2019)
17
+
18
+ - Added a bunch of reasons to breaking changes (#17)
19
+ - Relaxed Thor Dependency
20
+ - Add `verify` task for CI usage which returns exit codes depending on breaking changes (#24)
21
+
22
+ ## 0.6.0 (Feb 28th 2018)
23
+
24
+ ### New Features
25
+
26
+ - Add `#path` which returns a dot-delimited path to the affected schema member. (#15)
27
+
28
+ ## 0.5.1 (Feb 15th 2018)
29
+
30
+ ### Bug Fix
31
+
32
+ - Return a better message when adding a default value, if this one was nil before.
33
+
3
34
  ## 0.5.0 (Dec 2 2017)
4
35
 
5
- ## New Features
36
+ ### New Features
6
37
 
7
38
  - `AbstractChange#criticality` now returns a criticality object which
8
39
  has a level (non_breaking, dangerous, breaking) and a reason
@@ -13,14 +44,14 @@
13
44
 
14
45
  - New CLI `schema_comparator` which includes `dangerous_changes`
15
46
 
16
- ## Breaking Changes
47
+ ### Breaking Changes
17
48
 
18
49
  - Some changes have been recategorized as dangerous
19
50
  - Some type changes now return breaking or non-breaking depending on the type kind
20
51
 
21
52
  ## 0.4.0 (Nov 27 2017)
22
53
 
23
- ## Breaking Changes
54
+ ### Breaking Changes
24
55
 
25
56
  - Argument and InputValue type changes are considered non
26
57
  breaking if type goes from Null => Non-Null
@@ -36,32 +67,32 @@ Added changes:
36
67
 
37
68
  ### Bug fixes
38
69
 
39
- Fix issue in Enum differ (https://github.com/xuorig/graphql-schema_comparator/issues/9)
70
+ - Fix issue in Enum differ (https://github.com/xuorig/graphql-schema_comparator/issues/9)
40
71
 
41
72
  ## 0.3.1 (Nov 13 2017)
42
73
 
43
74
  ### Bug Fixes
44
75
 
45
- - Fix no method breaking issue https://github.com/xuorig/graphql-schema_comparator/issues/8
76
+ - Fix no method breaking issue https://github.com/xuorig/graphql-schema_comparator/issues/8
46
77
 
47
78
  ## 0.3.0 (Oct 14 2017)
48
79
 
49
80
  ### New features
50
81
 
51
- - Top level Directive definitions are now diffed, but not directives used on definitions (Coming soon)
52
- - Base class for changes added.
82
+ - Top level Directive definitions are now diffed, but not directives used on definitions (Coming soon)
83
+ - Base class for changes added.
53
84
 
54
85
  ### breaking changes
55
86
 
56
- - `breaking` method on change objects has been renamed `breaking?` for style
87
+ - `breaking` method on change objects has been renamed `breaking?` for style
57
88
 
58
89
  ## 0.2.0 (Aug 18 2017)
59
90
 
60
91
  ### New features
61
92
 
62
- - Add `#non_breaking_changes` to get a list of non breaking changes from a comparison result. (#4)
63
- - CLI now Prints results sorted and grouped by breaking / non-breaking (#3)
93
+ - Add `#non_breaking_changes` to get a list of non breaking changes from a comparison result. (#4)
94
+ - CLI now Prints results sorted and grouped by breaking / non-breaking (#3)
64
95
 
65
96
  ### Bug fixes
66
97
 
67
- - Fix message for `EnumValueRemoved` (#5)
98
+ - Fix message for `EnumValueRemoved` (#5)
data/LICENSE.txt CHANGED
@@ -1,6 +1,6 @@
1
1
  The MIT License (MIT)
2
2
 
3
- Copyright (c) 2017 TODO: Write your name
3
+ Copyright (c) 2017 Marc-Andre Giroux
4
4
 
5
5
  Permission is hereby granted, free of charge, to any person obtaining a copy
6
6
  of this software and associated documentation files (the "Software"), to deal
data/README.md CHANGED
@@ -87,7 +87,7 @@ Possible changes are all found in [changes.rb](lib/graphql/schema_comparator/cha
87
87
 
88
88
  ### Change Criticality
89
89
 
90
- Each change object has a ``#criticality` method which returns a `Changes::Criticality` object.
90
+ Each change object has a `#criticality` method which returns a `Changes::Criticality` object.
91
91
  This objects defines how dangerous a change is to a schema.
92
92
 
93
93
  The different levels of criticality (non_breaking, dangerous, breaking) are explained here:
@@ -5,9 +5,23 @@ require "thor"
5
5
  require "graphql/schema_comparator"
6
6
 
7
7
  class GraphQLSchema < Thor
8
+ desc "verify OLD_SCHEMA NEW_SCHEMA", "Behaves exactly like `compare` but returns an exit code for CI purposes"
9
+
10
+ def verify(old_schema, new_schema)
11
+ result = run_compare(old_schema, new_schema)
12
+ exit_code = result.breaking? ? 1 : 0
13
+ exit(exit_code)
14
+ end
15
+
8
16
  desc "compare OLD_SCHEMA NEW_SCHEMA", "Compares OLD_SCHEMA with NEW_SCHEMA and returns a list of changes"
9
17
 
10
18
  def compare(old_schema, new_schema)
19
+ run_compare(old_schema, new_schema)
20
+ end
21
+
22
+ private
23
+
24
+ def run_compare(old_schema, new_schema)
11
25
  parsed_old = parse_schema(old_schema)
12
26
  parsed_new = parse_schema(new_schema)
13
27
 
@@ -22,10 +36,9 @@ class GraphQLSchema < Thor
22
36
  else
23
37
  print_changes(result)
24
38
  end
39
+ result
25
40
  end
26
41
 
27
- private
28
-
29
42
  def print_changes(result)
30
43
  say "Detected the following changes between schemas:"
31
44
  say "\n"
@@ -21,10 +21,10 @@ Gem::Specification.new do |spec|
21
21
  spec.executables = ["graphql-schema", "schema_comparator"]
22
22
  spec.require_paths = ["lib"]
23
23
 
24
- spec.add_dependency "graphql", "~> 1.6"
25
- spec.add_dependency "thor", "~> 0.19"
24
+ spec.add_dependency "graphql", "~> 1.10"
25
+ spec.add_dependency "thor", ">= 0.19", "< 2.0"
26
+ spec.add_dependency "bundler", ">= 1.14"
26
27
 
27
- spec.add_development_dependency "bundler", "~> 1.14"
28
28
  spec.add_development_dependency "rake", "~> 10.0"
29
29
  spec.add_development_dependency "minitest", "~> 5.10"
30
30
  spec.add_development_dependency "pry-byebug", "~> 3.4"
@@ -35,7 +35,7 @@ module GraphQL
35
35
  private
36
36
 
37
37
  def self.parse_schema(schema)
38
- if schema.is_a?(GraphQL::Schema)
38
+ if schema.respond_to?(:ancestors) && schema.ancestors.include?(GraphQL::Schema)
39
39
  schema
40
40
  elsif schema.is_a?(String)
41
41
  GraphQL::Schema.from_definition(schema)
@@ -12,7 +12,7 @@ module GraphQL
12
12
  raise NotImplementedError
13
13
  end
14
14
 
15
- # @return [Boolean] If the change is breaking or not
15
+ # @return [Boolean] If the change is breaking or not
16
16
  def breaking?
17
17
  criticality.breaking?
18
18
  end
@@ -31,6 +31,11 @@ module GraphQL
31
31
  def criticality
32
32
  raise NotImplementedError
33
33
  end
34
+
35
+ # @return [String] Dot-delimited path to the affected schema member.
36
+ def path
37
+ raise NotImplementedError
38
+ end
34
39
  end
35
40
 
36
41
  # Mostly breaking changes
@@ -40,11 +45,17 @@ module GraphQL
40
45
 
41
46
  def initialize(removed_type)
42
47
  @removed_type = removed_type
43
- @criticality = Changes::Criticality.breaking
48
+ @criticality = Changes::Criticality.breaking(
49
+ reason: "Removing a type is a breaking change. It is preferable to deprecate and remove all references to this type first."
50
+ )
44
51
  end
45
52
 
46
53
  def message
47
- "`#{removed_type.name}` was removed"
54
+ "Type `#{removed_type.graphql_definition}` was removed"
55
+ end
56
+
57
+ def path
58
+ removed_type.graphql_definition.to_s
48
59
  end
49
60
  end
50
61
 
@@ -57,7 +68,11 @@ module GraphQL
57
68
  end
58
69
 
59
70
  def message
60
- "`#{directive.name}` was removed"
71
+ "Directive `#{directive.graphql_name}` was removed"
72
+ end
73
+
74
+ def path
75
+ "@#{directive.graphql_name}"
61
76
  end
62
77
  end
63
78
 
@@ -67,11 +82,17 @@ module GraphQL
67
82
  def initialize(old_type, new_type)
68
83
  @old_type = old_type
69
84
  @new_type = new_type
70
- @criticality = Changes::Criticality.breaking
85
+ @criticality = Changes::Criticality.breaking(
86
+ reason: "Changing the kind of a type is a breaking change because it can cause existing queries to error. For example, turning an object type to a scalar type would break queries that define a selection set for this type."
87
+ )
71
88
  end
72
89
 
73
90
  def message
74
- "`#{old_type.name}` kind changed from `#{old_type.kind}` to `#{new_type.kind}`"
91
+ "`#{old_type.graphql_definition}` kind changed from `#{old_type.kind}` to `#{new_type.kind}`"
92
+ end
93
+
94
+ def path
95
+ old_type.graphql_definition.to_s
75
96
  end
76
97
  end
77
98
 
@@ -81,11 +102,17 @@ module GraphQL
81
102
  def initialize(enum_type, enum_value)
82
103
  @enum_value = enum_value
83
104
  @enum_type = enum_type
84
- @criticality = Changes::Criticality.breaking
105
+ @criticality = Changes::Criticality.breaking(
106
+ reason: "Removing an enum value will cause existing queries that use this enum value to error."
107
+ )
85
108
  end
86
109
 
87
110
  def message
88
- "Enum value `#{enum_value.name}` was removed from enum `#{enum_type.name}`"
111
+ "Enum value `#{enum_value.graphql_name}` was removed from enum `#{enum_type.graphql_definition}`"
112
+ end
113
+
114
+ def path
115
+ [enum_type.graphql_definition, enum_value.graphql_name].join('.')
89
116
  end
90
117
  end
91
118
 
@@ -95,11 +122,17 @@ module GraphQL
95
122
  def initialize(union_type, union_member)
96
123
  @union_member = union_member
97
124
  @union_type = union_type
98
- @criticality = Changes::Criticality.breaking
125
+ @criticality = Changes::Criticality.breaking(
126
+ reason: "Removing a union member from a union can cause existing queries that use this union member in a fragment spread to error."
127
+ )
99
128
  end
100
129
 
101
130
  def message
102
- "Union member `#{union_member.name}` was removed from Union type `#{union_type.name}`"
131
+ "Union member `#{union_member.graphql_name}` was removed from Union type `#{union_type.graphql_definition}`"
132
+ end
133
+
134
+ def path
135
+ union_type.graphql_definition.to_s
103
136
  end
104
137
  end
105
138
 
@@ -109,11 +142,17 @@ module GraphQL
109
142
  def initialize(input_object_type, field)
110
143
  @input_object_type = input_object_type
111
144
  @field = field
112
- @criticality = Changes::Criticality.breaking
145
+ @criticality = Changes::Criticality.breaking(
146
+ reason: "Removing an input field will cause existing queries that use this input field to error."
147
+ )
113
148
  end
114
149
 
115
150
  def message
116
- "Input field `#{field.name}` was removed from input object type `#{input_object_type.name}`"
151
+ "Input field `#{field.graphql_name}` was removed from input object type `#{input_object_type.graphql_definition}`"
152
+ end
153
+
154
+ def path
155
+ [input_object_type.graphql_definition, field.graphql_name].join('.')
117
156
  end
118
157
  end
119
158
 
@@ -124,11 +163,17 @@ module GraphQL
124
163
  @object_type = object_type
125
164
  @field = field
126
165
  @argument = argument
127
- @criticality = Changes::Criticality.breaking
166
+ @criticality = Changes::Criticality.breaking(
167
+ reason: "Removing a field argument is a breaking change because it will cause existing queries that use this argument to error."
168
+ )
128
169
  end
129
170
 
130
171
  def message
131
- "Argument `#{argument.name}: #{argument.type}` was removed from field `#{object_type.name}.#{field.name}`"
172
+ "Argument `#{argument.graphql_name}: #{argument.type.graphql_definition}` was removed from field `#{object_type.graphql_definition}.#{field.graphql_name}`"
173
+ end
174
+
175
+ def path
176
+ [object_type.graphql_definition, field.graphql_name, argument.graphql_name].join('.')
132
177
  end
133
178
  end
134
179
 
@@ -142,7 +187,11 @@ module GraphQL
142
187
  end
143
188
 
144
189
  def message
145
- "Argument `#{argument.name}` was removed from directive `#{directive.name}`"
190
+ "Argument `#{argument.graphql_name}` was removed from directive `#{directive.graphql_name}`"
191
+ end
192
+
193
+ def path
194
+ ["@#{directive.graphql_name}", argument.graphql_name].join('.')
146
195
  end
147
196
  end
148
197
 
@@ -156,7 +205,11 @@ module GraphQL
156
205
  end
157
206
 
158
207
  def message
159
- "Schema query root has changed from `#{old_schema.query.name}` to `#{new_schema.query.name}`"
208
+ "Schema query root has changed from `#{old_schema.query.graphql_name}` to `#{new_schema.query.graphql_name}`"
209
+ end
210
+
211
+ def path
212
+ # TODO
160
213
  end
161
214
  end
162
215
 
@@ -166,11 +219,25 @@ module GraphQL
166
219
  def initialize(object_type, field)
167
220
  @object_type = object_type
168
221
  @field = field
169
- @criticality = Changes::Criticality.breaking
222
+
223
+ if field.deprecation_reason
224
+ @criticality = Changes::Criticality.breaking(
225
+ reason: "Removing a deprecated field is a breaking change. Before removing it, you may want" \
226
+ "to look at the field's usage to see the impact of removing the field."
227
+ )
228
+ else
229
+ @criticality = Changes::Criticality.breaking(
230
+ reason: "Removing a field is a breaking change. It is preferable to deprecate the field before removing it."
231
+ )
232
+ end
170
233
  end
171
234
 
172
235
  def message
173
- "Field `#{field.name}` was removed from object type `#{object_type.name}`"
236
+ "Field `#{field.graphql_name}` was removed from object type `#{object_type.graphql_definition}`"
237
+ end
238
+
239
+ def path
240
+ [object_type.graphql_definition, field.graphql_name].join('.')
174
241
  end
175
242
  end
176
243
 
@@ -184,7 +251,11 @@ module GraphQL
184
251
  end
185
252
 
186
253
  def message
187
- "Location `#{location}` was removed from directive `#{directive.name}`"
254
+ "Location `#{location}` was removed from directive `#{directive.graphql_name}`"
255
+ end
256
+
257
+ def path
258
+ "@#{directive.graphql_name}"
188
259
  end
189
260
  end
190
261
 
@@ -194,11 +265,17 @@ module GraphQL
194
265
  def initialize(interface, object_type)
195
266
  @interface = interface
196
267
  @object_type = object_type
197
- @criticality = Changes::Criticality.breaking
268
+ @criticality = Changes::Criticality.breaking(
269
+ reason: "Removing an interface from an object type can cause existing queries that use this in a fragment spread to error."
270
+ )
198
271
  end
199
272
 
200
273
  def message
201
- "`#{object_type.name}` object type no longer implements `#{interface.name}` interface"
274
+ "`#{object_type.graphql_definition}` object type no longer implements `#{interface.graphql_name}` interface"
275
+ end
276
+
277
+ def path
278
+ object_type.graphql_definition.to_s
202
279
  end
203
280
  end
204
281
 
@@ -214,16 +291,20 @@ module GraphQL
214
291
  end
215
292
 
216
293
  def message
217
- "Field `#{type}.#{old_field.name}` changed type from `#{old_field.type}` to `#{new_field.type}`"
294
+ "Field `#{type.graphql_definition}.#{old_field.graphql_name}` changed type from `#{old_field.type.graphql_definition}` to `#{new_field.type.graphql_definition}`"
218
295
  end
219
296
 
220
297
  def criticality
221
298
  if safe_change_for_field?(old_field.type, new_field.type)
222
299
  Changes::Criticality.non_breaking
223
300
  else
224
- Changes::Criticality.breaking
301
+ Changes::Criticality.breaking # TODO - Add reason
225
302
  end
226
303
  end
304
+
305
+ def path
306
+ [type.graphql_definition, old_field.graphql_name].join('.')
307
+ end
227
308
  end
228
309
 
229
310
  class InputFieldTypeChanged < AbstractChange
@@ -237,7 +318,9 @@ module GraphQL
237
318
  reason: "Changing an input field from non-null to null is considered non-breaking"
238
319
  )
239
320
  else
240
- @criticality = Changes::Criticality.breaking
321
+ @criticality = Changes::Criticality.breaking(
322
+ reason: "Changing the type of an input field can cause existing queries that use this field to error."
323
+ )
241
324
  end
242
325
 
243
326
  @input_type = input_type
@@ -246,7 +329,11 @@ module GraphQL
246
329
  end
247
330
 
248
331
  def message
249
- "Input field `#{input_type}.#{old_input_field.name}` changed type from `#{old_input_field.type}` to `#{new_input_field.type}`"
332
+ "Input field `#{input_type.graphql_definition}.#{old_input_field.graphql_name}` changed type from `#{old_input_field.type.graphql_definition}` to `#{new_input_field.type.graphql_definition}`"
333
+ end
334
+
335
+ def path
336
+ [input_type.graphql_definition, old_input_field.graphql_name].join('.')
250
337
  end
251
338
  end
252
339
 
@@ -261,7 +348,9 @@ module GraphQL
261
348
  reason: "Changing an input field from non-null to null is considered non-breaking"
262
349
  )
263
350
  else
264
- @criticality = Changes::Criticality.breaking
351
+ @criticality = Changes::Criticality.breaking(
352
+ reason: "Changing the type of a field's argument can cause existing queries that use this argument to error."
353
+ )
265
354
  end
266
355
 
267
356
  @type = type
@@ -271,8 +360,12 @@ module GraphQL
271
360
  end
272
361
 
273
362
  def message
274
- "Type for argument `#{new_argument.name}` on field `#{type.name}.#{field.name}` changed"\
275
- " from `#{old_argument.type}` to `#{new_argument.type}`"
363
+ "Type for argument `#{new_argument.graphql_name}` on field `#{type.graphql_definition}.#{field.graphql_definition.name}` changed"\
364
+ " from `#{old_argument.type.graphql_definition}` to `#{new_argument.type.graphql_definition}`"
365
+ end
366
+
367
+ def path
368
+ [type.graphql_definition, field.graphql_definition.name, old_argument.graphql_name].join('.')
276
369
  end
277
370
  end
278
371
 
@@ -296,8 +389,12 @@ module GraphQL
296
389
  end
297
390
 
298
391
  def message
299
- "Type for argument `#{new_argument.name}` on directive `#{directive.name}` changed"\
300
- " from `#{old_argument.type}` to `#{new_argument.type}`"
392
+ "Type for argument `#{new_argument.graphql_name}` on directive `#{directive.graphql_name}` changed"\
393
+ " from `#{old_argument.type.graphql_definition}` to `#{new_argument.type.graphql_definition}`"
394
+ end
395
+
396
+ def path
397
+ ["@#{directive.graphql_name}", old_argument.graphql_name].join('.')
301
398
  end
302
399
  end
303
400
 
@@ -313,6 +410,10 @@ module GraphQL
313
410
  def message
314
411
  "Schema mutation root has changed from `#{old_schema.mutation}` to `#{new_schema.mutation}`"
315
412
  end
413
+
414
+ def path
415
+ # TODO
416
+ end
316
417
  end
317
418
 
318
419
  class SchemaSubscriptionTypeChanged < AbstractChange
@@ -327,6 +428,10 @@ module GraphQL
327
428
  def message
328
429
  "Schema subscription type has changed from `#{old_schema.subscription}` to `#{new_schema.subscription}`"
329
430
  end
431
+
432
+ def path
433
+ # TODO
434
+ end
330
435
  end
331
436
 
332
437
  # Dangerous Changes
@@ -346,8 +451,16 @@ module GraphQL
346
451
  end
347
452
 
348
453
  def message
349
- "Default value for argument `#{new_argument.name}` on field `#{type.name}.#{field.name}` changed"\
350
- " from `#{old_argument.default_value}` to `#{new_argument.default_value}`"
454
+ if old_argument.default_value.nil? || old_argument.default_value == :__no_default__
455
+ "Default value `#{new_argument.default_value}` was added to argument `#{new_argument.graphql_name}` on field `#{type.graphql_definition}.#{field.graphql_name}`"
456
+ else
457
+ "Default value for argument `#{new_argument.graphql_name}` on field `#{type.graphql_definition}.#{field.name}` changed"\
458
+ " from `#{old_argument.default_value}` to `#{new_argument.default_value}`"
459
+ end
460
+ end
461
+
462
+ def path
463
+ [type.graphql_definition, field.graphql_name, old_argument.graphql_name].join('.')
351
464
  end
352
465
  end
353
466
 
@@ -365,9 +478,13 @@ module GraphQL
365
478
  end
366
479
 
367
480
  def message
368
- "Input field `#{input_type.name}.#{old_field.name}` default changed"\
481
+ "Input field `#{input_type.graphql_definition}.#{old_field.graphql_name}` default changed"\
369
482
  " from `#{old_field.default_value}` to `#{new_field.default_value}`"
370
483
  end
484
+
485
+ def path
486
+ [input_type.graphql_definition, old_field.graphql_name].join(".")
487
+ end
371
488
  end
372
489
 
373
490
  class DirectiveArgumentDefaultChanged < AbstractChange
@@ -384,9 +501,13 @@ module GraphQL
384
501
  end
385
502
 
386
503
  def message
387
- "Default value for argument `#{new_argument.name}` on directive `#{directive.name}` changed"\
504
+ "Default value for argument `#{new_argument.graphql_name}` on directive `#{directive.graphql_name}` changed"\
388
505
  " from `#{old_argument.default_value}` to `#{new_argument.default_value}`"
389
506
  end
507
+
508
+ def path
509
+ ["@#{directive.graphql_name}", new_argument.graphql_name].join(".")
510
+ end
390
511
  end
391
512
 
392
513
  class EnumValueAdded < AbstractChange
@@ -402,7 +523,11 @@ module GraphQL
402
523
  end
403
524
 
404
525
  def message
405
- "Enum value `#{enum_value.name}` was added to enum `#{enum_type.name}`"
526
+ "Enum value `#{enum_value.graphql_name}` was added to enum `#{enum_type.graphql_definition}`"
527
+ end
528
+
529
+ def path
530
+ [enum_type.graphql_definition, enum_value.graphql_name].join(".")
406
531
  end
407
532
  end
408
533
 
@@ -419,7 +544,11 @@ module GraphQL
419
544
  end
420
545
 
421
546
  def message
422
- "Union member `#{union_member.name}` was added to Union type `#{union_type.name}`"
547
+ "Union member `#{union_member.graphql_name}` was added to Union type `#{union_type.graphql_definition}`"
548
+ end
549
+
550
+ def path
551
+ union_type.graphql_definition.to_s
423
552
  end
424
553
  end
425
554
 
@@ -436,7 +565,11 @@ module GraphQL
436
565
  end
437
566
 
438
567
  def message
439
- "`#{object_type.name}` object implements `#{interface.name}` interface"
568
+ "`#{object_type.graphql_definition}` object implements `#{interface.graphql_name}` interface"
569
+ end
570
+
571
+ def path
572
+ object_type.graphql_definition.to_s
440
573
  end
441
574
  end
442
575
 
@@ -447,7 +580,7 @@ module GraphQL
447
580
 
448
581
  def initialize(input_object_type, field)
449
582
  @criticality = if field.type.non_null?
450
- Changes::Criticality.breaking
583
+ Changes::Criticality.breaking(reason: "Adding a non-null field to an existing input type will cause existing queries that use this input type to error because they will not provide a value for this new field.")
451
584
  else
452
585
  Changes::Criticality.non_breaking
453
586
  end
@@ -457,7 +590,11 @@ module GraphQL
457
590
  end
458
591
 
459
592
  def message
460
- "Input field `#{field.name}` was added to input object type `#{input_object_type.name}`"
593
+ "Input field `#{field.graphql_name}` was added to input object type `#{input_object_type.graphql_definition}`"
594
+ end
595
+
596
+ def path
597
+ [input_object_type.graphql_definition, field.graphql_name].join(".")
461
598
  end
462
599
  end
463
600
 
@@ -466,7 +603,7 @@ module GraphQL
466
603
 
467
604
  def initialize(type, field, argument)
468
605
  @criticality = if argument.type.non_null?
469
- Changes::Criticality.breaking
606
+ Changes::Criticality.breaking(reason: "Adding a required argument to an existing field is a breaking change because it will cause existing uses of this field to error.")
470
607
  else
471
608
  Changes::Criticality.non_breaking
472
609
  end
@@ -477,7 +614,11 @@ module GraphQL
477
614
  end
478
615
 
479
616
  def message
480
- "Argument `#{argument.name}: #{argument.type}` added to field `#{type.name}.#{field.name}`"
617
+ "Argument `#{argument.graphql_name}: #{argument.type.graphql_definition}` added to field `#{type.graphql_definition}.#{field.graphql_name}`"
618
+ end
619
+
620
+ def path
621
+ [type.graphql_definition, field.graphql_name, argument.graphql_name].join(".")
481
622
  end
482
623
  end
483
624
 
@@ -490,7 +631,11 @@ module GraphQL
490
631
  end
491
632
 
492
633
  def message
493
- "Type `#{type.name}` was added"
634
+ "Type `#{type.graphql_definition}` was added"
635
+ end
636
+
637
+ def path
638
+ type.graphql_definition.to_s
494
639
  end
495
640
  end
496
641
 
@@ -503,7 +648,11 @@ module GraphQL
503
648
  end
504
649
 
505
650
  def message
506
- "Directive `#{directive.name}` was added"
651
+ "Directive `#{directive.graphql_name}` was added"
652
+ end
653
+
654
+ def path
655
+ "@#{directive.graphql_name}"
507
656
  end
508
657
  end
509
658
 
@@ -517,7 +666,11 @@ module GraphQL
517
666
  end
518
667
 
519
668
  def message
520
- "Description `#{old_type.description}` on type `#{old_type.name}` has changed to `#{new_type.description}`"
669
+ "Description `#{old_type.description}` on type `#{old_type.graphql_definition}` has changed to `#{new_type.description}`"
670
+ end
671
+
672
+ def path
673
+ old_type.graphql_definition.to_s
521
674
  end
522
675
  end
523
676
 
@@ -532,9 +685,13 @@ module GraphQL
532
685
  end
533
686
 
534
687
  def message
535
- "Description for enum value `#{enum.name}.#{new_enum_value.name}` changed from " \
688
+ "Description for enum value `#{enum.graphql_name}.#{new_enum_value.graphql_name}` changed from " \
536
689
  "`#{old_enum_value.description}` to `#{new_enum_value.description}`"
537
690
  end
691
+
692
+ def path
693
+ [enum.graphql_name, old_enum_value.graphql_name].join(".")
694
+ end
538
695
  end
539
696
 
540
697
  class EnumValueDeprecated < AbstractChange
@@ -549,13 +706,17 @@ module GraphQL
549
706
 
550
707
  def message
551
708
  if old_enum_value.deprecation_reason
552
- "Enum value `#{enum.name}.#{new_enum_value.name}` deprecation reason changed " \
709
+ "Enum value `#{enum.graphql_name}.#{new_enum_value.graphql_name}` deprecation reason changed " \
553
710
  "from `#{old_enum_value.deprecation_reason}` to `#{new_enum_value.deprecation_reason}`"
554
711
  else
555
- "Enum value `#{enum.name}.#{new_enum_value.name}` was deprecated with reason" \
712
+ "Enum value `#{enum.graphql_name}.#{new_enum_value.graphql_name}` was deprecated with reason" \
556
713
  " `#{new_enum_value.deprecation_reason}`"
557
714
  end
558
715
  end
716
+
717
+ def path
718
+ [enum.graphql_name, old_enum_value.graphql_name].join(".")
719
+ end
559
720
  end
560
721
 
561
722
  class InputFieldDescriptionChanged < AbstractChange
@@ -569,9 +730,13 @@ module GraphQL
569
730
  end
570
731
 
571
732
  def message
572
- "Input field `#{input_type.name}.#{old_field.name}` description changed"\
733
+ "Input field `#{input_type.graphql_definition}.#{old_field.graphql_name}` description changed"\
573
734
  " from `#{old_field.description}` to `#{new_field.description}`"
574
735
  end
736
+
737
+ def path
738
+ [input_type.graphql_definition, old_field.graphql_name].join(".")
739
+ end
575
740
  end
576
741
 
577
742
  class DirectiveDescriptionChanged < AbstractChange
@@ -584,9 +749,13 @@ module GraphQL
584
749
  end
585
750
 
586
751
  def message
587
- "Directive `#{new_directive.name}` description changed"\
752
+ "Directive `#{new_directive.graphql_name}` description changed"\
588
753
  " from `#{old_directive.description}` to `#{new_directive.description}`"
589
754
  end
755
+
756
+ def path
757
+ "@#{old_directive.graphql_name}"
758
+ end
590
759
  end
591
760
 
592
761
  class FieldDescriptionChanged < AbstractChange
@@ -600,9 +769,13 @@ module GraphQL
600
769
  end
601
770
 
602
771
  def message
603
- "Field `#{type.name}.#{old_field.name}` description changed"\
772
+ "Field `#{type.graphql_definition}.#{old_field.graphql_name}` description changed"\
604
773
  " from `#{old_field.description}` to `#{new_field.description}`"
605
774
  end
775
+
776
+ def path
777
+ [type.graphql_definition, old_field.graphql_name].join(".")
778
+ end
606
779
  end
607
780
 
608
781
  class FieldArgumentDescriptionChanged < AbstractChange
@@ -617,9 +790,13 @@ module GraphQL
617
790
  end
618
791
 
619
792
  def message
620
- "Description for argument `#{new_argument.name}` on field `#{type.name}.#{field.name}` changed"\
793
+ "Description for argument `#{new_argument.graphql_name}` on field `#{type.graphql_definition}.#{field.graphql_name}` changed"\
621
794
  " from `#{old_argument.description}` to `#{new_argument.description}`"
622
795
  end
796
+
797
+ def path
798
+ [type.graphql_definition, field.graphql_name, old_argument.graphql_name].join(".")
799
+ end
623
800
  end
624
801
 
625
802
  class DirectiveArgumentDescriptionChanged < AbstractChange
@@ -633,9 +810,13 @@ module GraphQL
633
810
  end
634
811
 
635
812
  def message
636
- "Description for argument `#{new_argument.name}` on directive `#{directive.name}` changed"\
813
+ "Description for argument `#{new_argument.graphql_name}` on directive `#{directive.graphql_name}` changed"\
637
814
  " from `#{old_argument.description}` to `#{new_argument.description}`"
638
815
  end
816
+
817
+ def path
818
+ ["@#{directive.graphql_name}", old_argument.graphql_name].join(".")
819
+ end
639
820
  end
640
821
 
641
822
  class FieldDeprecationChanged < AbstractChange
@@ -649,9 +830,13 @@ module GraphQL
649
830
  end
650
831
 
651
832
  def message
652
- "Deprecation reason on field `#{type.name}.#{new_field.name}` has changed "\
833
+ "Deprecation reason on field `#{type.graphql_definition}.#{new_field.graphql_name}` has changed "\
653
834
  "from `#{old_field.deprecation_reason}` to `#{new_field.deprecation_reason}`"
654
835
  end
836
+
837
+ def path
838
+ [type.graphql_definition, old_field.graphql_name].join(".")
839
+ end
655
840
  end
656
841
 
657
842
  class FieldAdded < AbstractChange
@@ -664,9 +849,12 @@ module GraphQL
664
849
  end
665
850
 
666
851
  def message
667
- "Field `#{field.name}` was added to object type `#{object_type.name}`"
852
+ "Field `#{field.graphql_name}` was added to object type `#{object_type.graphql_definition}`"
668
853
  end
669
854
 
855
+ def path
856
+ [object_type.graphql_definition, field.graphql_name].join(".")
857
+ end
670
858
  end
671
859
 
672
860
  class DirectiveLocationAdded < AbstractChange
@@ -679,7 +867,11 @@ module GraphQL
679
867
  end
680
868
 
681
869
  def message
682
- "Location `#{location}` was added to directive `#{directive.name}`"
870
+ "Location `#{location}` was added to directive `#{directive.graphql_name}`"
871
+ end
872
+
873
+ def path
874
+ "@#{directive.graphql_name}"
683
875
  end
684
876
  end
685
877
 
@@ -841,7 +1033,7 @@ module GraphQL
841
1033
  end
842
1034
 
843
1035
  def message
844
- "Argument `#{argument.name}` was added to directive `#{directive.name}`"
1036
+ "Argument `#{argument.graphql_name}` was added to directive `#{directive.graphql_name}`"
845
1037
  end
846
1038
  end
847
1039
  end
@@ -21,7 +21,7 @@ module GraphQL
21
21
  changes << Changes::FieldArgumentDefaultChanged.new(type, field, old_arg, new_arg)
22
22
  end
23
23
 
24
- if old_arg.type != new_arg.type
24
+ if old_arg.type.graphql_definition != new_arg.type.graphql_definition
25
25
  changes << Changes::FieldArgumentTypeChanged.new(type, field, old_arg, new_arg)
26
26
  end
27
27
 
@@ -49,8 +49,8 @@ module GraphQL
49
49
  def each_common_argument(&block)
50
50
  intersection = old_arguments.keys & new_arguments.keys
51
51
  intersection.each do |common_arg|
52
- old_arg = new_directive.arguments[common_arg]
53
- new_arg = old_directive.arguments[common_arg]
52
+ old_arg = old_directive.arguments[common_arg]
53
+ new_arg = new_directive.arguments[common_arg]
54
54
 
55
55
  block.call(old_arg, new_arg)
56
56
  end
@@ -19,7 +19,7 @@ module GraphQL
19
19
  changes << Changes::DirectiveArgumentDefaultChanged.new(directive, old_arg, new_arg)
20
20
  end
21
21
 
22
- if old_arg.type != new_arg.type
22
+ if old_arg.type.graphql_definition != new_arg.type.graphql_definition
23
23
  changes << Changes::DirectiveArgumentTypeChanged.new(directive, old_arg, new_arg)
24
24
  end
25
25
 
@@ -24,7 +24,7 @@ module GraphQL
24
24
  changes << Changes::FieldDeprecationChanged.new(new_type, old_field, new_field)
25
25
  end
26
26
 
27
- if old_field.type != new_field.type
27
+ if old_field.type.graphql_definition != new_field.type.graphql_definition
28
28
  changes << Changes::FieldTypeChanged.new(new_type, old_field, new_field)
29
29
  end
30
30
 
@@ -21,7 +21,7 @@ module GraphQL
21
21
  changes << Changes::InputFieldDefaultChanged.new(old_type, old_field, new_field)
22
22
  end
23
23
 
24
- if old_field.type != new_field.type
24
+ if old_field.type.graphql_definition != new_field.type.graphql_definition
25
25
  changes << Changes::InputFieldTypeChanged.new(old_type, old_field, new_field)
26
26
  end
27
27
 
@@ -3,8 +3,8 @@ module GraphQL
3
3
  module Diff
4
4
  class ObjectType
5
5
  def initialize(old_type, new_type)
6
- @old_type = old_type
7
- @new_type = new_type
6
+ @old_type = old_type.graphql_definition
7
+ @new_type = new_type.graphql_definition
8
8
 
9
9
  @old_fields = old_type.fields
10
10
  @new_fields = new_type.fields
@@ -40,15 +40,19 @@ module GraphQL
40
40
  )
41
41
 
42
42
  def interface_removals
43
- removed = old_interfaces.select { |iface| !new_interfaces.include?(iface) }
43
+ removed = filter_interfaces(old_interfaces, new_interfaces)
44
44
  removed.map { |iface| Changes::ObjectTypeInterfaceRemoved.new(iface, old_type) }
45
45
  end
46
46
 
47
47
  def interface_additions
48
- added = new_interfaces.select { |iface| !old_interfaces.include?(iface) }
48
+ added = filter_interfaces(new_interfaces, old_interfaces)
49
49
  added.map { |iface| Changes::ObjectTypeInterfaceAdded.new(iface, new_type) }
50
50
  end
51
51
 
52
+ def filter_interfaces(interfaces, excluded_interfaces)
53
+ interfaces.select { |interface| !excluded_interfaces.map(&:graphql_definition).include?(interface.graphql_definition) }
54
+ end
55
+
52
56
  def field_removals
53
57
  removed = old_fields.values.select { |field| !new_fields[field.name] }
54
58
  removed.map { |field| Changes::FieldRemoved.new(old_type, field) }
@@ -40,7 +40,7 @@ module GraphQL
40
40
  if old_type.kind != new_type.kind
41
41
  changes << Changes::TypeKindChanged.new(old_type, new_type)
42
42
  else
43
- case old_type
43
+ case old_type.graphql_definition
44
44
  when GraphQL::EnumType
45
45
  changes += Diff::Enum.new(old_type, new_type).diff
46
46
  when GraphQL::UnionType
@@ -64,15 +64,15 @@ module GraphQL
64
64
  def changes_in_schema
65
65
  changes = []
66
66
 
67
- if old_schema.query != new_schema.query
67
+ if old_schema.query&.to_graphql != new_schema.query&.to_graphql
68
68
  changes << Changes::SchemaQueryTypeChanged.new(old_schema, new_schema)
69
69
  end
70
70
 
71
- if old_schema.mutation != new_schema.mutation
71
+ if old_schema.mutation&.to_graphql != new_schema.mutation&.to_graphql
72
72
  changes << Changes::SchemaMutationTypeChanged.new(old_schema, new_schema)
73
73
  end
74
74
 
75
- if old_schema.subscription != new_schema.subscription
75
+ if old_schema.subscription&.to_graphql != new_schema.subscription&.to_graphql
76
76
  changes << Changes::SchemaSubscriptionTypeChanged.new(old_schema, new_schema)
77
77
  end
78
78
 
@@ -26,11 +26,15 @@ module GraphQL
26
26
  attr_reader :old_type, :new_type, :old_possible_types, :new_possible_types
27
27
 
28
28
  def removed_possible_types
29
- old_possible_types.select { |type| !new_possible_types.include?(type) }
29
+ filter_types(old_possible_types, new_possible_types)
30
30
  end
31
31
 
32
32
  def added_possible_types
33
- new_possible_types.select { |type| !old_possible_types.include?(type) }
33
+ filter_types(new_possible_types, old_possible_types)
34
+ end
35
+
36
+ def filter_types(types, exclude_types)
37
+ types.select { |type| !exclude_types.map(&:graphql_definition).include?(type.graphql_definition) }
34
38
  end
35
39
  end
36
40
  end
@@ -1,5 +1,5 @@
1
1
  module GraphQL
2
2
  module SchemaComparator
3
- VERSION = "0.5.0"
3
+ VERSION = "1.0.1"
4
4
  end
5
5
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: graphql-schema_comparator
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.5.0
4
+ version: 1.0.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Marc-Andre Giroux
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2017-12-02 00:00:00.000000000 Z
11
+ date: 2021-05-26 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: graphql
@@ -16,40 +16,46 @@ dependencies:
16
16
  requirements:
17
17
  - - "~>"
18
18
  - !ruby/object:Gem::Version
19
- version: '1.6'
19
+ version: '1.10'
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
24
  - - "~>"
25
25
  - !ruby/object:Gem::Version
26
- version: '1.6'
26
+ version: '1.10'
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: thor
29
29
  requirement: !ruby/object:Gem::Requirement
30
30
  requirements:
31
- - - "~>"
31
+ - - ">="
32
32
  - !ruby/object:Gem::Version
33
33
  version: '0.19'
34
+ - - "<"
35
+ - !ruby/object:Gem::Version
36
+ version: '2.0'
34
37
  type: :runtime
35
38
  prerelease: false
36
39
  version_requirements: !ruby/object:Gem::Requirement
37
40
  requirements:
38
- - - "~>"
41
+ - - ">="
39
42
  - !ruby/object:Gem::Version
40
43
  version: '0.19'
44
+ - - "<"
45
+ - !ruby/object:Gem::Version
46
+ version: '2.0'
41
47
  - !ruby/object:Gem::Dependency
42
48
  name: bundler
43
49
  requirement: !ruby/object:Gem::Requirement
44
50
  requirements:
45
- - - "~>"
51
+ - - ">="
46
52
  - !ruby/object:Gem::Version
47
53
  version: '1.14'
48
- type: :development
54
+ type: :runtime
49
55
  prerelease: false
50
56
  version_requirements: !ruby/object:Gem::Requirement
51
57
  requirements:
52
- - - "~>"
58
+ - - ">="
53
59
  - !ruby/object:Gem::Version
54
60
  version: '1.14'
55
61
  - !ruby/object:Gem::Dependency
@@ -104,8 +110,8 @@ executables:
104
110
  extensions: []
105
111
  extra_rdoc_files: []
106
112
  files:
113
+ - ".github/workflows/ci.yml"
107
114
  - ".gitignore"
108
- - ".travis.yml"
109
115
  - CHANGELOG.md
110
116
  - CODE_OF_CONDUCT.md
111
117
  - Gemfile
@@ -155,8 +161,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
155
161
  - !ruby/object:Gem::Version
156
162
  version: '0'
157
163
  requirements: []
158
- rubyforge_project:
159
- rubygems_version: 2.6.8
164
+ rubygems_version: 3.0.3
160
165
  signing_key:
161
166
  specification_version: 4
162
167
  summary: Compare GraphQL schemas and get the changes that happened.
data/.travis.yml DELETED
@@ -1,10 +0,0 @@
1
- ---
2
- language: ruby
3
- sudo: false
4
- cache: bundler
5
- before_install:
6
- - gem update --system --no-doc
7
- - gem install bundler
8
- rvm:
9
- - 2.3.4
10
- - 2.4.1