chutney 2.1.0 → 3.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (55) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +8 -2
  3. data/Gemfile +2 -0
  4. data/README.md +6 -1
  5. data/Rakefile +2 -0
  6. data/chutney.gemspec +13 -6
  7. data/config/{chutney.yml → chutney_defaults.yml} +2 -0
  8. data/config/cucumber.yml +1 -0
  9. data/docs/usage/rules.md +7 -1
  10. data/exe/chutney +23 -3
  11. data/lib/chutney.rb +26 -22
  12. data/lib/chutney/configuration.rb +9 -2
  13. data/lib/chutney/formatter.rb +6 -5
  14. data/lib/chutney/formatter/json_formatter.rb +2 -0
  15. data/lib/chutney/formatter/pie_formatter.rb +11 -10
  16. data/lib/chutney/formatter/rainbow_formatter.rb +13 -13
  17. data/lib/chutney/issue.rb +2 -0
  18. data/lib/chutney/linter.rb +87 -83
  19. data/lib/chutney/linter/avoid_full_stop.rb +4 -4
  20. data/lib/chutney/linter/avoid_outline_for_single_example.rb +7 -5
  21. data/lib/chutney/linter/avoid_scripting.rb +8 -6
  22. data/lib/chutney/linter/avoid_typographers_quotes.rb +16 -14
  23. data/lib/chutney/linter/background_does_more_than_setup.rb +8 -7
  24. data/lib/chutney/linter/background_requires_multiple_scenarios.rb +7 -4
  25. data/lib/chutney/linter/bad_scenario_name.rb +6 -4
  26. data/lib/chutney/linter/empty_feature_file.rb +10 -0
  27. data/lib/chutney/linter/file_name_differs_feature_name.rb +7 -5
  28. data/lib/chutney/linter/givens_after_background.rb +7 -8
  29. data/lib/chutney/linter/invalid_file_name.rb +3 -1
  30. data/lib/chutney/linter/invalid_step_flow.rb +9 -9
  31. data/lib/chutney/linter/missing_example_name.rb +9 -9
  32. data/lib/chutney/linter/missing_feature_description.rb +6 -3
  33. data/lib/chutney/linter/missing_feature_name.rb +6 -3
  34. data/lib/chutney/linter/missing_scenario_name.rb +4 -6
  35. data/lib/chutney/linter/missing_test_action.rb +4 -2
  36. data/lib/chutney/linter/missing_verification.rb +4 -2
  37. data/lib/chutney/linter/required_tags_starts_with.rb +7 -6
  38. data/lib/chutney/linter/same_tag_for_all_scenarios.rb +20 -19
  39. data/lib/chutney/linter/scenario_names_match.rb +6 -6
  40. data/lib/chutney/linter/tag_used_multiple_times.rb +3 -1
  41. data/lib/chutney/linter/too_clumsy.rb +4 -2
  42. data/lib/chutney/linter/too_long_step.rb +6 -4
  43. data/lib/chutney/linter/too_many_different_tags.rb +10 -8
  44. data/lib/chutney/linter/too_many_steps.rb +6 -4
  45. data/lib/chutney/linter/too_many_tags.rb +5 -3
  46. data/lib/chutney/linter/unique_scenario_names.rb +5 -5
  47. data/lib/chutney/linter/unknown_variable.rb +15 -15
  48. data/lib/chutney/linter/unused_variable.rb +15 -16
  49. data/lib/chutney/linter/use_background.rb +20 -19
  50. data/lib/chutney/linter/use_outline.rb +15 -14
  51. data/lib/chutney/version.rb +3 -1
  52. data/lib/config/locales/en.yml +2 -0
  53. data/spec/chutney_spec.rb +11 -9
  54. data/spec/spec_helper.rb +2 -0
  55. metadata +19 -15
@@ -1,24 +1,26 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Chutney
2
4
  # service class to lint for too many different tags
3
5
  class TooManyDifferentTags < Linter
4
6
  def lint
5
7
  tags = all_tags
6
8
  return if tags.length <= maxcount
7
-
9
+
8
10
  add_issue(
9
- I18n.t('linters.too_many_different_tags', count: tags.length, max: maxcount),
11
+ I18n.t('linters.too_many_different_tags', count: tags.length, max: maxcount),
10
12
  feature
11
13
  )
12
14
  end
13
-
14
- def maxcount
15
+
16
+ def maxcount
15
17
  configuration['MaxCount']&.to_i || 3
16
18
  end
17
-
19
+
18
20
  def all_tags
19
- return [] unless feature.include?(:children)
20
-
21
- tags_for(feature) + feature[:children].map { |scenario| tags_for(scenario) }.flatten
21
+ return [] unless feature&.scenarios
22
+
23
+ tags_for(feature) + feature.scenarios.map { |scenario| tags_for(scenario) }.flatten
22
24
  end
23
25
  end
24
26
  end
@@ -1,17 +1,19 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Chutney
2
4
  # service class to lint for too many steps
3
5
  class TooManySteps < Linter
4
6
  def lint
5
7
  filled_scenarios do |feature, scenario|
6
- next if scenario[:steps].length <= maxcount
7
-
8
+ next if scenario.steps.length <= maxcount
9
+
8
10
  add_issue(
9
- I18n.t('linters.too_many_steps', count: scenario[:steps].length, max: maxcount),
11
+ I18n.t('linters.too_many_steps', count: scenario.steps.length, max: maxcount),
10
12
  feature
11
13
  )
12
14
  end
13
15
  end
14
-
16
+
15
17
  def maxcount
16
18
  configuration['MaxCount']&.to_i || 10
17
19
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Chutney
2
4
  # service class to lint for too many tags
3
5
  class TooManyTags < Linter
@@ -5,14 +7,14 @@ module Chutney
5
7
  scenarios do |feature, scenario|
6
8
  tags = tags_for(feature) + tags_for(scenario)
7
9
  next unless tags.length > maxcount
8
-
10
+
9
11
  add_issue(
10
- I18n.t('linters.too_many_tags', count: tags.length, max: maxcount),
12
+ I18n.t('linters.too_many_tags', count: tags.length, max: maxcount),
11
13
  feature
12
14
  )
13
15
  end
14
16
  end
15
-
17
+
16
18
  def maxcount
17
19
  configuration['MaxCount']&.to_i || 3
18
20
  end
@@ -1,12 +1,12 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Chutney
2
4
  # service class to lint for unique scenario names
3
5
  class UniqueScenarioNames < Linter
4
6
  def lint
5
7
  references_by_name = {}
6
8
  scenarios do |feature, scenario|
7
- next unless scenario.key? :name
8
-
9
- name = scenario[:name]
9
+ name = scenario.name
10
10
  if references_by_name[name]
11
11
  issue(name, references_by_name[name], scenario)
12
12
  else
@@ -14,13 +14,13 @@ module Chutney
14
14
  end
15
15
  end
16
16
  end
17
-
17
+
18
18
  def issue(name, first_location, scenario)
19
19
  add_issue(
20
20
  I18n.t('linters.unique_scenario_names',
21
21
  name: name,
22
22
  line: first_location[:line],
23
- column: first_location[:column]),
23
+ column: first_location[:column]),
24
24
  feature, scenario
25
25
  )
26
26
  end
@@ -1,13 +1,15 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Chutney
2
4
  # service class to lint for unknown variables
3
5
  class UnknownVariable < Linter
4
6
  def lint
5
7
  filled_scenarios do |feature, scenario|
6
8
  known_vars = Set.new(known_variables(scenario))
7
- scenario[:steps].each do |step|
9
+ scenario.steps.each do |step|
8
10
  step_vars(step).each do |used_var|
9
11
  next if known_vars.include? used_var
10
-
12
+
11
13
  add_issue(
12
14
  I18n.t('linters.unknown_variable', variable: used_var), feature, scenario
13
15
  )
@@ -17,17 +19,17 @@ module Chutney
17
19
  end
18
20
 
19
21
  def step_vars(step)
20
- vars = gather_vars step[:text]
21
- return vars unless step.include? :argument
22
-
23
- vars + gather_vars_from_argument(step[:argument])
22
+ vars = gather_vars step.text
23
+ return vars unless step.block
24
+
25
+ vars + gather_vars_from_argument(step.block)
24
26
  end
25
27
 
26
28
  def gather_vars_from_argument(argument)
27
- return gather_vars argument[:content] if argument[:type] == :DocString
28
-
29
- (argument[:rows] || []).map do |row|
30
- row[:cells].map { |value| gather_vars value[:value] }.flatten
29
+ return gather_vars argument.content if argument.is_a? CukeModeler::DocString
30
+
31
+ argument.rows.map do |row|
32
+ row.cells.map { |cell| gather_vars cell.value }.flatten
31
33
  end.flatten
32
34
  end
33
35
 
@@ -36,11 +38,9 @@ module Chutney
36
38
  end
37
39
 
38
40
  def known_variables(scenario)
39
- (scenario[:examples] || []).map do |example|
40
- next unless example.key? :tableHeader
41
-
42
- example[:tableHeader][:cells].map { |cell| cell[:value].strip }
43
- end.flatten
41
+ return [] unless scenario.is_a? CukeModeler::Outline
42
+
43
+ scenario.examples.map { |ex| ex.rows.first.cells.map(&:value) }.flatten
44
44
  end
45
45
  end
46
46
  end
@@ -1,14 +1,14 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Chutney
2
4
  # service class to lint for unused variables
3
5
  class UnusedVariable < Linter
4
6
  def lint
5
7
  scenarios do |feature, scenario|
6
- next unless scenario.key?(:examples)
7
-
8
- scenario[:examples].each do |example|
9
- next unless example.key?(:tableHeader)
10
-
11
- example[:tableHeader][:cells].map { |cell| cell[:value] }.each do |variable|
8
+ next unless scenario.is_a? CukeModeler::Outline
9
+
10
+ scenario.examples.each do |example|
11
+ example.rows.first.cells.map(&:value).each do |variable|
12
12
  next if used?(variable, scenario)
13
13
 
14
14
  add_issue(I18n.t('linters.unused_variable', variable: variable), feature, scenario, example)
@@ -19,11 +19,10 @@ module Chutney
19
19
 
20
20
  def used?(variable, scenario)
21
21
  variable = "<#{variable}>"
22
- return false unless scenario.key? :steps
23
-
24
- scenario[:steps].each do |step|
25
- return true if step[:text].include? variable
26
- next unless step.include? :argument
22
+
23
+ scenario.steps.each do |step|
24
+ return true if step.text.include? variable
25
+ next unless step.block
27
26
  return true if used_in_docstring?(variable, step)
28
27
  return true if used_in_table?(variable, step)
29
28
  end
@@ -31,14 +30,14 @@ module Chutney
31
30
  end
32
31
 
33
32
  def used_in_docstring?(variable, step)
34
- step[:argument][:type] == :DocString && step[:argument][:content].include?(variable)
33
+ step.block.is_a?(CukeModeler::DocString) && step.block.content.include?(variable)
35
34
  end
36
35
 
37
36
  def used_in_table?(variable, step)
38
- return false unless step[:argument][:type] == :DataTable
39
-
40
- step[:argument][:rows].each do |row|
41
- row[:cells].each { |value| return true if value[:value].include?(variable) }
37
+ return false unless step.block.is_a?(CukeModeler::Table)
38
+
39
+ step.block.rows.each do |row|
40
+ row.cells.each { |cell| return true if cell.value.include?(variable) }
42
41
  end
43
42
  false
44
43
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Chutney
2
4
  # service class to lint for using background
3
5
  class UseBackground < Linter
@@ -13,14 +15,13 @@ module Chutney
13
15
  end
14
16
 
15
17
  def gather_givens
16
- return unless feature.include? :children
17
-
18
+ return unless feature.children
19
+
18
20
  has_non_given_step = false
19
- feature[:children].each do |scenario|
20
- next unless scenario.include? :steps
21
- next if scenario[:steps].empty?
22
-
23
- has_non_given_step = true unless given_word?(scenario[:steps].first[:keyword])
21
+ scenarios do |_feature, scenario|
22
+ next unless scenario.steps
23
+
24
+ has_non_given_step = true unless given_word?(scenario.steps.first.keyword)
24
25
  end
25
26
  return if has_non_given_step
26
27
 
@@ -29,15 +30,13 @@ module Chutney
29
30
  result
30
31
  end
31
32
 
32
- def expanded_steps
33
- feature[:children].each do |scenario|
34
- next unless scenario[:type] != :Background
35
- next unless scenario.include? :steps
36
- next if scenario[:steps].empty?
37
-
38
- prototypes = [render_step(scenario[:steps].first)]
39
- prototypes = expand_examples(scenario[:examples], prototypes) if scenario.key? :examples
40
- prototypes.each { |prototype| yield prototype }
33
+ def expanded_steps(&block)
34
+ scenarios do |_feature, scenario|
35
+ next unless scenario.steps
36
+
37
+ prototypes = [render_step(scenario.steps.first)]
38
+ prototypes = expand_examples(scenario.examples, prototypes) if scenario.is_a? CukeModeler::Outline
39
+ prototypes.each(&block)
41
40
  end
42
41
  end
43
42
 
@@ -50,10 +49,12 @@ module Chutney
50
49
 
51
50
  def expand_outlines(sentence, example)
52
51
  result = []
53
- headers = example[:tableHeader][:cells].map { |cell| cell[:value] }
54
- example[:tableBody].each do |row| # .slice(1, example[:tableBody].length).each do |row|
52
+ headers = example.rows.first.cells.map(&:value)
53
+ example.rows.each_with_index do |row, idx|
54
+ next if idx.zero? # skip the header
55
+
55
56
  modified_sentence = sentence.dup
56
- headers.zip(row[:cells].map { |cell| cell[:value] }).map do |key, value|
57
+ headers.zip(row.cells.map(&:value)).map do |key, value|
57
58
  modified_sentence.gsub!("<#{key}>", value)
58
59
  end
59
60
  result.push modified_sentence
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Chutney
2
4
  # service class to lint for using outline
3
5
  class UseOutline < Linter
@@ -9,18 +11,18 @@ module Chutney
9
11
  scenarios.product(scenarios) do |lhs, rhs|
10
12
  next if lhs == rhs
11
13
  next if lhs[:reference][:line] > rhs[:reference][:line]
12
-
14
+
13
15
  similarity = determine_similarity(lhs[:text], rhs[:text])
14
16
  next unless similarity >= 0.95
15
-
17
+
16
18
  similarity_pct = similarity.round(3) * 100
17
-
19
+
18
20
  add_issue(lhs, rhs, similarity_pct)
19
21
  end
20
22
  end
21
-
23
+
22
24
  def add_issue(lhs, rhs, pct)
23
- super(I18n.t('linters.use_outline',
25
+ super(I18n.t('linters.use_outline',
24
26
  pct: pct,
25
27
  lhs_name: lhs[:name],
26
28
  lhs_line: lhs[:reference][:line],
@@ -36,13 +38,12 @@ module Chutney
36
38
 
37
39
  def gather_scenarios(feature)
38
40
  scenarios = []
39
- return scenarios unless feature.include? :children
40
-
41
- feature[:children].each do |scenario|
42
- next unless scenario[:type] == :Scenario
43
- next unless scenario.include? :steps
44
- next if scenario[:steps].empty?
45
-
41
+ return scenarios if feature.nil? || !feature.tests
42
+
43
+ scenarios do |_feature, scenario|
44
+ next unless scenario.steps
45
+ next if scenario.steps.empty?
46
+
46
47
  scenarios.push generate_reference(feature, scenario)
47
48
  end
48
49
  scenarios
@@ -51,8 +52,8 @@ module Chutney
51
52
  def generate_reference(feature, scenario)
52
53
  reference = {}
53
54
  reference[:reference] = location(feature, scenario, nil)
54
- reference[:name] = "#{scenario[:keyword]}: #{scenario[:name]}"
55
- reference[:text] = scenario[:steps].map { |step| render_step(step) }.join ' '
55
+ reference[:name] = "#{scenario.keyword}: #{scenario.name}"
56
+ reference[:text] = scenario.steps.map { |step| render_step(step) }.join ' '
56
57
  reference
57
58
  end
58
59
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Chutney
2
- VERSION = '2.1.0'.freeze
4
+ VERSION = '3.0.0'
3
5
  end
@@ -21,6 +21,8 @@ en:
21
21
  Avoid using Background if you only have a single scenario.
22
22
  bad_scenario_name: >-
23
23
  You should avoid using words like '%{word}' in your scenario names.
24
+ empty_feature_file: >-
25
+ The feature file is empty
24
26
  file_name_differs_feature_name: >-
25
27
  The name of the feature should reflect the file name. Consider renaming this feature
26
28
  to '%{expected}'.
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'chutney'
2
4
 
3
5
  describe Chutney::ChutneyLint do
@@ -6,25 +8,25 @@ describe Chutney::ChutneyLint do
6
8
  it 'has a version number' do
7
9
  expect(Chutney::VERSION).not_to be nil
8
10
  end
9
-
11
+
10
12
  describe '#initialize' do
11
13
  it 'creates an instance' do
12
14
  expect(subject).not_to be_nil
13
15
  end
14
-
16
+
15
17
  it 'has an empty list of files if none are given' do
16
18
  expect(subject.files).to eq []
17
19
  end
18
-
20
+
19
21
  it 'has a list of files given on initialization' do
20
22
  alt_subject = Chutney::ChutneyLint.new('a', 'b')
21
23
  expect(alt_subject.files).to eq %w[a b]
22
24
  end
23
-
25
+
24
26
  it 'initializes a results hash' do
25
27
  expect(subject.results).to eq({})
26
28
  end
27
-
29
+
28
30
  it 'sets the load path for I18n' do
29
31
  expect(I18n.load_path).not_to eq []
30
32
  end
@@ -34,25 +36,25 @@ describe Chutney::ChutneyLint do
34
36
  expect(subject.configuration).not_to be_nil
35
37
  expect(subject.configuration).to respond_to :[]
36
38
  end
37
-
39
+
38
40
  it 'allows the configuration to be set explicitly' do
39
41
  config = { 'BackgroundDoesMoreThanSetup' => { 'Enabled' => true } }
40
42
  subject.configuration = config
41
43
  expect(subject.configuration).to be config
42
44
  end
43
-
45
+
44
46
  it 'controls the available linters' do
45
47
  subject.configuration = {}
46
48
  expect(subject.linters).to be_empty
47
49
  end
48
-
50
+
49
51
  it 'enables linters to be activated' do
50
52
  config = { 'BackgroundDoesMoreThanSetup' => { 'Enabled' => true } }
51
53
  subject.configuration = config
52
54
  expect(subject.linters).to eq [Chutney::BackgroundDoesMoreThanSetup]
53
55
  end
54
56
  end
55
-
57
+
56
58
  context 'linting' do
57
59
  it 'aliases analyse and analyze' do
58
60
  expect(subject).to respond_to :analyse
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'simplecov'
2
4
  require 'coveralls'
3
5
  # Coveralls.wear!
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: chutney
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.1.0
4
+ version: 3.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Nigel Brookes-Thomas
@@ -11,7 +11,7 @@ authors:
11
11
  autorequire:
12
12
  bindir: exe
13
13
  cert_chain: []
14
- date: 2020-07-17 00:00:00.000000000 Z
14
+ date: 2020-09-23 00:00:00.000000000 Z
15
15
  dependencies:
16
16
  - !ruby/object:Gem::Dependency
17
17
  name: amatch
@@ -28,19 +28,19 @@ dependencies:
28
28
  - !ruby/object:Gem::Version
29
29
  version: 0.4.0
30
30
  - !ruby/object:Gem::Dependency
31
- name: gherkin
31
+ name: cuke_modeler
32
32
  requirement: !ruby/object:Gem::Requirement
33
33
  requirements:
34
34
  - - "~>"
35
35
  - !ruby/object:Gem::Version
36
- version: 5.1.0
36
+ version: '3.3'
37
37
  type: :runtime
38
38
  prerelease: false
39
39
  version_requirements: !ruby/object:Gem::Requirement
40
40
  requirements:
41
41
  - - "~>"
42
42
  - !ruby/object:Gem::Version
43
- version: 5.1.0
43
+ version: '3.3'
44
44
  - !ruby/object:Gem::Dependency
45
45
  name: i18n
46
46
  requirement: !ruby/object:Gem::Requirement
@@ -103,14 +103,14 @@ dependencies:
103
103
  requirements:
104
104
  - - "~>"
105
105
  - !ruby/object:Gem::Version
106
- version: '3.0'
106
+ version: '5.1'
107
107
  type: :development
108
108
  prerelease: false
109
109
  version_requirements: !ruby/object:Gem::Requirement
110
110
  requirements:
111
111
  - - "~>"
112
112
  - !ruby/object:Gem::Version
113
- version: '3.0'
113
+ version: '5.1'
114
114
  - !ruby/object:Gem::Dependency
115
115
  name: pry-byebug
116
116
  requirement: !ruby/object:Gem::Requirement
@@ -173,14 +173,14 @@ dependencies:
173
173
  requirements:
174
174
  - - "~>"
175
175
  - !ruby/object:Gem::Version
176
- version: 0.85.1
176
+ version: 0.90.0
177
177
  type: :development
178
178
  prerelease: false
179
179
  version_requirements: !ruby/object:Gem::Requirement
180
180
  requirements:
181
181
  - - "~>"
182
182
  - !ruby/object:Gem::Version
183
- version: 0.85.1
183
+ version: 0.90.0
184
184
  - !ruby/object:Gem::Dependency
185
185
  name: rspec
186
186
  requirement: !ruby/object:Gem::Requirement
@@ -195,8 +195,10 @@ dependencies:
195
195
  - - "~>"
196
196
  - !ruby/object:Gem::Version
197
197
  version: '3.8'
198
- description: A linter for your Cucumber features. It supports any spoken language
199
- Cucumber v3 supports.
198
+ description: A linter for your Cucumber features. Making sure you have nice, expressible
199
+ Gherkin is essential is making sure you have a readable test-base. Chutney is designed
200
+ to sniff out smells in your feature files. It supports any spoken language Cucumber
201
+ supports.
200
202
  email:
201
203
  - nigel@brookes-thomas.co.uk
202
204
  executables:
@@ -215,7 +217,8 @@ files:
215
217
  - README.md
216
218
  - Rakefile
217
219
  - chutney.gemspec
218
- - config/chutney.yml
220
+ - config/chutney_defaults.yml
221
+ - config/cucumber.yml
219
222
  - docs/.keep
220
223
  - docs/_config.yml
221
224
  - docs/credits.md
@@ -247,6 +250,7 @@ files:
247
250
  - lib/chutney/linter/background_does_more_than_setup.rb
248
251
  - lib/chutney/linter/background_requires_multiple_scenarios.rb
249
252
  - lib/chutney/linter/bad_scenario_name.rb
253
+ - lib/chutney/linter/empty_feature_file.rb
250
254
  - lib/chutney/linter/file_name_differs_feature_name.rb
251
255
  - lib/chutney/linter/givens_after_background.rb
252
256
  - lib/chutney/linter/invalid_file_name.rb
@@ -288,9 +292,9 @@ require_paths:
288
292
  - lib
289
293
  required_ruby_version: !ruby/object:Gem::Requirement
290
294
  requirements:
291
- - - ">="
295
+ - - "~>"
292
296
  - !ruby/object:Gem::Version
293
- version: '0'
297
+ version: '2.6'
294
298
  required_rubygems_version: !ruby/object:Gem::Requirement
295
299
  requirements:
296
300
  - - ">="
@@ -300,5 +304,5 @@ requirements: []
300
304
  rubygems_version: 3.1.2
301
305
  signing_key:
302
306
  specification_version: 4
303
- summary: A linter for English language Gherkin
307
+ summary: A linter for multi-lingual Gherkin
304
308
  test_files: []