graphql-schema_comparator 0.4.0 → 0.5.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +18 -0
- data/README.md +27 -22
- data/bin/graphql-schema +2 -0
- data/bin/schema_comparator +55 -0
- data/graphql-schema_comparator.gemspec +1 -1
- data/lib/graphql/schema_comparator.rb +7 -1
- data/lib/graphql/schema_comparator/changes.rb +352 -431
- data/lib/graphql/schema_comparator/changes/criticality.rb +88 -0
- data/lib/graphql/schema_comparator/changes/safe_type_change.rb +34 -0
- data/lib/graphql/schema_comparator/result.rb +10 -3
- data/lib/graphql/schema_comparator/version.rb +1 -1
- metadata +6 -2
@@ -0,0 +1,88 @@
|
|
1
|
+
module GraphQL
|
2
|
+
module SchemaComparator
|
3
|
+
module Changes
|
4
|
+
# Defines the criticality of a {Change} object.
|
5
|
+
class Criticality
|
6
|
+
# Non-breaking criticality usually defines changes that are always
|
7
|
+
# safe to make to a GraphQL Schema. They do not
|
8
|
+
# require any changes on the client side
|
9
|
+
NON_BREAKING = 1
|
10
|
+
|
11
|
+
# Dangerous criticality defines changes that are not breaking
|
12
|
+
# the schema, but may break runtime logic on clients
|
13
|
+
# if they did not code defensively enough to prevent
|
14
|
+
# these changes.
|
15
|
+
DANGEROUS = 2
|
16
|
+
|
17
|
+
# Breaking criticality are changes that immediatly impact
|
18
|
+
# clients usually causing queries not to be valid anymore.
|
19
|
+
BREAKING = 3
|
20
|
+
|
21
|
+
attr_reader :level, :reason
|
22
|
+
|
23
|
+
class << self
|
24
|
+
# Returns a new Criticality object with a BREAKING level
|
25
|
+
# @param reason [String] optional reason for this criticality
|
26
|
+
# @return [GraphQL::SchemaComparator::Changes::Criticality]
|
27
|
+
def breaking(reason: "This change is a breaking change")
|
28
|
+
new(
|
29
|
+
level: BREAKING,
|
30
|
+
reason: reason
|
31
|
+
)
|
32
|
+
end
|
33
|
+
|
34
|
+
# Returns a new Criticality object with a NON_BREAKING level
|
35
|
+
# @param reason [String] optional reason for this criticality
|
36
|
+
# @return [GraphQL::SchemaComparator::Changes::Criticality]
|
37
|
+
def non_breaking(reason: "This change is safe")
|
38
|
+
new(
|
39
|
+
level: NON_BREAKING,
|
40
|
+
reason: reason
|
41
|
+
)
|
42
|
+
end
|
43
|
+
|
44
|
+
# Returns a new Criticality object with a DANGEROUS level
|
45
|
+
# @param reason [String] optional reason for this criticality
|
46
|
+
# @return [GraphQL::SchemaComparator::Changes::Criticality]
|
47
|
+
def dangerous(reason: "This change is dangerous")
|
48
|
+
new(
|
49
|
+
level: DANGEROUS,
|
50
|
+
reason: reason
|
51
|
+
)
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
# Creates a new Criticality object
|
56
|
+
#
|
57
|
+
# @param level [Symbol] The criticality level
|
58
|
+
# @param reason [String] The reason why this criticality is set on the change
|
59
|
+
def initialize(level: NON_BREAKING, reason: nil)
|
60
|
+
@level = level
|
61
|
+
@reason = reason
|
62
|
+
end
|
63
|
+
|
64
|
+
def <=>(other)
|
65
|
+
if level == other.level
|
66
|
+
0
|
67
|
+
elsif level < other.level
|
68
|
+
-1
|
69
|
+
else
|
70
|
+
1
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
def breaking?
|
75
|
+
@level == BREAKING
|
76
|
+
end
|
77
|
+
|
78
|
+
def non_breaking?
|
79
|
+
@level == NON_BREAKING
|
80
|
+
end
|
81
|
+
|
82
|
+
def dangerous?
|
83
|
+
@level == DANGEROUS
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
module GraphQL
|
2
|
+
module SchemaComparator
|
3
|
+
module Changes
|
4
|
+
module SafeTypeChange
|
5
|
+
def safe_change_for_field?(old_type, new_type)
|
6
|
+
if !old_type.kind.wraps? && !new_type.kind.wraps?
|
7
|
+
old_type == new_type
|
8
|
+
elsif new_type.kind.non_null?
|
9
|
+
of_type = old_type.kind.non_null? ? old_type.of_type : old_type
|
10
|
+
safe_change_for_field?(of_type, new_type.of_type)
|
11
|
+
elsif old_type.kind.list?
|
12
|
+
new_type.kind.list? && safe_change_for_field?(old_type.of_type, new_type.of_type) ||
|
13
|
+
new_type.kind.non_null? && safe_change_for_field?(old_type, new_type.of_type)
|
14
|
+
else
|
15
|
+
false
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
def safe_change_for_input_value?(old_type, new_type)
|
20
|
+
if !old_type.kind.wraps? && !new_type.kind.wraps?
|
21
|
+
old_type == new_type
|
22
|
+
elsif old_type.kind.list? && new_type.kind.list?
|
23
|
+
safe_change_for_input_value?(old_type.of_type, new_type.of_type)
|
24
|
+
elsif old_type.kind.non_null?
|
25
|
+
of_type = new_type.kind.non_null? ? new_type.of_type : new_type
|
26
|
+
safe_change_for_input_value?(old_type.of_type, of_type)
|
27
|
+
else
|
28
|
+
false
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
@@ -1,17 +1,24 @@
|
|
1
1
|
module GraphQL
|
2
2
|
module SchemaComparator
|
3
|
+
# The result of a comparison between two schema versions
|
3
4
|
class Result
|
4
|
-
attr_reader :changes, :breaking_changes, :non_breaking_changes
|
5
|
+
attr_reader :changes, :breaking_changes, :non_breaking_changes, :dangerous_changes
|
5
6
|
|
6
7
|
def initialize(changes)
|
7
|
-
@changes = changes.sort_by
|
8
|
-
@breaking_changes
|
8
|
+
@changes = changes.sort_by(&:criticality).reverse
|
9
|
+
@breaking_changes = @changes.select(&:breaking?)
|
10
|
+
@non_breaking_changes = @changes.select(&:non_breaking?)
|
11
|
+
@dangerous_changes = @changes.select(&:dangerous?)
|
9
12
|
end
|
10
13
|
|
14
|
+
# If the two schemas were identical
|
15
|
+
# @return [Boolean]
|
11
16
|
def identical?
|
12
17
|
@changes.empty?
|
13
18
|
end
|
14
19
|
|
20
|
+
# If there was a breaking change between the two schema versions
|
21
|
+
# @return [Boolean]
|
15
22
|
def breaking?
|
16
23
|
breaking_changes.any?
|
17
24
|
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.
|
4
|
+
version: 0.5.0
|
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-
|
11
|
+
date: 2017-12-02 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: graphql
|
@@ -100,6 +100,7 @@ email:
|
|
100
100
|
- mgiroux0@gmail.com
|
101
101
|
executables:
|
102
102
|
- graphql-schema
|
103
|
+
- schema_comparator
|
103
104
|
extensions: []
|
104
105
|
extra_rdoc_files: []
|
105
106
|
files:
|
@@ -113,10 +114,13 @@ files:
|
|
113
114
|
- Rakefile
|
114
115
|
- bin/console
|
115
116
|
- bin/graphql-schema
|
117
|
+
- bin/schema_comparator
|
116
118
|
- bin/setup
|
117
119
|
- graphql-schema_comparator.gemspec
|
118
120
|
- lib/graphql/schema_comparator.rb
|
119
121
|
- lib/graphql/schema_comparator/changes.rb
|
122
|
+
- lib/graphql/schema_comparator/changes/criticality.rb
|
123
|
+
- lib/graphql/schema_comparator/changes/safe_type_change.rb
|
120
124
|
- lib/graphql/schema_comparator/diff/argument.rb
|
121
125
|
- lib/graphql/schema_comparator/diff/directive.rb
|
122
126
|
- lib/graphql/schema_comparator/diff/directive_argument.rb
|