chutney 0.5.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.circleci/config.yml +14 -0
- data/.gitignore +14 -0
- data/.rubocop.yml +55 -0
- data/Dockerfile +9 -0
- data/Gemfile +3 -0
- data/Guardfile +3 -0
- data/LICENSE +22 -0
- data/README.md +84 -0
- data/Rakefile +51 -0
- data/chutney.gemspec +54 -0
- data/config/default.yml +58 -0
- data/exe/chutney +35 -0
- data/lib/chutney/.DS_Store +0 -0
- data/lib/chutney/configuration.rb +32 -0
- data/lib/chutney/issue.rb +35 -0
- data/lib/chutney/linter/avoid_outline_for_single_example.rb +19 -0
- data/lib/chutney/linter/avoid_period.rb +19 -0
- data/lib/chutney/linter/avoid_scripting.rb +24 -0
- data/lib/chutney/linter/background_does_more_than_setup.rb +20 -0
- data/lib/chutney/linter/background_requires_multiple_scenarios.rb +18 -0
- data/lib/chutney/linter/bad_scenario_name.rb +21 -0
- data/lib/chutney/linter/be_declarative.rb +49 -0
- data/lib/chutney/linter/file_name_differs_feature_name.rb +27 -0
- data/lib/chutney/linter/invalid_file_name.rb +16 -0
- data/lib/chutney/linter/invalid_step_flow.rb +41 -0
- data/lib/chutney/linter/missing_example_name.rb +23 -0
- data/lib/chutney/linter/missing_feature_description.rb +17 -0
- data/lib/chutney/linter/missing_feature_name.rb +18 -0
- data/lib/chutney/linter/missing_scenario_name.rb +18 -0
- data/lib/chutney/linter/missing_test_action.rb +16 -0
- data/lib/chutney/linter/missing_verification.rb +16 -0
- data/lib/chutney/linter/required_tags_starts_with.rb +16 -0
- data/lib/chutney/linter/same_tag_for_all_scenarios.rb +73 -0
- data/lib/chutney/linter/tag_collector.rb +10 -0
- data/lib/chutney/linter/tag_constraint.rb +35 -0
- data/lib/chutney/linter/tag_used_multiple_times.rb +23 -0
- data/lib/chutney/linter/too_clumsy.rb +17 -0
- data/lib/chutney/linter/too_long_step.rb +17 -0
- data/lib/chutney/linter/too_many_different_tags.rb +45 -0
- data/lib/chutney/linter/too_many_steps.rb +15 -0
- data/lib/chutney/linter/too_many_tags.rb +19 -0
- data/lib/chutney/linter/unique_scenario_names.rb +22 -0
- data/lib/chutney/linter/unknown_variable.rb +47 -0
- data/lib/chutney/linter/unused_variable.rb +47 -0
- data/lib/chutney/linter/use_background.rb +82 -0
- data/lib/chutney/linter/use_outline.rb +53 -0
- data/lib/chutney/linter.rb +164 -0
- data/lib/chutney/version.rb +3 -0
- data/lib/chutney.rb +131 -0
- data/spec/chutney_spec.rb +68 -0
- data/spec/configuration_spec.rb +58 -0
- data/spec/required_tags_starts_with_spec.rb +74 -0
- data/spec/shared_contexts/file_exists.rb +12 -0
- data/spec/shared_contexts/gherkin_linter.rb +14 -0
- 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
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
data/Gemfile
ADDED
data/Guardfile
ADDED
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
|
data/config/default.yml
ADDED
@@ -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
|