From 81423701b0378af56d53402b1a95026b71369246 Mon Sep 17 00:00:00 2001 From: Raphael Hoegger Date: Wed, 10 Apr 2019 19:52:52 +0200 Subject: [PATCH] Adding new linter "cookstyle" for chef recipes (Issue #1187) (#2362) --- ale_linters/chef/cookstyle.vim | 54 +++++++++++++++++++ doc/ale-chef.txt | 20 +++++++ doc/ale-supported-languages-and-tools.txt | 1 + doc/ale.txt | 1 + supported-tools.md | 1 + .../test_cookstyle_command_callback.vader | 19 +++++++ test/handler/test_cookstyle_handler.vader | 22 ++++++++ 7 files changed, 118 insertions(+) create mode 100644 ale_linters/chef/cookstyle.vim create mode 100644 test/command_callback/test_cookstyle_command_callback.vader create mode 100644 test/handler/test_cookstyle_handler.vader diff --git a/ale_linters/chef/cookstyle.vim b/ale_linters/chef/cookstyle.vim new file mode 100644 index 00000000..50bae2aa --- /dev/null +++ b/ale_linters/chef/cookstyle.vim @@ -0,0 +1,54 @@ +" Author: Raphael Hoegger - https://github.com/pfuender +" Description: Cookstyle (RuboCop based), a code style analyzer for Ruby files + +call ale#Set('chef_cookstyle_executable', 'cookstyle') +call ale#Set('chef_cookstyle_options', '') + +function! ale_linters#chef#cookstyle#GetCommand(buffer) abort + let l:options = ale#Var(a:buffer, 'chef_cookstyle_options') + + return '%e' . ale#Pad(escape(l:options, '~')) . ' --force-exclusion --format json --stdin ' . ' %s' +endfunction + +function! ale_linters#chef#cookstyle#Handle(buffer, lines) abort + if len(a:lines) == 0 + return [] + endif + + let l:errors = ale#util#FuzzyJSONDecode(a:lines[0], {}) + + if !has_key(l:errors, 'summary') + \|| l:errors['summary']['offense_count'] == 0 + \|| empty(l:errors['files']) + return [] + endif + + let l:output = [] + + for l:error in l:errors['files'][0]['offenses'] + let l:start_col = str2nr(l:error['location']['start_column']) + let l:end_col = str2nr(l:error['location']['last_column']) + + if !l:end_col + let l:end_col = l:start_col + 1 + endif + + call add(l:output, { + \ 'lnum': str2nr(l:error['location']['line']), + \ 'col': l:start_col, + \ 'end_col': l:end_col, + \ 'code': l:error['cop_name'], + \ 'text': l:error['message'], + \ 'type': l:error['severity'] is? 'convention' ? 'W' : 'E', + \}) + endfor + + return l:output +endfunction + +call ale#linter#Define('chef', { +\ 'name': 'cookstyle', +\ 'executable': {b -> ale#Var(b, 'chef_cookstyle_executable')}, +\ 'command': function('ale_linters#chef#cookstyle#GetCommand'), +\ 'callback': 'ale_linters#chef#cookstyle#Handle', +\}) diff --git a/doc/ale-chef.txt b/doc/ale-chef.txt index 5024e279..75e144ec 100644 --- a/doc/ale-chef.txt +++ b/doc/ale-chef.txt @@ -2,6 +2,26 @@ ALE Chef Integration *ale-chef-options* +=============================================================================== +cookstyle *ale-chef-cookstyle* + +g:ale_chef_cookstyle_options *g:ale_chef_cookstyle_options* + *b:ale_chef_cookstyle_options* + Type: |String| + Default: `''` + + This variable can be changed to modify flags given to cookstyle. + + +g:ale_chef_cookstyle_executable *g:ale_chef_cookstyle_executable* + *b:ale_chef_cookstyle_executable* + Type: |String| + Default: `'cookstyle'` + + This variable can be changed to point to the cookstyle binary in case it's + not on the $PATH or a specific version/path must be used. + + =============================================================================== foodcritic *ale-chef-foodcritic* diff --git a/doc/ale-supported-languages-and-tools.txt b/doc/ale-supported-languages-and-tools.txt index 3f329ba2..4307649d 100644 --- a/doc/ale-supported-languages-and-tools.txt +++ b/doc/ale-supported-languages-and-tools.txt @@ -71,6 +71,7 @@ Notes: * `gcc` * `uncrustify` * Chef + * `cookstyle` * `foodcritic` * Clojure * `joker` diff --git a/doc/ale.txt b/doc/ale.txt index 6155dc37..34b5047f 100644 --- a/doc/ale.txt +++ b/doc/ale.txt @@ -1864,6 +1864,7 @@ documented in additional help files. uncrustify............................|ale-c-uncrustify| ccls..................................|ale-c-ccls| chef....................................|ale-chef-options| + cookstyle.............................|ale-chef-cookstyle| foodcritic............................|ale-chef-foodcritic| clojure.................................|ale-clojure-options| joker.................................|ale-clojure-joker| diff --git a/supported-tools.md b/supported-tools.md index 532fc1f8..36d72d3e 100644 --- a/supported-tools.md +++ b/supported-tools.md @@ -80,6 +80,7 @@ formatting. * [gcc](https://gcc.gnu.org/) * [uncrustify](https://github.com/uncrustify/uncrustify) * Chef + * [cookstyle](https://docs.chef.io/cookstyle.html) * [foodcritic](http://www.foodcritic.io/) * Clojure * [joker](https://github.com/candid82/joker) diff --git a/test/command_callback/test_cookstyle_command_callback.vader b/test/command_callback/test_cookstyle_command_callback.vader new file mode 100644 index 00000000..ad7391cc --- /dev/null +++ b/test/command_callback/test_cookstyle_command_callback.vader @@ -0,0 +1,19 @@ +Before: + call ale#assert#SetUpLinterTest('chef', 'cookstyle') + +After: + call ale#assert#TearDownLinterTest() + +Execute(The default command should be correct): + AssertLinter 'cookstyle', ale#Escape('cookstyle') . ' --force-exclusion --format json --stdin %s' + +Execute(The executable path should be configurable): + let b:ale_chef_cookstyle_executable = 'foobar' + + AssertLinter 'foobar', ale#Escape('foobar') . ' --force-exclusion --format json --stdin %s' + +Execute(The linter options should be configurable): + let b:ale_chef_cookstyle_options = '--parallel' + + AssertLinter 'cookstyle', ale#Escape('cookstyle') . ' --parallel --force-exclusion --format json --stdin %s' + diff --git a/test/handler/test_cookstyle_handler.vader b/test/handler/test_cookstyle_handler.vader new file mode 100644 index 00000000..7d705a19 --- /dev/null +++ b/test/handler/test_cookstyle_handler.vader @@ -0,0 +1,22 @@ +Before: + runtime ale_linters/chef/cookstyle.vim + +After: + call ale#linter#Reset() + +Execute(Basic warnings should be handled): + AssertEqual + \ [ + \ { + \ 'lnum': 58, + \ 'col': 24, + \ 'code': 'Style/UnneededInterpolation', + \ 'type': 'W', + \ 'end_col': 40, + \ 'text': 'Style/UnneededInterpolation: Prefer `to_s` over string interpolation.', + \ } + \ ], + \ ale_linters#chef#cookstyle#Handle(bufnr(''), [ + \ '{"metadata":{"rubocop_version":"0.62.0","ruby_engine":"ruby","ruby_version":"2.6.0","ruby_patchlevel":"0","ruby_platform":"x86_64-linux"},"files":[{"path":"recipes/default.rb","offenses":[{"severity":"convention","message":"Style/UnneededInterpolation: Prefer `to_s` over string interpolation.","cop_name":"Style/UnneededInterpolation","corrected":false,"location":{"start_line":58,"start_column":24,"last_line":58,"last_column":40,"length":17,"line":58,"column":24}}]}],"summary":{"offense_count":1,"target_file_count":1,"inspected_file_count":1}}' + \ ]) +