chutney 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.
Files changed (56) hide show
  1. checksums.yaml +7 -0
  2. data/.circleci/config.yml +14 -0
  3. data/.gitignore +14 -0
  4. data/.rubocop.yml +55 -0
  5. data/Dockerfile +9 -0
  6. data/Gemfile +3 -0
  7. data/Guardfile +3 -0
  8. data/LICENSE +22 -0
  9. data/README.md +84 -0
  10. data/Rakefile +51 -0
  11. data/chutney.gemspec +54 -0
  12. data/config/default.yml +58 -0
  13. data/exe/chutney +35 -0
  14. data/lib/chutney/.DS_Store +0 -0
  15. data/lib/chutney/configuration.rb +32 -0
  16. data/lib/chutney/issue.rb +35 -0
  17. data/lib/chutney/linter/avoid_outline_for_single_example.rb +19 -0
  18. data/lib/chutney/linter/avoid_period.rb +19 -0
  19. data/lib/chutney/linter/avoid_scripting.rb +24 -0
  20. data/lib/chutney/linter/background_does_more_than_setup.rb +20 -0
  21. data/lib/chutney/linter/background_requires_multiple_scenarios.rb +18 -0
  22. data/lib/chutney/linter/bad_scenario_name.rb +21 -0
  23. data/lib/chutney/linter/be_declarative.rb +49 -0
  24. data/lib/chutney/linter/file_name_differs_feature_name.rb +27 -0
  25. data/lib/chutney/linter/invalid_file_name.rb +16 -0
  26. data/lib/chutney/linter/invalid_step_flow.rb +41 -0
  27. data/lib/chutney/linter/missing_example_name.rb +23 -0
  28. data/lib/chutney/linter/missing_feature_description.rb +17 -0
  29. data/lib/chutney/linter/missing_feature_name.rb +18 -0
  30. data/lib/chutney/linter/missing_scenario_name.rb +18 -0
  31. data/lib/chutney/linter/missing_test_action.rb +16 -0
  32. data/lib/chutney/linter/missing_verification.rb +16 -0
  33. data/lib/chutney/linter/required_tags_starts_with.rb +16 -0
  34. data/lib/chutney/linter/same_tag_for_all_scenarios.rb +73 -0
  35. data/lib/chutney/linter/tag_collector.rb +10 -0
  36. data/lib/chutney/linter/tag_constraint.rb +35 -0
  37. data/lib/chutney/linter/tag_used_multiple_times.rb +23 -0
  38. data/lib/chutney/linter/too_clumsy.rb +17 -0
  39. data/lib/chutney/linter/too_long_step.rb +17 -0
  40. data/lib/chutney/linter/too_many_different_tags.rb +45 -0
  41. data/lib/chutney/linter/too_many_steps.rb +15 -0
  42. data/lib/chutney/linter/too_many_tags.rb +19 -0
  43. data/lib/chutney/linter/unique_scenario_names.rb +22 -0
  44. data/lib/chutney/linter/unknown_variable.rb +47 -0
  45. data/lib/chutney/linter/unused_variable.rb +47 -0
  46. data/lib/chutney/linter/use_background.rb +82 -0
  47. data/lib/chutney/linter/use_outline.rb +53 -0
  48. data/lib/chutney/linter.rb +164 -0
  49. data/lib/chutney/version.rb +3 -0
  50. data/lib/chutney.rb +131 -0
  51. data/spec/chutney_spec.rb +68 -0
  52. data/spec/configuration_spec.rb +58 -0
  53. data/spec/required_tags_starts_with_spec.rb +74 -0
  54. data/spec/shared_contexts/file_exists.rb +12 -0
  55. data/spec/shared_contexts/gherkin_linter.rb +14 -0
  56. metadata +201 -0
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 3cd3fedd515ac329a7742839bf65e5ff798497fefc097e46163190b9ad2f7e75
4
+ data.tar.gz: 972f91728233ccde39ad8f2f403a791eedd9463498ac4729a87c98c9fff9ab94
5
+ SHA512:
6
+ metadata.gz: d030c44774a962c83e119c77ffad06e8329c04d543db465693a3b27ecc08a4100e215aefbc2b48c3c85e2aa4791bc411454f4d0bd792c15349430e80423e1695
7
+ data.tar.gz: d0700418789e7562d5fd2f6317abf8f849e6b1a60b491232e4188212dbaf22901f5bc6302ce20d8d0c79ebb2c5ef3582463768c419710c52f9d4aaa9bfb482ac
@@ -0,0 +1,14 @@
1
+ # Use the latest 2.1 version of CircleCI pipeline processing engine, see https://circleci.com/docs/2.0/configuration-reference/
2
+ version: 2.1
3
+
4
+
5
+ jobs:
6
+ build:
7
+ docker:
8
+ - image: circleci/ruby:2.6.3-stretch-node
9
+ steps:
10
+ - checkout
11
+ - run: bundle install
12
+ - run: bundle exec rake test
13
+
14
+
data/.gitignore ADDED
@@ -0,0 +1,14 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /_yardoc/
4
+ /coverage/
5
+ /doc/
6
+ /pkg/
7
+ /spec/reports/
8
+ /tmp/
9
+
10
+ Gemfile.lock
11
+ # rspec failure tracking
12
+ .rspec_status
13
+
14
+ .DS_Store
data/.rubocop.yml ADDED
@@ -0,0 +1,55 @@
1
+ # This configuration was generated by
2
+ # `rubocop --auto-gen-config`
3
+ # on 2016-08-11 02:50:03 +0200 using RuboCop version 0.42.0.
4
+ # The point is for the user to remove these configuration records
5
+ # one by one as the offenses are removed from the code base.
6
+ # Note that changes in the inspected code, or installation of new
7
+ # versions of RuboCop, may require this file to be generated again.
8
+
9
+ # Offense count: 1
10
+ Metrics/AbcSize:
11
+ Max: 16
12
+
13
+ # Offense count: 1
14
+ # Configuration parameters: CountComments.
15
+ Metrics/ClassLength:
16
+ Max: 123
17
+
18
+ # Offense count: 33
19
+ # Configuration parameters: AllowHeredoc, AllowURI, URISchemes.
20
+ # URISchemes: http, https
21
+ Metrics/LineLength:
22
+ Max: 116
23
+ Exclude:
24
+ - "**/*_spec.rb"
25
+ # Offense count: 1
26
+ # Configuration parameters: CountComments.
27
+ Metrics/MethodLength:
28
+ Max: 11
29
+
30
+ # Offense count: 1
31
+ # Cop supports --auto-correct.
32
+ # Configuration parameters: EnforcedStyle, SupportedStyles.
33
+ # SupportedStyles: predicate, comparison
34
+ Style/NumericPredicate:
35
+ Exclude:
36
+ - 'lib/chutney/linter/file_name_differs_feature_name.rb'
37
+
38
+ Metrics/ModuleLength:
39
+ Exclude:
40
+ - "**/*_spec.rb"
41
+
42
+ Metrics/BlockLength:
43
+ Exclude:
44
+ - "**/*_spec.rb"
45
+
46
+ Layout/IndentationWidth:
47
+ Exclude:
48
+ - "**/*_spec.rb"
49
+
50
+ Layout/IndentHeredoc:
51
+ Exclude:
52
+ - "**/*_spec.rb"
53
+
54
+ Layout/TrailingWhitespace:
55
+ Enabled: false
data/Dockerfile ADDED
@@ -0,0 +1,9 @@
1
+ FROM ruby
2
+ MAINTAINER think@hotmail.de
3
+
4
+ RUN gem install chutney --no-format-exec
5
+
6
+ ENV LC_ALL=C.UTF-8
7
+
8
+ ENTRYPOINT ["chutney"]
9
+ CMD ["--help"]
data/Gemfile ADDED
@@ -0,0 +1,3 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gemspec
data/Guardfile ADDED
@@ -0,0 +1,3 @@
1
+ guard 'rake', task: :default do
2
+ watch(%r{^src/.*$})
3
+ end
data/LICENSE ADDED
@@ -0,0 +1,22 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2015 Funkwerk AG
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
22
+
data/README.md ADDED
@@ -0,0 +1,84 @@
1
+ # Lint Gherkin Files
2
+
3
+ [![Build Status](https://travis-ci.org/funkwerk/gherkin_lint.svg)](https://travis-ci.org/funkwerk/gherkin_lint)
4
+ [![Build status](https://ci.appveyor.com/api/projects/status/31w2m0x1b9484jbi/branch/master?svg=true)](https://ci.appveyor.com/project/lindt/gherkin-lint/branch/master)
5
+ [![Code Climate](https://codeclimate.com/github/funkwerk/gherkin_lint/badges/gpa.svg)](https://codeclimate.com/github/funkwerk/gherkin_lint)
6
+ [![Docker Build](https://img.shields.io/docker/automated/gherkin/lint.svg)](https://hub.docker.com/r/gherkin/lint/)
7
+ [![Downloads](https://img.shields.io/gem/dt/gherkin_lint.svg)](https://rubygems.org/gems/gherkin_lint)
8
+ [![Latest Tag](https://img.shields.io/github/tag/funkwerk/gherkin_lint.svg)](https://rubygems.org/gems/gherkin_lint)
9
+
10
+ This tool lints gherkin files.
11
+
12
+ ## Usage
13
+
14
+ run `gherkin_lint` on a list of files
15
+
16
+ gherkin_lint -f '<wild_card_path>' #default is `features/**/*.feature`
17
+
18
+ With `--disable CHECK` or `--enable CHECK` it's possible to disable respectivly enable program wide checks except when a linter requires additional values to be set in order to be valid. Currently only RequiredTagStartsWith meets this criteria.
19
+
20
+ Checks could be disabled using tags within Feature Files. To do so, add @disableCHECK.
21
+ Detailed usage within the [disable_tags](https://github.com/funkwerk/gherkin_lint/blob/master/features/disable_tags.feature) feature.
22
+
23
+ ### Usage with Docker
24
+
25
+ Assuming there are feature files in the current directory. Then call.
26
+
27
+ `docker run -ti -v $(pwd):/src -w /src gherkin/lint *.feature`
28
+
29
+ This will mount the current directory within the Gherkin Lint Docker Container and then check all feature files.
30
+
31
+ ## Checks
32
+
33
+ - [avoid outline for single example](https://github.com/funkwerk/gherkin_lint/blob/master/features/avoid_outline_for_single_example.feature)
34
+ - [avoid period](https://github.com/funkwerk/gherkin_lint/blob/master/features/avoid_period.feature)
35
+ - [avoid scripting](https://github.com/funkwerk/gherkin_lint/blob/master/features/avoid_scripting.feature)
36
+ - [be declarative](https://github.com/funkwerk/gherkin_lint/blob/master/features/be_declarative.feature)
37
+ - [background does more than setup](https://github.com/funkwerk/gherkin_lint/blob/master/features/background_does_more_than_setup.feature)
38
+ - [background requires scenario](https://github.com/funkwerk/gherkin_lint/blob/master/features/background_requires_scenario.feature)
39
+ - [bad scenario name](https://github.com/funkwerk/gherkin_lint/blob/master/features/bad_scenario_name.feature)
40
+ - [file name differs feature name](https://github.com/funkwerk/gherkin_lint/blob/master/features/file_name_differs_feature_name.feature)
41
+ - [invalid file name](https://github.com/funkwerk/gherkin_lint/blob/master/features/invalid_file_name.feature)
42
+ - [invalid step flow](https://github.com/funkwerk/gherkin_lint/blob/master/features/invalid_step_flow.feature)
43
+ - [missing example name](https://github.com/funkwerk/gherkin_lint/blob/master/features/missing_example_name.feature)
44
+ - [missing feature description](https://github.com/funkwerk/gherkin_lint/blob/master/features/missing_feature_description.feature)
45
+ - [missing feature name](https://github.com/funkwerk/gherkin_lint/blob/master/features/missing_feature_name.feature)
46
+ - [missing scenario name](https://github.com/funkwerk/gherkin_lint/blob/master/features/missing_scenario_name.feature)
47
+ - [missing test action](https://github.com/funkwerk/gherkin_lint/blob/master/features/missing_test_action.feature)
48
+ - [missing verification](https://github.com/funkwerk/gherkin_lint/blob/master/features/missing_verification.feature)
49
+ - [required tag starts with](https://github.com/funkwerk/gherkin_lint/blob/master/features/required_tag_starts_with.feature) - disabled by default
50
+ - [same tag for all scenarios](https://github.com/funkwerk/gherkin_lint/blob/master/features/same_tag_for_all_scenarios.feature)
51
+ - [tag used multiple times](https://github.com/funkwerk/gherkin_lint/blob/master/features/tag_used_multiple_times.feature)
52
+ - [too clumsy](https://github.com/funkwerk/gherkin_lint/blob/master/features/too_clumsy.feature)
53
+ - [too long step](https://github.com/funkwerk/gherkin_lint/blob/master/features/too_long_step.feature)
54
+ - [too many different tags](https://github.com/funkwerk/gherkin_lint/blob/master/features/too_many_different_tags.feature)
55
+ - [too many steps](https://github.com/funkwerk/gherkin_lint/blob/master/features/too_many_steps.feature)
56
+ - [too many tags](https://github.com/funkwerk/gherkin_lint/blob/master/features/too_many_tags.feature)
57
+ - [unique scenario names](https://github.com/funkwerk/gherkin_lint/blob/master/features/unique_scenario_names.feature)
58
+ - [unknown variable](https://github.com/funkwerk/gherkin_lint/blob/master/features/unknown_variable.feature)
59
+ - [use background](https://github.com/funkwerk/gherkin_lint/blob/master/features/use_background.feature)
60
+ - [use outline](https://github.com/funkwerk/gherkin_lint/blob/master/features/use_outline.feature)
61
+
62
+ ## Errors and Warnings
63
+
64
+ There are errors and warnings.
65
+
66
+ ### Warnings
67
+
68
+ Warnings are for issues that do not influence the returncode. These issues are also for introducing new checks.
69
+ These new checks will stay some releases as warning and will be later declared as error, to give users the possibility to adapt their codebase.
70
+
71
+ ### Errors
72
+
73
+ If there is at least one error, the returncode will be set to ERROR (!= 0).
74
+
75
+ ## Installation
76
+
77
+ Install it with:
78
+
79
+ `sudo gem install gherkin_lint`
80
+
81
+ After that `gherkin_lint` executable is available.
82
+
83
+ ## Configuration
84
+ If you have a custom configuration you'd like to run on a regular basis instead of passing enable and disable flags through the CLI on every run, you can configure a ```.chutney.yml``` file that will be loaded on execution. The format and available linters are in [```config/default.yml```](config/default.yml)
data/Rakefile ADDED
@@ -0,0 +1,51 @@
1
+ require 'rake/testtask'
2
+
3
+ task default: :build
4
+
5
+ desc 'Builds the Gem.'
6
+ task build: :format
7
+ task build: :self_check
8
+ task build: :test do
9
+ sh 'gem build gherkin_lint.gemspec'
10
+ end
11
+
12
+ desc 'Publishes the Gem'
13
+ task :push do
14
+ sh 'gem push gherkin_lint-1.2.2.gem'
15
+ end
16
+
17
+ desc 'Checks ruby style'
18
+ task :rubocop do
19
+ begin
20
+ sh 'rubocop'
21
+ rescue RuntimeError => e
22
+ # Rubocop failing due to style violations is fine. Other errors should bubble up to our attention.
23
+ raise e unless e.message =~ /status \(1\).*rubocop/
24
+
25
+ puts 'Rubocop failed'
26
+ end
27
+ end
28
+
29
+ task test: :rubocop
30
+ task test: :language
31
+ task :test do
32
+ sh 'cucumber --tags "not @skip" --guess'
33
+ end
34
+
35
+ task :format do
36
+ options = []
37
+ options.push '--replace' if ENV['repair']
38
+ # TODO: sh "gherkin_format #{options.join ' '} features/*.feature"
39
+ end
40
+
41
+ task :language do
42
+ # TODO: sh 'gherkin_language features/*.feature'
43
+ end
44
+
45
+ task :self_check do
46
+ disabled_checks = %w[
47
+ UnknownVariable
48
+ BadScenarioName
49
+ ]
50
+ sh "ruby ./bin/gherkin_lint --disable #{disabled_checks.join ','} features/*.feature"
51
+ end
data/chutney.gemspec ADDED
@@ -0,0 +1,54 @@
1
+ # Disable rubocop checks for the .gemspec
2
+ # I'll take the output from 'bundle gem new' to be authoritative
3
+ # rubocop:disable all
4
+
5
+ lib = File.expand_path('../lib', __FILE__)
6
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
7
+ require 'chutney/version'
8
+
9
+ Gem::Specification.new do |spec|
10
+ spec.name = 'chutney'
11
+ spec.version = Chutney::VERSION
12
+ spec.authors = ['Nigel Brookes-Thomas', 'Stefan Rohe', 'Nishtha Argawal', 'John Gluck']
13
+ spec.email = ['nigel@brookes-thomas.co.uk']
14
+
15
+ spec.summary = 'A linter for English language Gherkin'
16
+ spec.description = 'A fork of gherkin_lint (https://github.com/funkwerk/gherkin_lint) ' \
17
+ 'which is no-longer being actively maintained'
18
+
19
+ spec.homepage = 'https://github.com/BillyRuffian/chutney'
20
+ spec.license = 'MIT'
21
+
22
+ # Prevent pushing this gem to RubyGems.org. To allow pushes either set the 'allowed_push_host'
23
+ # to allow pushing to a single host or delete this section to allow pushing to any host.
24
+ if spec.respond_to?(:metadata)
25
+ # spec.metadata['allowed_push_host'] = 'TODO: Set to 'http://mygemserver.com''
26
+
27
+ # spec.metadata['homepage_uri'] = spec.homepage
28
+ spec.metadata['source_code_uri'] = 'https://github.com/BillyRuffian/faker_maker'
29
+ # spec.metadata['changelog_uri'] = 'TODO: Put your gem's CHANGELOG.md URL here.'
30
+ else
31
+ raise 'RubyGems 2.0 or newer is required to protect against ' \
32
+ 'public gem pushes.'
33
+ end
34
+
35
+ # Specify which files should be added to the gem when it is released.
36
+ # The `git ls-files -z` loads the files in the RubyGem that have been added into git.
37
+ spec.files = Dir.chdir(File.expand_path('..', __FILE__)) do
38
+ `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|s|features)/}) }
39
+ end
40
+
41
+ spec.bindir = 'exe'
42
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
43
+ spec.require_paths = ['lib']
44
+
45
+ spec.add_runtime_dependency 'amatch', '~> 0.4.0'
46
+ spec.add_runtime_dependency 'engtagger', '~> 0.2'
47
+ spec.add_runtime_dependency 'cucumber', '~> 3.0'
48
+ spec.add_runtime_dependency 'multi_json', '~> 1.0'
49
+ spec.add_runtime_dependency 'term-ansicolor', '1.7.1'
50
+
51
+ spec.add_development_dependency 'aruba', '~> 0.14.0'
52
+ spec.add_development_dependency 'rubocop', '~> 0.68.0'
53
+
54
+ end
@@ -0,0 +1,58 @@
1
+ AvoidOutlineForSingleExample:
2
+ Enabled: true
3
+ AvoidPeriod:
4
+ Enabled: true
5
+ AvoidScripting:
6
+ Enabled: true
7
+ BackgroundDoesMoreThanSetup:
8
+ Enabled: true
9
+ BackgroundRequiresMultipleScenarios:
10
+ Enabled: true
11
+ BadScenarioName:
12
+ Enabled: true
13
+ BeDeclarative:
14
+ Enabled: true
15
+ FileNameDiffersFeatureName:
16
+ Enabled: true
17
+ MissingExampleName:
18
+ Enabled: true
19
+ MissingFeatureDescription:
20
+ Enabled: true
21
+ MissingFeatureName:
22
+ Enabled: true
23
+ MissingScenarioName:
24
+ Enabled: true
25
+ MissingTestAction:
26
+ Enabled: true
27
+ MissingVerification:
28
+ Enabled: true
29
+ InvalidFileName:
30
+ Enabled: true
31
+ InvalidStepFlow:
32
+ Enabled: true
33
+ RequiredTagsStartsWith:
34
+ Enabled: false
35
+ SameTagForAllScenarios:
36
+ Enabled: true
37
+ TagUsedMultipleTimes:
38
+ Enabled: true
39
+ TooClumsy:
40
+ Enabled: true
41
+ TooManyDifferentTags:
42
+ Enabled: true
43
+ TooManySteps:
44
+ Enabled: true
45
+ TooManyTags:
46
+ Enabled: true
47
+ TooLongStep:
48
+ Enabled: true
49
+ UniqueScenarioNames:
50
+ Enabled: true
51
+ UnknownVariable:
52
+ Enabled: true
53
+ UnusedVariable:
54
+ Enabled: true
55
+ UseBackground:
56
+ Enabled: true
57
+ UseOutline:
58
+ Enabled: true
data/exe/chutney ADDED
@@ -0,0 +1,35 @@
1
+ #!/usr/bin/env ruby
2
+ require 'chutney'
3
+ require 'optparse'
4
+
5
+ options = {}
6
+ OptionParser.new do |opts|
7
+ opts.banner = 'Usage: gherkin_language [files]'
8
+ opts.on('-v', '--[no-]verbose', 'Run verbosely') do |verbose|
9
+ options[:verbose] = verbose
10
+ end
11
+ opts.on('--enable [CHECKS]', 'Enabled checks. Separated by ","') do |checks|
12
+ options[:enable] = checks.split(',')
13
+ end
14
+ opts.on('--disable [CHECKS]', 'Disabled checks. Separated by ","') do |checks|
15
+ options[:disable] = checks.split(',')
16
+ end
17
+ opts.on('-f', '--filepath [file/s]', 'File path where features are located') do |file|
18
+ options[:files] = file
19
+ end
20
+ end.parse!
21
+
22
+ linter = Chutney::ChutneyLint.new
23
+ linter.disable options[:disable] if options.key? :disable
24
+ linter.enable options[:enable] if options.key? :enable
25
+ linter.set_linter
26
+
27
+ files = ARGV.map { |pattern| Dir.glob(pattern) }.flatten
28
+ files += Dir.glob(options[:files]) if options.key? :files
29
+ files = Dir.glob('features/**/*.feature') if ARGV.empty? && !options.key?(:files)
30
+
31
+ files.each do |file|
32
+ linter.analyze file
33
+ end
34
+
35
+ exit linter.report
Binary file
@@ -0,0 +1,32 @@
1
+ require 'yaml'
2
+ module Chutney
3
+ # gherkin_lint configuration object
4
+ class Configuration
5
+ attr_reader :config
6
+
7
+ def initialize(path)
8
+ @path = path
9
+ @config = load_configuration || ''
10
+ load_user_configuration
11
+ end
12
+
13
+ def configuration_path
14
+ @path
15
+ end
16
+
17
+ def load_configuration
18
+ YAML.load_file configuration_path || '' if File.exist? configuration_path
19
+ end
20
+
21
+ def load_user_configuration
22
+ config_file = Dir.glob(File.join(Dir.pwd, '**', '.chutney.yml')).first
23
+ merge_config(config_file) if !config_file.nil? && File.exist?(config_file)
24
+ end
25
+
26
+ private
27
+
28
+ def merge_config(config_file)
29
+ @config.merge!(YAML.load_file(config_file)) { |_k, old, new| old.merge!(new) } unless @config.empty?
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,35 @@
1
+ require 'term/ansicolor'
2
+
3
+ module Chutney
4
+ # entity value class for issues
5
+ class Issue
6
+ include Term::ANSIColor
7
+ attr_reader :name, :references, :description
8
+
9
+ def initialize(name, references, description = nil)
10
+ @name = name
11
+ @references = references
12
+ @description = description
13
+ end
14
+ end
15
+
16
+ # entity value class for errors
17
+ class Error < Issue
18
+ def render
19
+ result = red(@name)
20
+ result += " - #{@description}" unless @description.nil?
21
+ result += "\n " + green(@references.uniq * "\n ")
22
+ result
23
+ end
24
+ end
25
+
26
+ # entity value class for warnings
27
+ class Warning < Issue
28
+ def render
29
+ result = "#{yellow(@name)} (Warning)"
30
+ result += " - #{@description}" unless @description.nil?
31
+ result += "\n " + green(@references.uniq * "\n ")
32
+ result
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,19 @@
1
+ require 'chutney/linter'
2
+
3
+ module Chutney
4
+ # service class to lint for avoiding outline for single example
5
+ class AvoidOutlineForSingleExample < Linter
6
+ def lint
7
+ scenarios do |file, feature, scenario|
8
+ next unless scenario[:type] == :ScenarioOutline
9
+
10
+ next unless scenario.key? :examples
11
+ next if scenario[:examples].length > 1
12
+ next if scenario[:examples].first[:tableBody].length > 1
13
+
14
+ references = [reference(file, feature, scenario)]
15
+ add_error(references, 'You have a Scenarion Outline with a single example - rewrite to use a Scenario')
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,19 @@
1
+ require 'chutney/linter'
2
+
3
+ module Chutney
4
+ # service class to lint for avoiding periods
5
+ class AvoidPeriod < Linter
6
+ MESSAGE = 'Avoid using a period (full-stop) in steps so that it is easier to re-use them'.freeze
7
+
8
+ def lint
9
+ scenarios do |file, feature, scenario|
10
+ next unless scenario.key? :steps
11
+
12
+ scenario[:steps].each do |step|
13
+ references = [reference(file, feature, scenario, step)]
14
+ add_error(references, MESSAGE) if step[:text].strip.end_with? '.'
15
+ end
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,24 @@
1
+ require 'chutney/linter'
2
+
3
+ module Chutney
4
+ # service class to lint for avoid scripting
5
+ class AvoidScripting < Linter
6
+ MESSAGE = "You have multiple (%d) 'When' actions in your steps - you should only have one".freeze
7
+
8
+ def lint
9
+ filled_scenarios do |file, feature, scenario|
10
+ steps = filter_when_steps scenario[:steps]
11
+ next if steps.length <= 1
12
+
13
+ references = [reference(file, feature, scenario)]
14
+ add_error(references, MESSAGE % steps.length)
15
+ end
16
+ end
17
+
18
+ def filter_when_steps(steps)
19
+ steps = steps.drop_while { |step| step[:keyword] != 'When ' }
20
+ steps = steps.reverse.drop_while { |step| step[:keyword] != 'Then ' }.reverse
21
+ steps.reject { |step| step[:keyword] == 'Then ' }
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,20 @@
1
+ require 'chutney/linter'
2
+
3
+ module Chutney
4
+ # service class to lint for background that does more than setup
5
+ class BackgroundDoesMoreThanSetup < Linter
6
+ MESSAGE = 'A Feature\'s Background should just contain \'Given\' steps'.freeze
7
+
8
+ def lint
9
+ backgrounds do |file, feature, background|
10
+ next unless background.key? :steps
11
+
12
+ invalid_steps = background[:steps].select { |step| step[:keyword] == 'When ' || step[:keyword] == 'Then ' }
13
+ next if invalid_steps.empty?
14
+
15
+ references = [reference(file, feature, background, invalid_steps[0])]
16
+ add_error(references, MESSAGE)
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,18 @@
1
+ require 'chutney/linter'
2
+
3
+ module Chutney
4
+ # service class for check that there are multiple scenarios once a background is used
5
+ class BackgroundRequiresMultipleScenarios < Linter
6
+ MESSAGE = 'Avoid using Background steps for just one scenario'.freeze
7
+
8
+ def lint
9
+ backgrounds do |file, feature, background|
10
+ scenarios = feature[:children].reject { |element| element[:type] == :Background }
11
+ next if scenarios.length >= 2
12
+
13
+ references = [reference(file, feature, background)]
14
+ add_error(references, MESSAGE)
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,21 @@
1
+ require 'chutney/linter'
2
+
3
+ module Chutney
4
+ # service class to lint for bad scenario names
5
+ class BadScenarioName < Linter
6
+ MESSAGE = 'You should avoid using words like \'test\', \'check\' or \'verify\' ' \
7
+ 'when naming your scenarios to keep them understandable'.freeze
8
+
9
+ def lint
10
+ scenarios do |file, feature, scenario|
11
+ next if scenario[:name].empty?
12
+
13
+ references = [reference(file, feature, scenario)]
14
+ bad_words = %w[test verif check]
15
+ bad_words.each do |bad_word|
16
+ add_error(references, MESSAGE) if scenario[:name].downcase.include? bad_word
17
+ end
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,49 @@
1
+ require 'chutney/linter'
2
+ require 'engtagger'
3
+
4
+ module Chutney
5
+ # service class to lint for avoiding periods
6
+ class BeDeclarative < Linter
7
+ MESSAGE = 'This step does not contain a verb'.freeze
8
+
9
+ def initialize
10
+ super
11
+ end
12
+
13
+ def lint
14
+ filled_scenarios do |file, feature, scenario|
15
+ scenario[:steps].each do |step|
16
+ references = [reference(file, feature, scenario, step)]
17
+ add_warning(references, MESSAGE) unless verb? step
18
+ end
19
+ end
20
+ end
21
+
22
+ def verb?(step)
23
+ tagged = tagger.add_tags step[:text]
24
+ step_verbs = verbs tagged
25
+
26
+ !step_verbs.empty?
27
+ end
28
+
29
+ def verbs(tagged_text)
30
+ verbs =
31
+ %i[
32
+ get_infinitive_verbs
33
+ get_past_tense_verbs
34
+ get_gerund_verbs
35
+ get_passive_verbs
36
+ get_present_verbs
37
+ get_base_present_verbs
38
+ ]
39
+
40
+ verbs.map { |verb| tagger.send(verb, tagged_text).keys }.flatten
41
+ end
42
+
43
+ def tagger
44
+ @tagger = EngTagger.new unless instance_variable_defined? :@tagger
45
+
46
+ @tagger
47
+ end
48
+ end
49
+ end