chutney 0.5.0

Sign up to get free protection for your applications and to get access to all the features.
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