graphql-schema_comparator 1.1.2 → 1.2.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
2
  SHA256:
3
- metadata.gz: 9b44c88f5ca678f250a1f7a90021d7ae5cae95a899b524ed8551878329de7e53
4
- data.tar.gz: d49d50b3d029030a09170773db81b493f7ffb781006238129bfb17bcdf625301
3
+ metadata.gz: aa337e772bf6a06c8ee1043b482e556d0536bbdc20df463ac8281e98ed8b970e
4
+ data.tar.gz: 1de6b8f0b37cab53d2c20481ea62099e1e09ed382d1c8bccfcf3f2a0c3e58401
5
5
  SHA512:
6
- metadata.gz: a0d2435ef322c736c666d634e735720313d2befc4768dcdfb744209fce67d43bcc523c09c051c581de456fdcc82ff687dd072102088704f52a694ca13076052e
7
- data.tar.gz: 8850e901ebe67bbc4400fb20617ab59cf33ddaf45469008a3cc7bbc27609fbef488747ffb4b6db95af4f0c4572f03fbf43fba9cd5d38eb4adef896ca58624256
6
+ metadata.gz: b08bf90193cd6fe2858c369c86d02cfbe6903aae1535743eb75b966de8303da0f7d6901dda33343c36ebbebf28c9e73d2f115713125f93e5aa88cd7e62a8d18f
7
+ data.tar.gz: db81019920724822356558d021097a2af6a3440d3fb744c8b73c19d9eec58f7745a236fb36afebd08c264b5965650ad31c0021d3d04b522931ac56edb427c862
data/CHANGELOG.md CHANGED
@@ -1,5 +1,18 @@
1
1
  # Changelog
2
2
 
3
+ ## 1.2.1 (October 27 2023)
4
+
5
+ ### Bug Fix
6
+
7
+ - Add support for path on `DirectiveArgumentAdded` (#57)
8
+
9
+ ## 1.2.0 (October 18 2023)
10
+
11
+ ### Bug Fix
12
+
13
+ - More selective detection of breaking/dangerous enum value changes (#54)
14
+ - Improve schema root operation type changes (#55)
15
+
3
16
  ## 1.1.2 (September 15 2022)
4
17
 
5
18
  ### Bug Fix
@@ -99,12 +99,18 @@ module GraphQL
99
99
  class EnumValueRemoved < AbstractChange
100
100
  attr_reader :enum_value, :enum_type, :criticality
101
101
 
102
- def initialize(enum_type, enum_value)
102
+ def initialize(enum_type, enum_value, usage)
103
103
  @enum_value = enum_value
104
104
  @enum_type = enum_type
105
- @criticality = Changes::Criticality.breaking(
106
- reason: "Removing an enum value will cause existing queries that use this enum value to error."
107
- )
105
+ @criticality = if usage.input?
106
+ Changes::Criticality.breaking(
107
+ reason: "Removing an enum value will cause existing queries that use this enum value to error."
108
+ )
109
+ else
110
+ Changes::Criticality.non_breaking(
111
+ reason: "Removing an enum value for enums used only in outputs is non-breaking."
112
+ )
113
+ end
108
114
  end
109
115
 
110
116
  def message
@@ -195,21 +201,93 @@ module GraphQL
195
201
  end
196
202
  end
197
203
 
198
- class SchemaQueryTypeChanged < AbstractChange
199
- attr_reader :old_schema, :new_schema, :criticality
204
+ class RootOperationTypeAdded < AbstractChange
205
+ attr_reader :new_schema, :operation_type, :criticality
206
+
207
+ def initialize(new_schema:, operation_type:)
208
+ @new_schema = new_schema
209
+ @operation_type = operation_type
210
+ @criticality = Changes::Criticality.non_breaking(
211
+ reason: "Adding a schema #{operation_type} root is considered non-breaking."
212
+ )
213
+ end
214
+
215
+ def message
216
+ "Schema #{operation_type} root `#{operation_type_name}` was added"
217
+ end
200
218
 
201
- def initialize(old_schema, new_schema)
219
+ def path
220
+ operation_type_name
221
+ end
222
+
223
+ def operation_type_name
224
+ case operation_type
225
+ when :query
226
+ new_schema.query.graphql_name
227
+ when :mutation
228
+ new_schema.mutation.graphql_name
229
+ when :subscription
230
+ new_schema.subscription.graphql_name
231
+ end
232
+ end
233
+ end
234
+
235
+ class RootOperationTypeChanged < AbstractChange
236
+ attr_reader :old_schema, :new_schema, :operation_type, :criticality
237
+
238
+ def initialize(old_schema:, new_schema:, operation_type:)
202
239
  @old_schema = old_schema
203
240
  @new_schema = new_schema
241
+ @operation_type = operation_type
204
242
  @criticality = Changes::Criticality.breaking
205
243
  end
206
244
 
207
245
  def message
208
- "Schema query root has changed from `#{old_schema.query.graphql_name}` to `#{new_schema.query.graphql_name}`"
246
+ "Schema #{operation_type} root has changed from `#{operation_type_name(old_schema)}` to `#{operation_type_name(new_schema)}`"
209
247
  end
210
248
 
211
249
  def path
212
- # TODO
250
+ operation_type_name(old_schema)
251
+ end
252
+
253
+ def operation_type_name(schema)
254
+ case operation_type
255
+ when :query
256
+ schema.query.graphql_name
257
+ when :mutation
258
+ schema.mutation.graphql_name
259
+ when :subscription
260
+ schema.subscription.graphql_name
261
+ end
262
+ end
263
+ end
264
+
265
+ class RootOperationTypeRemoved < AbstractChange
266
+ attr_reader :old_schema, :operation_type, :criticality
267
+
268
+ def initialize(old_schema:, operation_type:)
269
+ @old_schema = old_schema
270
+ @operation_type = operation_type
271
+ @criticality = Changes::Criticality.breaking
272
+ end
273
+
274
+ def message
275
+ "Schema #{operation_type} root `#{operation_type_name}` was removed"
276
+ end
277
+
278
+ def path
279
+ operation_type_name
280
+ end
281
+
282
+ def operation_type_name
283
+ case operation_type
284
+ when :query
285
+ old_schema.query.graphql_name
286
+ when :mutation
287
+ old_schema.mutation.graphql_name
288
+ when :subscription
289
+ old_schema.subscription.graphql_name
290
+ end
213
291
  end
214
292
  end
215
293
 
@@ -398,42 +476,6 @@ module GraphQL
398
476
  end
399
477
  end
400
478
 
401
- class SchemaMutationTypeChanged < AbstractChange
402
- attr_reader :old_schema, :new_schema, :criticality
403
-
404
- def initialize(old_schema, new_schema)
405
- @old_schema = old_schema
406
- @new_schema = new_schema
407
- @criticality = Changes::Criticality.breaking
408
- end
409
-
410
- def message
411
- "Schema mutation root has changed from `#{old_schema.mutation}` to `#{new_schema.mutation}`"
412
- end
413
-
414
- def path
415
- # TODO
416
- end
417
- end
418
-
419
- class SchemaSubscriptionTypeChanged < AbstractChange
420
- attr_reader :old_schema, :new_schema, :criticality
421
-
422
- def initialize(old_schema, new_schema)
423
- @old_schema = old_schema
424
- @new_schema = new_schema
425
- @criticality = Changes::Criticality.breaking
426
- end
427
-
428
- def message
429
- "Schema subscription type has changed from `#{old_schema.subscription}` to `#{new_schema.subscription}`"
430
- end
431
-
432
- def path
433
- # TODO
434
- end
435
- end
436
-
437
479
  # Dangerous Changes
438
480
 
439
481
  class FieldArgumentDefaultChanged < AbstractChange
@@ -451,11 +493,11 @@ module GraphQL
451
493
  end
452
494
 
453
495
  def message
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 `#{field.path}`"
456
- else
496
+ if old_argument.default_value?
457
497
  "Default value for argument `#{new_argument.graphql_name}` on field `#{field.path}` changed"\
458
498
  " from `#{old_argument.default_value}` to `#{new_argument.default_value}`"
499
+ else
500
+ "Default value `#{new_argument.default_value}` was added to argument `#{new_argument.graphql_name}` on field `#{field.path}`"
459
501
  end
460
502
  end
461
503
 
@@ -501,8 +543,12 @@ module GraphQL
501
543
  end
502
544
 
503
545
  def message
504
- "Default value for argument `#{new_argument.graphql_name}` on directive `#{directive.graphql_name}` changed"\
505
- " from `#{old_argument.default_value}` to `#{new_argument.default_value}`"
546
+ if old_argument.default_value?
547
+ "Default value for argument `#{new_argument.graphql_name}` on directive `#{directive.graphql_name}` changed"\
548
+ " from `#{old_argument.default_value}` to `#{new_argument.default_value}`"
549
+ else
550
+ "Default value `#{new_argument.default_value}` was added to argument `#{new_argument.graphql_name}` on directive `#{directive.graphql_name}`"
551
+ end
506
552
  end
507
553
 
508
554
  def path
@@ -513,13 +559,19 @@ module GraphQL
513
559
  class EnumValueAdded < AbstractChange
514
560
  attr_reader :enum_type, :enum_value, :criticality
515
561
 
516
- def initialize(enum_type, enum_value)
562
+ def initialize(enum_type, enum_value, usage)
517
563
  @enum_type = enum_type
518
564
  @enum_value = enum_value
519
- @criticality = Changes::Criticality.dangerous(
520
- reason: "Adding an enum value may break existing clients that were not " \
521
- "programming defensively against an added case when querying an enum."
522
- )
565
+ @criticality = if usage.output?
566
+ Changes::Criticality.dangerous(
567
+ reason: "Adding an enum value may break existing clients that were not " \
568
+ "programmed defensively against an added case when querying an enum."
569
+ )
570
+ else
571
+ Changes::Criticality.non_breaking(
572
+ reason: "Adding an enum value for enums used only in inputs is non-breaking."
573
+ )
574
+ end
523
575
  end
524
576
 
525
577
  def message
@@ -1034,6 +1086,10 @@ module GraphQL
1034
1086
  def message
1035
1087
  "Argument `#{argument.graphql_name}` was added to directive `#{directive.graphql_name}`"
1036
1088
  end
1089
+
1090
+ def path
1091
+ ["@#{directive.graphql_name}", argument.graphql_name].join('.')
1092
+ end
1037
1093
  end
1038
1094
  end
1039
1095
  end
@@ -2,19 +2,21 @@ module GraphQL
2
2
  module SchemaComparator
3
3
  module Diff
4
4
  class Enum
5
- def initialize(old_enum, new_enum)
5
+ def initialize(old_enum, new_enum, usage)
6
6
  @old_enum = old_enum
7
7
  @new_enum = new_enum
8
8
 
9
9
  @old_values = old_enum.values
10
10
  @new_values = new_enum.values
11
+
12
+ @usage = usage
11
13
  end
12
14
 
13
15
  def diff
14
16
  changes = []
15
17
 
16
- changes += removed_values.map { |value| Changes::EnumValueRemoved.new(old_enum, value) }
17
- changes += added_values.map { |value| Changes::EnumValueAdded.new(new_enum, value) }
18
+ changes += removed_values.map { |value| Changes::EnumValueRemoved.new(old_enum, value, usage) }
19
+ changes += added_values.map { |value| Changes::EnumValueAdded.new(new_enum, value, usage) }
18
20
 
19
21
  each_common_value do |old_value, new_value|
20
22
  # TODO: Add Directive Stuff
@@ -33,7 +35,7 @@ module GraphQL
33
35
 
34
36
  private
35
37
 
36
- attr_reader :old_enum, :new_enum, :old_values, :new_values
38
+ attr_reader :old_enum, :new_enum, :old_values, :new_values, :usage
37
39
 
38
40
  def each_common_value(&block)
39
41
  intersection = old_values.keys & new_values.keys
@@ -42,7 +42,7 @@ module GraphQL
42
42
  else
43
43
  case old_type.kind.name
44
44
  when "ENUM"
45
- changes += Diff::Enum.new(old_type, new_type).diff
45
+ changes += Diff::Enum.new(old_type, new_type, enum_usage(new_type)).diff
46
46
  when "UNION"
47
47
  changes += Diff::Union.new(old_type, new_type).diff
48
48
  when "INPUT_OBJECT"
@@ -65,15 +65,33 @@ module GraphQL
65
65
  changes = []
66
66
 
67
67
  if old_schema.query&.graphql_name != new_schema.query&.graphql_name
68
- changes << Changes::SchemaQueryTypeChanged.new(old_schema, new_schema)
68
+ if old_schema.query.nil?
69
+ changes << Changes::RootOperationTypeAdded.new(new_schema: new_schema, operation_type: :query)
70
+ elsif new_schema.query.nil?
71
+ changes << Changes::RootOperationTypeRemoved.new(old_schema: old_schema, operation_type: :query)
72
+ else
73
+ changes << Changes::RootOperationTypeChanged.new(old_schema: old_schema, new_schema: new_schema, operation_type: :query)
74
+ end
69
75
  end
70
76
 
71
77
  if old_schema.mutation&.graphql_name != new_schema.mutation&.graphql_name
72
- changes << Changes::SchemaMutationTypeChanged.new(old_schema, new_schema)
78
+ if old_schema.mutation.nil?
79
+ changes << Changes::RootOperationTypeAdded.new(new_schema: new_schema, operation_type: :mutation)
80
+ elsif new_schema.mutation.nil?
81
+ changes << Changes::RootOperationTypeRemoved.new(old_schema: old_schema, operation_type: :mutation)
82
+ else
83
+ changes << Changes::RootOperationTypeChanged.new(old_schema: old_schema, new_schema: new_schema, operation_type: :mutation)
84
+ end
73
85
  end
74
86
 
75
87
  if old_schema.subscription&.graphql_name != new_schema.subscription&.graphql_name
76
- changes << Changes::SchemaSubscriptionTypeChanged.new(old_schema, new_schema)
88
+ if old_schema.subscription.nil?
89
+ changes << Changes::RootOperationTypeAdded.new(new_schema: new_schema, operation_type: :subscription)
90
+ elsif new_schema.subscription.nil?
91
+ changes << Changes::RootOperationTypeRemoved.new(old_schema: old_schema, operation_type: :subscription)
92
+ else
93
+ changes << Changes::RootOperationTypeChanged.new(old_schema: old_schema, new_schema: new_schema, operation_type: :subscription)
94
+ end
77
95
  end
78
96
 
79
97
  changes
@@ -94,6 +112,12 @@ module GraphQL
94
112
 
95
113
  private
96
114
 
115
+ def enum_usage(new_enum)
116
+ input_usage = new_schema.references_to(new_enum).any? { |member| member.is_a?(GraphQL::Schema::Argument) }
117
+ output_usage = new_schema.references_to(new_enum).any? { |member| member.is_a?(GraphQL::Schema::Field) }
118
+ EnumUsage.new(input: input_usage, output: output_usage)
119
+ end
120
+
97
121
  def each_common_type(&block)
98
122
  intersection = old_types.keys & new_types.keys
99
123
  intersection.each do |common_type_name|
@@ -0,0 +1,18 @@
1
+ module GraphQL
2
+ module SchemaComparator
3
+ class EnumUsage
4
+ def initialize(input:, output:)
5
+ @input = input
6
+ @output = output
7
+ end
8
+
9
+ def input?
10
+ @input
11
+ end
12
+
13
+ def output?
14
+ @output
15
+ end
16
+ end
17
+ end
18
+ end
@@ -1,5 +1,5 @@
1
1
  module GraphQL
2
2
  module SchemaComparator
3
- VERSION = "1.1.2"
3
+ VERSION = "1.2.1"
4
4
  end
5
5
  end
@@ -4,6 +4,7 @@ require "graphql/schema_comparator/version"
4
4
  require "graphql/schema_comparator/result"
5
5
 
6
6
  require 'graphql/schema_comparator/changes'
7
+ require 'graphql/schema_comparator/enum_usage'
7
8
 
8
9
  require "graphql/schema_comparator/diff/schema"
9
10
  require "graphql/schema_comparator/diff/argument"
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: 1.1.2
4
+ version: 1.2.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Marc-Andre Giroux
8
- autorequire:
8
+ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2022-09-15 00:00:00.000000000 Z
11
+ date: 2023-10-27 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: graphql
@@ -147,6 +147,7 @@ files:
147
147
  - lib/graphql/schema_comparator/diff/object_type.rb
148
148
  - lib/graphql/schema_comparator/diff/schema.rb
149
149
  - lib/graphql/schema_comparator/diff/union.rb
150
+ - lib/graphql/schema_comparator/enum_usage.rb
150
151
  - lib/graphql/schema_comparator/result.rb
151
152
  - lib/graphql/schema_comparator/version.rb
152
153
  - schema.graphql
@@ -158,7 +159,7 @@ metadata:
158
159
  changelog_uri: https://github.com/xuorig/graphql-schema_comparator/blob/master/CHANGELOG.md
159
160
  source_code_uri: https://github.com/xuorig/graphql-schema_comparator
160
161
  bug_tracker_uri: https://github.com/xuorig/graphql-schema_comparator/issues
161
- post_install_message:
162
+ post_install_message:
162
163
  rdoc_options: []
163
164
  require_paths:
164
165
  - lib
@@ -173,8 +174,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
173
174
  - !ruby/object:Gem::Version
174
175
  version: '0'
175
176
  requirements: []
176
- rubygems_version: 3.0.3.1
177
- signing_key:
177
+ rubygems_version: 3.4.10
178
+ signing_key:
178
179
  specification_version: 4
179
180
  summary: Compare GraphQL schemas and get the changes that happened.
180
181
  test_files: []