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.
@@ -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 { |c| [c.breaking? ? 1 : 2, c.message] }
8
- @breaking_changes, @non_breaking_changes = @changes.partition(&:breaking?)
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
@@ -1,5 +1,5 @@
1
1
  module GraphQL
2
2
  module SchemaComparator
3
- VERSION = "0.4.0"
3
+ VERSION = "0.5.0"
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.4.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-27 00:00:00.000000000 Z
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