graphql-schema_comparator 0.4.0 → 0.5.0
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 +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
|