graphql-schema_comparator 1.1.2 → 1.2.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 9b44c88f5ca678f250a1f7a90021d7ae5cae95a899b524ed8551878329de7e53
4
- data.tar.gz: d49d50b3d029030a09170773db81b493f7ffb781006238129bfb17bcdf625301
3
+ metadata.gz: 9a21994b860741a5060b7600e7473348c0bf0445ecca50ea68966762448a967f
4
+ data.tar.gz: b4197e9f75dac972f474fd578fab78588b54f77ade6d36b126ad57a3f702b85c
5
5
  SHA512:
6
- metadata.gz: a0d2435ef322c736c666d634e735720313d2befc4768dcdfb744209fce67d43bcc523c09c051c581de456fdcc82ff687dd072102088704f52a694ca13076052e
7
- data.tar.gz: 8850e901ebe67bbc4400fb20617ab59cf33ddaf45469008a3cc7bbc27609fbef488747ffb4b6db95af4f0c4572f03fbf43fba9cd5d38eb4adef896ca58624256
6
+ metadata.gz: 0b637ed11e3ba28902bd61f9e082cb0ac20f0be6868450b70e6e04df56b0019cbdba4a869d750e4dcaee4af454da799ae05512d2299300cbab3497d5d09d8392
7
+ data.tar.gz: 276c28e5588937b25361937ae594ff678981f71ac84f8f370ebada3e917e8f22f44a54c8dfb32cb9cfa8bf4e58b467dc42de6eb8ef22f864446b50c23f668a1e
data/CHANGELOG.md CHANGED
@@ -1,5 +1,12 @@
1
1
  # Changelog
2
2
 
3
+ ## 1.2.0 (October 18 2023)
4
+
5
+ ### Bug Fix
6
+
7
+ - More selective detection of breaking/dangerous enum value changes (#54)
8
+ - Improve schema root operation type changes (#55)
9
+
3
10
  ## 1.1.2 (September 15 2022)
4
11
 
5
12
  ### 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
218
+
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
200
237
 
201
- def initialize(old_schema, new_schema)
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
@@ -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.0"
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.0
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-18 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: []