cuke_linter 0.12.0 → 1.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +41 -1
- data/README.md +12 -8
- data/cuke_linter.gemspec +25 -21
- data/exe/cuke_linter +3 -1
- data/lib/cuke_linter.rb +119 -176
- data/lib/cuke_linter/configuration.rb +45 -0
- data/lib/cuke_linter/default_linters.rb +32 -0
- data/lib/cuke_linter/formatters/pretty_formatter.rb +63 -35
- data/lib/cuke_linter/gherkin.rb +10 -0
- data/lib/cuke_linter/linter_registration.rb +32 -0
- data/lib/cuke_linter/linters/background_does_more_than_setup_linter.rb +17 -1
- data/lib/cuke_linter/linters/element_with_common_tags_linter.rb +23 -14
- data/lib/cuke_linter/linters/element_with_duplicate_tags_linter.rb +18 -13
- data/lib/cuke_linter/linters/element_with_too_many_tags_linter.rb +17 -11
- data/lib/cuke_linter/linters/feature_with_too_many_different_tags_linter.rb +1 -3
- data/lib/cuke_linter/linters/feature_without_description_linter.rb +1 -1
- data/lib/cuke_linter/linters/linter.rb +17 -13
- data/lib/cuke_linter/linters/step_with_too_many_characters_linter.rb +2 -2
- data/lib/cuke_linter/linters/test_should_use_background_linter.rb +56 -4
- data/lib/cuke_linter/linters/test_with_action_step_as_final_step_linter.rb +12 -1
- data/lib/cuke_linter/linters/test_with_bad_name_linter.rb +4 -4
- data/lib/cuke_linter/linters/test_with_no_action_step_linter.rb +12 -1
- data/lib/cuke_linter/linters/test_with_no_verification_step_linter.rb +12 -1
- data/lib/cuke_linter/linters/test_with_setup_step_after_action_step_linter.rb +18 -2
- data/lib/cuke_linter/linters/test_with_setup_step_after_verification_step_linter.rb +18 -2
- data/lib/cuke_linter/linters/test_with_setup_step_as_final_step_linter.rb +12 -1
- data/lib/cuke_linter/version.rb +1 -1
- data/testing/cucumber/features/linters/background_does_more_than_setup.feature +34 -0
- data/testing/cucumber/features/linters/test_with_action_as_final_step.feature +25 -3
- data/testing/cucumber/features/linters/test_with_no_action_step.feature +27 -1
- data/testing/cucumber/features/linters/test_with_no_verification_step.feature +28 -1
- data/testing/cucumber/features/linters/test_with_setup_step_after_action_step.feature +28 -1
- data/testing/cucumber/features/linters/test_with_setup_step_after_verification_step.feature +28 -1
- data/testing/cucumber/features/linters/test_with_setup_step_as_final_step.feature +25 -3
- metadata +88 -106
- data/.gitignore +0 -19
- data/.simplecov +0 -8
- data/.travis.yml +0 -23
- data/CONTRIBUTING.md +0 -26
- data/Gemfile +0 -6
- data/Rakefile +0 -63
- data/appveyor.yml +0 -43
- data/bin/console +0 -14
- data/bin/setup +0 -8
- data/environments/common_env.rb +0 -12
- data/environments/cucumber_env.rb +0 -22
- data/environments/rspec_env.rb +0 -50
- data/testing/cucumber/step_definitions/action_steps.rb +0 -84
- data/testing/cucumber/step_definitions/setup_steps.rb +0 -230
- data/testing/cucumber/step_definitions/verification_steps.rb +0 -94
- data/testing/file_helper.rb +0 -41
- data/testing/formatter_factory.rb +0 -15
- data/testing/gemfiles/cuke_modeler1.gemfile +0 -8
- data/testing/gemfiles/cuke_modeler2.gemfile +0 -8
- data/testing/linter_factory.rb +0 -60
- data/testing/model_factory.rb +0 -109
- data/testing/rspec/spec/integration/cli_integration_spec.rb +0 -556
- data/testing/rspec/spec/integration/configuration_spec.rb +0 -811
- data/testing/rspec/spec/integration/cuke_linter_integration_spec.rb +0 -243
- data/testing/rspec/spec/integration/formatters/formatter_integration_specs.rb +0 -5
- data/testing/rspec/spec/integration/formatters/pretty_formatter_integration_spec.rb +0 -8
- data/testing/rspec/spec/integration/linters/background_does_more_than_setup_linter_integration_spec.rb +0 -8
- data/testing/rspec/spec/integration/linters/element_with_common_tags_linter_integration_spec.rb +0 -8
- data/testing/rspec/spec/integration/linters/element_with_duplicate_tags_linter_integration_spec.rb +0 -8
- data/testing/rspec/spec/integration/linters/element_with_too_many_tags_linter_integration_spec.rb +0 -8
- data/testing/rspec/spec/integration/linters/example_without_name_linter_integration_spec.rb +0 -8
- data/testing/rspec/spec/integration/linters/feature_file_with_invalid_name_integration_spec.rb +0 -8
- data/testing/rspec/spec/integration/linters/feature_file_with_mismatched_name_integration_spec.rb +0 -8
- data/testing/rspec/spec/integration/linters/feature_with_too_many_different_tags_linter_integration_spec.rb +0 -8
- data/testing/rspec/spec/integration/linters/feature_without_description_linter_integration_spec.rb +0 -8
- data/testing/rspec/spec/integration/linters/feature_without_name_linter_integration_spec.rb +0 -8
- data/testing/rspec/spec/integration/linters/feature_without_scenarios_linter_integration_spec.rb +0 -8
- data/testing/rspec/spec/integration/linters/linter_integration_spec.rb +0 -8
- data/testing/rspec/spec/integration/linters/linter_integration_specs.rb +0 -7
- data/testing/rspec/spec/integration/linters/outline_with_single_example_row_linter_integration_spec.rb +0 -8
- data/testing/rspec/spec/integration/linters/single_test_background_linter_integration_spec.rb +0 -8
- data/testing/rspec/spec/integration/linters/step_with_end_period_linter_integration_spec.rb +0 -8
- data/testing/rspec/spec/integration/linters/step_with_too_many_characters_linter_integration_spec.rb +0 -8
- data/testing/rspec/spec/integration/linters/test_should_use_background_linter_integration_spec.rb +0 -8
- data/testing/rspec/spec/integration/linters/test_with_action_step_as_final_step_linter_integration_spec.rb +0 -8
- data/testing/rspec/spec/integration/linters/test_with_bad_name_integration_spec.rb +0 -8
- data/testing/rspec/spec/integration/linters/test_with_no_action_step_integration_spec.rb +0 -8
- data/testing/rspec/spec/integration/linters/test_with_no_name_integration_spec.rb +0 -8
- data/testing/rspec/spec/integration/linters/test_with_no_verification_step_integration_spec.rb +0 -8
- data/testing/rspec/spec/integration/linters/test_with_setup_step_after_action_step_linter_integration_spec.rb +0 -8
- data/testing/rspec/spec/integration/linters/test_with_setup_step_after_verification_step_linter_integration_spec.rb +0 -8
- data/testing/rspec/spec/integration/linters/test_with_setup_step_as_final_step_linter_integration_spec.rb +0 -8
- data/testing/rspec/spec/integration/linters/test_with_too_many_steps_linter_integration_spec.rb +0 -8
- data/testing/rspec/spec/unit/cuke_linter_unit_spec.rb +0 -102
- data/testing/rspec/spec/unit/formatters/formatter_unit_specs.rb +0 -11
- data/testing/rspec/spec/unit/formatters/pretty_formatter_unit_spec.rb +0 -115
- data/testing/rspec/spec/unit/linters/background_does_more_than_setup_linter_unit_spec.rb +0 -77
- data/testing/rspec/spec/unit/linters/configurable_linter_unit_specs.rb +0 -11
- data/testing/rspec/spec/unit/linters/element_with_common_tags_linter_unit_spec.rb +0 -248
- data/testing/rspec/spec/unit/linters/element_with_duplicate_tags_linter_unit_spec.rb +0 -203
- data/testing/rspec/spec/unit/linters/element_with_too_many_tags_linter_unit_spec.rb +0 -296
- data/testing/rspec/spec/unit/linters/example_without_name_linter_unit_spec.rb +0 -81
- data/testing/rspec/spec/unit/linters/feature_file_with_invalid_name_linter_unit_spec.rb +0 -106
- data/testing/rspec/spec/unit/linters/feature_file_with_mismatched_name_linter_unit_spec.rb +0 -124
- data/testing/rspec/spec/unit/linters/feature_with_too_many_different_tags_linter_unit_spec.rb +0 -293
- data/testing/rspec/spec/unit/linters/feature_without_description_linter_unit_spec.rb +0 -80
- data/testing/rspec/spec/unit/linters/feature_without_name_linter_unit_spec.rb +0 -84
- data/testing/rspec/spec/unit/linters/feature_without_scenarios_linter_unit_spec.rb +0 -102
- data/testing/rspec/spec/unit/linters/linter_unit_spec.rb +0 -197
- data/testing/rspec/spec/unit/linters/linter_unit_specs.rb +0 -57
- data/testing/rspec/spec/unit/linters/outline_with_single_example_row_linter_unit_spec.rb +0 -184
- data/testing/rspec/spec/unit/linters/single_test_background_linter_unit_spec.rb +0 -89
- data/testing/rspec/spec/unit/linters/step_with_end_period_linter_unit_spec.rb +0 -54
- data/testing/rspec/spec/unit/linters/step_with_too_many_characters_linter_unit_spec.rb +0 -155
- data/testing/rspec/spec/unit/linters/test_should_use_background_linter_unit_spec.rb +0 -226
- data/testing/rspec/spec/unit/linters/test_with_action_step_as_final_step_linter_unit_spec.rb +0 -98
- data/testing/rspec/spec/unit/linters/test_with_bad_name_linter_unit_spec.rb +0 -81
- data/testing/rspec/spec/unit/linters/test_with_no_action_step_linter_unit_spec.rb +0 -176
- data/testing/rspec/spec/unit/linters/test_with_no_name_linter_unit_spec.rb +0 -88
- data/testing/rspec/spec/unit/linters/test_with_no_verification_step_linter_unit_spec.rb +0 -179
- data/testing/rspec/spec/unit/linters/test_with_setup_step_after_action_step_linter_unit_spec.rb +0 -124
- data/testing/rspec/spec/unit/linters/test_with_setup_step_after_verification_step_linter_unit_spec.rb +0 -125
- data/testing/rspec/spec/unit/linters/test_with_setup_step_as_final_step_linter_unit_spec.rb +0 -98
- data/testing/rspec/spec/unit/linters/test_with_too_many_steps_linter_unit_spec.rb +0 -192
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: b911b1679a6fb00926c3b64558813e575c745da01f3ba6e95a8b51fe59412724
|
4
|
+
data.tar.gz: 1aa6dbd5a0d469f2870495c8f02ed2650633aba21d7098463a61797681e43ec1
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 4761dd56728c44a2537bc283794a24a8d071bf643609f7a82f0fd033c73f733e5aba11978ea7eedbd42c353bb22b8cea962412510c4d0e91aa806a137bdc2b0e
|
7
|
+
data.tar.gz: 2546da3f22c1b3e33d4f735ed6cf02ceda2e9f54aab37fc051833075193718ec13fe941a7b313721d8e059523abb1b642fcf00c8c6a8e66bf6e9df9c92eeafcc
|
data/CHANGELOG.md
CHANGED
@@ -8,6 +8,41 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
8
8
|
|
9
9
|
Nothing yet...
|
10
10
|
|
11
|
+
## [1.1.0] - 2020-06-14
|
12
|
+
|
13
|
+
### Added
|
14
|
+
- Now compatible with CukeModeler 3.x
|
15
|
+
|
16
|
+
## [1.0.1] - 2020-05-06
|
17
|
+
|
18
|
+
### Fixed
|
19
|
+
- Replaced some code that was not valid with earlier versions of Ruby 2.x, with which this gem is specified as being compatible.
|
20
|
+
|
21
|
+
|
22
|
+
## [1.0.0] - 2020-03-09
|
23
|
+
|
24
|
+
### Changed
|
25
|
+
- No longer including every file in the Git repository as part of the gem. Only the files needed for using the linter (and the informative ones like the README) will be packaged into the released gem.
|
26
|
+
|
27
|
+
|
28
|
+
## [0.13.0] - 2020-03-01
|
29
|
+
|
30
|
+
### Added
|
31
|
+
- Added the ability to configure relevant keywords for linters whose behavior is impacted by the dialect in which feature files are written.
|
32
|
+
- BackgroundDoesMoreThanSetupLinter
|
33
|
+
- TestWithActionStepAsFinalStepLinter
|
34
|
+
- TestWithNoActionStepLinter
|
35
|
+
- TestWithNoVerificationStepLinter
|
36
|
+
- TestWithSetupStepAfterActionStepLinter
|
37
|
+
- TestWithSetupStepAfterVerificationStepLinter
|
38
|
+
- TestWithSetupStepAsFinalStepLinter
|
39
|
+
|
40
|
+
|
41
|
+
## [0.12.1] - 2020-02-15
|
42
|
+
|
43
|
+
### Fixed
|
44
|
+
- `TestShouldUseBackgroundLinter` no longer suggests moving steps to the background if they have an outline parameter.
|
45
|
+
|
11
46
|
## [0.12.0] - 2020-02-13
|
12
47
|
|
13
48
|
### Added
|
@@ -129,7 +164,12 @@ Nothing yet...
|
|
129
164
|
- Custom linters, formatters, and command line usability
|
130
165
|
|
131
166
|
|
132
|
-
[Unreleased]: https://github.com/enkessler/cuke_linter/compare/
|
167
|
+
[Unreleased]: https://github.com/enkessler/cuke_linter/compare/v1.1.0...HEAD
|
168
|
+
[1.1.0]: https://github.com/enkessler/cuke_linter/compare/v1.0.1...v1.1.0
|
169
|
+
[1.0.1]: https://github.com/enkessler/cuke_linter/compare/v1.0.0...v1.0.1
|
170
|
+
[1.0.0]: https://github.com/enkessler/cuke_linter/compare/v0.13.0...v1.0.0
|
171
|
+
[0.13.0]: https://github.com/enkessler/cuke_linter/compare/v0.12.1...v0.13.0
|
172
|
+
[0.12.1]: https://github.com/enkessler/cuke_linter/compare/v0.12.0...v0.12.1
|
133
173
|
[0.12.0]: https://github.com/enkessler/cuke_linter/compare/v0.11.1...v0.12.0
|
134
174
|
[0.11.1]: https://github.com/enkessler/cuke_linter/compare/v0.11.0...v0.11.1
|
135
175
|
[0.11.0]: https://github.com/enkessler/cuke_linter/compare/v0.10.0...v0.11.0
|
data/README.md
CHANGED
@@ -8,11 +8,11 @@ User stuff:
|
|
8
8
|
[![Yard Docs](http://img.shields.io/badge/Documentation-API-blue.svg)](https://www.rubydoc.info/gems/cuke_linter)
|
9
9
|
|
10
10
|
Developer stuff:
|
11
|
-
[![Build Status](https://travis-ci.org/enkessler/cuke_linter.svg?branch=
|
12
|
-
[![Build Status](https://ci.appveyor.com/api/projects/status/g5o70u747x073evy/branch/
|
13
|
-
[![Coverage Status](https://coveralls.io/repos/github/enkessler/cuke_linter/badge.svg?branch=
|
11
|
+
[![Build Status](https://travis-ci.org/enkessler/cuke_linter.svg?branch=master)](https://travis-ci.org/enkessler/cuke_linter)
|
12
|
+
[![Build Status](https://ci.appveyor.com/api/projects/status/g5o70u747x073evy/branch/master?svg=true)](https://ci.appveyor.com/project/enkessler/cuke-linter/branch/master)
|
13
|
+
[![Coverage Status](https://coveralls.io/repos/github/enkessler/cuke_linter/badge.svg?branch=master)](https://coveralls.io/github/enkessler/cuke_linter?branch=master)
|
14
14
|
[![Maintainability](https://api.codeclimate.com/v1/badges/d1b86760e59a457c8e73/maintainability)](https://codeclimate.com/github/enkessler/cuke_linter/maintainability)
|
15
|
-
[![Inline docs](http://inch-ci.org/github/enkessler/cuke_linter.svg?branch=
|
15
|
+
[![Inline docs](http://inch-ci.org/github/enkessler/cuke_linter.svg?branch=master)](https://inch-ci.org/github/enkessler/cuke_linter?branch=master)
|
16
16
|
|
17
17
|
---
|
18
18
|
|
@@ -104,7 +104,8 @@ class MyCustomLinter
|
|
104
104
|
return nil unless model.is_a?(CukeModeler::Scenario)
|
105
105
|
|
106
106
|
if model.name.empty?
|
107
|
-
{ problem: 'Scenario has no name',
|
107
|
+
{ problem: 'Scenario has no name',
|
108
|
+
location: "#{model.get_ancestor(:feature_file).path}:#{model.source_line}" }
|
108
109
|
else
|
109
110
|
nil
|
110
111
|
end
|
@@ -134,13 +135,16 @@ output_path = "#{__dir__}/my_report.txt"
|
|
134
135
|
model_tree_root = CukeModeler::Directory.new(Dir.pwd)
|
135
136
|
additional_file_path = 'path/to/some.feature'
|
136
137
|
|
137
|
-
# Providing the formatter twice so that
|
138
|
-
CukeLinter.lint(linters: [linter],
|
138
|
+
# Providing the formatter twice so that output also is printed to the console
|
139
|
+
CukeLinter.lint(linters: [linter],
|
140
|
+
formatters: [[formatter], [formatter, output_path]],
|
141
|
+
model_trees: [model_tree_root],
|
142
|
+
file_paths: [additional_file_path])
|
139
143
|
```
|
140
144
|
|
141
145
|
### Configuration
|
142
146
|
|
143
|
-
Rather than using the default linters or providing a custom set of of modified linters every time linting occurs, which linters to use and any linter specific modifications can be configured in a more static manner via a configuration file or setting the configuration directly in code. See [documentation](#documentation) for specifics.
|
147
|
+
Rather than using the default linters or providing a custom set of of modified linters every time linting occurs, which linters to use and any linter specific modifications (such as choosing a non-default dialect) can be configured in a more static manner via a configuration file or setting the configuration directly in code. See [documentation](#documentation) for specifics.
|
144
148
|
|
145
149
|
|
146
150
|
### <a id="documentation"></a>Everything Else
|
data/cuke_linter.gemspec
CHANGED
@@ -1,40 +1,44 @@
|
|
1
|
-
|
2
|
-
lib = File.expand_path("../lib", __FILE__)
|
1
|
+
lib = File.expand_path('lib', __dir__)
|
3
2
|
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
-
require
|
3
|
+
require 'cuke_linter/version'
|
5
4
|
|
6
5
|
Gem::Specification.new do |spec|
|
7
|
-
spec.name =
|
6
|
+
spec.name = 'cuke_linter'
|
8
7
|
spec.version = CukeLinter::VERSION
|
9
|
-
spec.authors = [
|
10
|
-
spec.email = [
|
8
|
+
spec.authors = ['Eric Kessler']
|
9
|
+
spec.email = ['morrow748@gmail.com']
|
11
10
|
|
12
|
-
spec.summary =
|
11
|
+
spec.summary = 'Lints feature files used by Cucumber and other similar frameworks.'
|
13
12
|
spec.homepage = 'https://github.com/enkessler/cuke_linter'
|
14
|
-
spec.license =
|
13
|
+
spec.license = 'MIT'
|
15
14
|
|
16
15
|
|
17
|
-
# TODO: don't just include everything in the gem
|
18
16
|
# Specify which files should be added to the gem when it is released.
|
19
17
|
# The `git ls-files -z` loads the files in the RubyGem that have been added into git.
|
20
|
-
spec.files = Dir.chdir(File.expand_path('
|
21
|
-
`git ls-files -z`.split("\x0")
|
18
|
+
spec.files = Dir.chdir(File.expand_path('', __dir__)) do
|
19
|
+
source_controlled_files = `git ls-files -z`.split("\x0")
|
20
|
+
source_controlled_files.keep_if { |file| file =~ %r{^(lib|exe|testing/cucumber/features)} }
|
21
|
+
source_controlled_files + ['README.md', 'LICENSE.txt', 'CHANGELOG.md', 'cuke_linter.gemspec']
|
22
22
|
end
|
23
|
-
spec.bindir =
|
23
|
+
spec.bindir = 'exe'
|
24
24
|
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
25
|
-
spec.require_paths = [
|
25
|
+
spec.require_paths = ['lib']
|
26
26
|
|
27
27
|
spec.required_ruby_version = '~> 2.0'
|
28
28
|
|
29
|
-
spec.add_runtime_dependency 'cuke_modeler', '>= 1.5', '<
|
29
|
+
spec.add_runtime_dependency 'cuke_modeler', '>= 1.5', '< 4.0'
|
30
30
|
|
31
|
-
spec.add_development_dependency
|
32
|
-
spec.add_development_dependency
|
33
|
-
spec.add_development_dependency "racatt", "~> 1.0"
|
34
|
-
spec.add_development_dependency "rake", "~> 12.0"
|
35
|
-
spec.add_development_dependency "require_all", "~> 2.0"
|
36
|
-
spec.add_development_dependency "rspec", "~> 3.0"
|
37
|
-
spec.add_development_dependency 'simplecov', '< 1.0.0'
|
31
|
+
spec.add_development_dependency 'bundler', '< 3.0'
|
32
|
+
spec.add_development_dependency 'childprocess', '~> 3.0'
|
38
33
|
spec.add_development_dependency 'coveralls', '< 1.0.0'
|
34
|
+
spec.add_development_dependency 'cucumber', '< 5.0'
|
35
|
+
spec.add_development_dependency 'cuke_slicer', '>= 2.0.2', '< 3.0'
|
36
|
+
spec.add_development_dependency 'ffi', '~> 1.0'
|
37
|
+
spec.add_development_dependency 'parallel', '~> 1.0'
|
39
38
|
spec.add_development_dependency 'rainbow', '< 4.0.0'
|
39
|
+
spec.add_development_dependency 'rake', '~> 12.0'
|
40
|
+
spec.add_development_dependency 'require_all', '~> 2.0'
|
41
|
+
spec.add_development_dependency 'rspec', '~> 3.0'
|
42
|
+
spec.add_development_dependency 'rubocop', '< 1.0.0'
|
43
|
+
spec.add_development_dependency 'simplecov', '< 1.0.0'
|
40
44
|
end
|
data/exe/cuke_linter
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
2
|
|
3
|
-
require
|
3
|
+
require 'cuke_linter'
|
4
4
|
require 'optparse'
|
5
5
|
|
6
6
|
params = {}
|
@@ -9,6 +9,7 @@ params[:formatters] = []
|
|
9
9
|
params[:outs] = []
|
10
10
|
params[:requires] = []
|
11
11
|
|
12
|
+
# rubocop:disable Metrics/BlockLength
|
12
13
|
parser = OptionParser.new do |options|
|
13
14
|
|
14
15
|
options.set_summary_width(30)
|
@@ -68,6 +69,7 @@ parser = OptionParser.new do |options|
|
|
68
69
|
end
|
69
70
|
|
70
71
|
end
|
72
|
+
# rubocop:enable Metrics/BlockLength
|
71
73
|
|
72
74
|
begin
|
73
75
|
parser.parse!
|
data/lib/cuke_linter.rb
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
require 'yaml'
|
2
2
|
require 'cuke_modeler'
|
3
3
|
|
4
|
-
require
|
4
|
+
require 'cuke_linter/version'
|
5
5
|
require 'cuke_linter/formatters/pretty_formatter'
|
6
6
|
require 'cuke_linter/linters/linter'
|
7
7
|
require 'cuke_linter/linters/background_does_more_than_setup_linter'
|
@@ -29,227 +29,170 @@ require 'cuke_linter/linters/test_with_setup_step_after_action_step_linter'
|
|
29
29
|
require 'cuke_linter/linters/test_with_setup_step_after_verification_step_linter'
|
30
30
|
require 'cuke_linter/linters/test_with_setup_step_as_final_step_linter'
|
31
31
|
require 'cuke_linter/linters/test_with_too_many_steps_linter'
|
32
|
+
require 'cuke_linter/configuration'
|
33
|
+
require 'cuke_linter/default_linters'
|
34
|
+
require 'cuke_linter/gherkin'
|
35
|
+
require 'cuke_linter/linter_registration'
|
32
36
|
|
33
37
|
|
34
38
|
# The top level namespace used by this gem
|
35
|
-
|
36
39
|
module CukeLinter
|
37
40
|
|
38
|
-
|
39
|
-
|
40
|
-
'ElementWithDuplicateTagsLinter' => ElementWithDuplicateTagsLinter.new,
|
41
|
-
'ElementWithTooManyTagsLinter' => ElementWithTooManyTagsLinter.new,
|
42
|
-
'ExampleWithoutNameLinter' => ExampleWithoutNameLinter.new,
|
43
|
-
'FeatureFileWithInvalidNameLinter' => FeatureFileWithInvalidNameLinter.new,
|
44
|
-
'FeatureFileWithMismatchedNameLinter' => FeatureFileWithMismatchedNameLinter.new,
|
45
|
-
'FeatureWithTooManyDifferentTagsLinter' => FeatureWithTooManyDifferentTagsLinter.new,
|
46
|
-
'FeatureWithoutDescriptionLinter' => FeatureWithoutDescriptionLinter.new,
|
47
|
-
'FeatureWithoutNameLinter' => FeatureWithoutNameLinter.new,
|
48
|
-
'FeatureWithoutScenariosLinter' => FeatureWithoutScenariosLinter.new,
|
49
|
-
'OutlineWithSingleExampleRowLinter' => OutlineWithSingleExampleRowLinter.new,
|
50
|
-
'SingleTestBackgroundLinter' => SingleTestBackgroundLinter.new,
|
51
|
-
'StepWithEndPeriodLinter' => StepWithEndPeriodLinter.new,
|
52
|
-
'StepWithTooManyCharactersLinter' => StepWithTooManyCharactersLinter.new,
|
53
|
-
'TestShouldUseBackgroundLinter' => TestShouldUseBackgroundLinter.new,
|
54
|
-
'TestWithActionStepAsFinalStepLinter' => TestWithActionStepAsFinalStepLinter.new,
|
55
|
-
'TestWithBadNameLinter' => TestWithBadNameLinter.new,
|
56
|
-
'TestWithNoActionStepLinter' => TestWithNoActionStepLinter.new,
|
57
|
-
'TestWithNoNameLinter' => TestWithNoNameLinter.new,
|
58
|
-
'TestWithNoVerificationStepLinter' => TestWithNoVerificationStepLinter.new,
|
59
|
-
'TestWithSetupStepAfterActionStepLinter' => TestWithSetupStepAfterActionStepLinter.new,
|
60
|
-
'TestWithSetupStepAfterVerificationStepLinter' => TestWithSetupStepAfterVerificationStepLinter.new,
|
61
|
-
'TestWithSetupStepAsFinalStepLinter' => TestWithSetupStepAsFinalStepLinter.new,
|
62
|
-
'TestWithTooManyStepsLinter' => TestWithTooManyStepsLinter.new }
|
63
|
-
|
64
|
-
|
65
|
-
# Configures linters based on the given options
|
66
|
-
def self.load_configuration(config_file_path: nil, config: nil)
|
67
|
-
# TODO: define what happens if both a configuration file and a configuration are provided. Merge them or have direct config take precedence? Both?
|
68
|
-
|
69
|
-
unless config || config_file_path
|
70
|
-
config_file_path = "#{Dir.pwd}/.cuke_linter"
|
71
|
-
raise 'No configuration or configuration file given and no .cuke_linter file found' unless File.exist?(config_file_path)
|
72
|
-
end
|
73
|
-
|
74
|
-
config = config || YAML.load_file(config_file_path)
|
41
|
+
extend CukeLinter::Configuration
|
42
|
+
extend CukeLinter::LinterRegistration
|
75
43
|
|
76
|
-
|
77
|
-
to_delete = []
|
44
|
+
class << self
|
78
45
|
|
79
|
-
|
80
|
-
|
81
|
-
|
46
|
+
# Lints the given model trees and file paths using the given linting objects and formatting
|
47
|
+
# the results with the given formatters and their respective output locations
|
48
|
+
def lint(file_paths: [], model_trees: [], linters: registered_linters.values, formatters: [[CukeLinter::PrettyFormatter.new]]) # rubocop:disable Metrics/LineLength
|
49
|
+
# TODO: Test this?
|
50
|
+
# Because directive memoization is based on a model's `#object_id` and Ruby reuses object IDs over the
|
51
|
+
# life of a program as objects are garbage collected, it is not safe to remember the IDs forever. However,
|
52
|
+
# models shouldn't get GC'd in the middle of the linting process and so the start of the linting process is
|
53
|
+
# a good time to reset things
|
54
|
+
@directives_for_feature_file = {}
|
82
55
|
|
83
|
-
|
56
|
+
model_trees = [CukeModeler::Directory.new(Dir.pwd)] if model_trees.empty? && file_paths.empty?
|
57
|
+
file_path_models = collect_file_path_models(file_paths)
|
58
|
+
model_sets = model_trees + file_path_models
|
84
59
|
|
85
|
-
|
86
|
-
|
60
|
+
linting_data = lint_models(model_sets, linters)
|
61
|
+
format_data(formatters, linting_data)
|
87
62
|
|
88
|
-
|
63
|
+
linting_data
|
89
64
|
end
|
90
65
|
|
91
|
-
to_delete.each { |linter_name| unregister_linter(linter_name) }
|
92
|
-
end
|
93
|
-
|
94
|
-
# Returns the registered linters to their default state
|
95
|
-
def self.reset_linters
|
96
|
-
@registered_linters = nil
|
97
|
-
end
|
98
|
-
|
99
|
-
# Registers for linting use the given linter object, tracked by the given name
|
100
|
-
def self.register_linter(linter:, name:)
|
101
|
-
self.registered_linters[name] = linter
|
102
|
-
end
|
103
|
-
|
104
|
-
# Unregisters the linter object tracked by the given name so that it is not used for linting
|
105
|
-
def self.unregister_linter(name)
|
106
|
-
self.registered_linters.delete(name)
|
107
|
-
end
|
108
66
|
|
109
|
-
|
110
|
-
def self.registered_linters
|
111
|
-
@registered_linters ||= Marshal.load(Marshal.dump(@original_linters))
|
112
|
-
end
|
67
|
+
private
|
113
68
|
|
114
|
-
# Unregisters all currently registered linting objects
|
115
|
-
def self.clear_registered_linters
|
116
|
-
self.registered_linters.clear
|
117
|
-
end
|
118
69
|
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
# Because directive memoization is based on a model's `#object_id` and Ruby reuses object IDs over the
|
124
|
-
# life of a program as objects are garbage collected, it is not safe to remember the IDs forever. However,
|
125
|
-
# models shouldn't get GC'd in the middle of the linting process and so the start of the linting process is
|
126
|
-
# a good time to reset things
|
127
|
-
@directives_for_feature_file = {}
|
128
|
-
|
129
|
-
model_trees = [CukeModeler::Directory.new(Dir.pwd)] if model_trees.empty? && file_paths.empty?
|
130
|
-
file_path_models = file_paths.collect do |file_path|
|
131
|
-
# TODO: raise exception unless path exists
|
132
|
-
case
|
133
|
-
when File.directory?(file_path)
|
70
|
+
def collect_file_path_models(file_paths)
|
71
|
+
file_paths.collect do |file_path|
|
72
|
+
# TODO: raise exception unless path exists?
|
73
|
+
if File.directory?(file_path)
|
134
74
|
CukeModeler::Directory.new(file_path)
|
135
|
-
|
75
|
+
elsif File.file?(file_path) && File.extname(file_path) == '.feature'
|
136
76
|
CukeModeler::FeatureFile.new(file_path)
|
137
|
-
else
|
138
|
-
# Non-feature files are not modeled
|
139
|
-
end
|
140
|
-
end.compact # Compacting in order to get rid of any `nil` values left over from non-feature files
|
141
|
-
|
142
|
-
linting_data = []
|
143
|
-
model_sets = model_trees + file_path_models
|
144
|
-
|
145
|
-
model_sets.each do |model_tree|
|
146
|
-
model_tree.each_model do |model|
|
147
|
-
applicable_linters = relevant_linters_for_model(linters, model)
|
148
|
-
applicable_linters.each do |linter|
|
149
|
-
# TODO: have linters lint only certain types of models
|
150
|
-
# linting_data.concat(linter.lint(model)) if relevant_model?(linter, model)
|
151
|
-
|
152
|
-
result = linter.lint(model)
|
153
|
-
|
154
|
-
if result
|
155
|
-
result[:linter] = linter.name
|
156
|
-
linting_data << result
|
157
|
-
end
|
158
77
|
end
|
159
|
-
end
|
78
|
+
end.compact # Compacting in order to get rid of any `nil` values left over from non-feature files
|
160
79
|
end
|
161
80
|
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
81
|
+
def lint_models(model_sets, linters)
|
82
|
+
[].tap do |linting_data|
|
83
|
+
model_sets.each do |model_tree|
|
84
|
+
model_tree.each_model do |model|
|
85
|
+
applicable_linters = relevant_linters_for_model(linters, model)
|
86
|
+
applicable_linters.each do |linter|
|
87
|
+
# TODO: have linters lint only certain types of models?
|
88
|
+
# linting_data.concat(linter.lint(model)) if relevant_model?(linter, model)
|
89
|
+
|
90
|
+
result = linter.lint(model)
|
91
|
+
|
92
|
+
if result
|
93
|
+
result[:linter] = linter.name
|
94
|
+
linting_data << result
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|
172
99
|
end
|
173
100
|
end
|
174
101
|
|
175
|
-
|
176
|
-
|
177
|
-
end
|
102
|
+
def relevant_linters_for_model(base_linters, model)
|
103
|
+
feature_file_model = model.get_ancestor(:feature_file)
|
178
104
|
|
105
|
+
# Linter directives are not applicable for directory and feature file models. Every other
|
106
|
+
# model type should have a feature file ancestor from which to grab linter directive comments.
|
107
|
+
return base_linters if feature_file_model.nil?
|
179
108
|
|
180
|
-
|
181
|
-
feature_file_model = model.get_ancestor(:feature_file)
|
109
|
+
linter_modifications_for_model = {}
|
182
110
|
|
183
|
-
|
184
|
-
|
111
|
+
linter_directives_for_feature_file(feature_file_model).each do |directive|
|
112
|
+
# Assuming that the directives are in the same order that they appear in the file
|
113
|
+
break if directive[:source_line] > model.source_line
|
185
114
|
|
186
|
-
|
115
|
+
linter_modifications_for_model[directive[:linter_class]] = directive[:enabled_status]
|
116
|
+
end
|
187
117
|
|
188
|
-
|
189
|
-
|
190
|
-
break if directive[:source_line] > model.source_line
|
118
|
+
disabled_linter_classes = linter_modifications_for_model.reject { |_name, status| status }.keys
|
119
|
+
enabled_linter_classes = linter_modifications_for_model.select { |_name, status| status }.keys
|
191
120
|
|
192
|
-
|
121
|
+
determine_final_linters(base_linters, disabled_linter_classes, enabled_linter_classes)
|
193
122
|
end
|
194
123
|
|
195
|
-
|
196
|
-
|
124
|
+
def determine_final_linters(base_linters, disabled_linter_classes, enabled_linter_classes)
|
125
|
+
final_linters = base_linters.reject { |linter| disabled_linter_classes.include?(linter.class) }
|
197
126
|
|
198
|
-
|
199
|
-
|
200
|
-
|
201
|
-
end
|
202
|
-
|
203
|
-
final_linters
|
204
|
-
end
|
127
|
+
enabled_linter_classes.each do |clazz|
|
128
|
+
final_linters << dynamic_linters[clazz] unless final_linters.map(&:class).include?(clazz)
|
129
|
+
end
|
205
130
|
|
206
|
-
|
131
|
+
final_linters
|
132
|
+
end
|
207
133
|
|
134
|
+
def linter_directives_for_feature_file(feature_file_model)
|
135
|
+
# IMPORTANT ASSUMPTION: Models never change during the life of a linting, so data only has to be gathered once
|
136
|
+
existing_directives = @directives_for_feature_file[feature_file_model.object_id]
|
208
137
|
|
209
|
-
|
210
|
-
# IMPORTANT ASSUMPTION: Models never change during the life of a linting, so data only has to be gathered once
|
211
|
-
return @directives_for_feature_file[feature_file_model.object_id] if @directives_for_feature_file[feature_file_model.object_id]
|
138
|
+
return existing_directives if existing_directives
|
212
139
|
|
140
|
+
directives = gather_directives_in_feature(feature_file_model)
|
213
141
|
|
214
|
-
|
142
|
+
# Make sure that the directives are in the same order as they appear in the source file
|
143
|
+
directives = directives.sort_by { |a| a[:source_line] }
|
215
144
|
|
216
|
-
|
217
|
-
|
218
|
-
next unless pieces # Skipping non-directive file comments
|
145
|
+
@directives_for_feature_file[feature_file_model.object_id] = directives
|
146
|
+
end
|
219
147
|
|
220
|
-
|
221
|
-
|
222
|
-
|
223
|
-
|
224
|
-
|
148
|
+
def gather_directives_in_feature(feature_file_model)
|
149
|
+
[].tap do |directives|
|
150
|
+
feature_file_model.comments.each do |comment|
|
151
|
+
pieces = comment.text.match(/#\s*cuke_linter:(disable|enable)\s+(.*)/)
|
152
|
+
next unless pieces # Skipping non-directive file comments
|
153
|
+
|
154
|
+
linter_classes = pieces[2].tr(',', ' ').split(' ')
|
155
|
+
linter_classes.each do |clazz|
|
156
|
+
directives << { linter_class: Kernel.const_get(clazz),
|
157
|
+
enabled_status: pieces[1] != 'disable',
|
158
|
+
source_line: comment.source_line }
|
159
|
+
end
|
160
|
+
end
|
225
161
|
end
|
226
162
|
end
|
227
163
|
|
228
|
-
|
229
|
-
|
164
|
+
def dynamic_linters
|
165
|
+
# No need to keep making new ones over and over...
|
166
|
+
@dynamic_linters ||= Hash.new { |hash, key| hash[key] = key.new }
|
167
|
+
# return @dynamic_linters if @dynamic_linters
|
168
|
+
#
|
169
|
+
# @dynamic_linters = {}
|
170
|
+
end
|
230
171
|
|
172
|
+
def format_data(formatters, linting_data)
|
173
|
+
formatters.each do |formatter_output_pair|
|
174
|
+
formatter = formatter_output_pair[0]
|
175
|
+
location = formatter_output_pair[1]
|
231
176
|
|
232
|
-
|
233
|
-
end
|
177
|
+
formatted_data = formatter.format(linting_data)
|
234
178
|
|
235
|
-
|
179
|
+
if location
|
180
|
+
File.write(location, formatted_data)
|
181
|
+
else
|
182
|
+
puts formatted_data
|
183
|
+
end
|
184
|
+
end
|
185
|
+
end
|
236
186
|
|
237
|
-
|
238
|
-
#
|
239
|
-
|
240
|
-
#
|
187
|
+
# Not linting unused code
|
188
|
+
# rubocop:disable Metrics/LineLength
|
189
|
+
# def self.relevant_model?(linter, model)
|
190
|
+
# model_classes = linter.class.target_model_types.map { |type| CukeModeler.const_get(type.to_s.capitalize.chop) }
|
191
|
+
# model_classes.any? { |clazz| model.is_a?(clazz) }
|
192
|
+
# end
|
241
193
|
#
|
242
|
-
#
|
243
|
-
|
244
|
-
|
245
|
-
private_class_method(:dynamic_linters)
|
246
|
-
|
247
|
-
|
248
|
-
# # def self.relevant_model?(linter, model)
|
249
|
-
# # model_classes = linter.class.target_model_types.map { |type| CukeModeler.const_get(type.to_s.capitalize.chop) }
|
250
|
-
# # model_classes.any? { |clazz| model.is_a?(clazz) }
|
251
|
-
# # end
|
252
|
-
# #
|
253
|
-
# # private_class_method(:relevant_model?)
|
194
|
+
# private_class_method(:relevant_model?)
|
195
|
+
# rubocop:enable Metrics/LineLength
|
254
196
|
|
197
|
+
end
|
255
198
|
end
|