Add the dockerfile_lint linter for Dockerfiles (#1971)
* Add the dockerfile_lint linter for Dockerfiles
This commit is contained in:
parent
34318aedf4
commit
7af33637e8
6 changed files with 214 additions and 2 deletions
|
@ -117,7 +117,7 @@ formatting.
|
|||
| D | [dls](https://github.com/d-language-server/dls), [dmd](https://dlang.org/dmd-linux.html), [uncrustify](https://github.com/uncrustify/uncrustify) |
|
||||
| Dafny | [dafny](https://rise4fun.com/Dafny) !! |
|
||||
| Dart | [dartanalyzer](https://github.com/dart-lang/sdk/tree/master/pkg/analyzer_cli) !!, [language_server](https://github.com/natebosch/dart_language_server), [dartfmt](https://github.com/dart-lang/sdk/tree/master/utils/dartfmt) |
|
||||
| Dockerfile | [hadolint](https://github.com/hadolint/hadolint) |
|
||||
| Dockerfile | [dockerfile_lint](https://github.com/projectatomic/dockerfile_lint), [hadolint](https://github.com/hadolint/hadolint) |
|
||||
| Elixir | [credo](https://github.com/rrrene/credo), [dialyxir](https://github.com/jeremyjh/dialyxir), [dogma](https://github.com/lpil/dogma), [mix](https://hexdocs.pm/mix/Mix.html) !!, [elixir-ls](https://github.com/JakeBecker/elixir-ls) |
|
||||
| Elm | [elm-format](https://github.com/avh4/elm-format), [elm-make](https://github.com/elm-lang/elm-make) |
|
||||
| Erb | [erb](https://apidock.com/ruby/ERB), [erubi](https://github.com/jeremyevans/erubi), [erubis](https://github.com/kwatch/erubis) |
|
||||
|
|
61
ale_linters/dockerfile/dockerfile_lint.vim
Normal file
61
ale_linters/dockerfile/dockerfile_lint.vim
Normal file
|
@ -0,0 +1,61 @@
|
|||
" Author: Alexander Olofsson <alexander.olofsson@liu.se>
|
||||
|
||||
call ale#Set('dockerfile_dockerfile_lint_executable', 'dockerfile_lint')
|
||||
call ale#Set('dockerfile_dockerfile_lint_options', '')
|
||||
|
||||
function! ale_linters#dockerfile#dockerfile_lint#GetType(type) abort
|
||||
if a:type is? 'error'
|
||||
return 'E'
|
||||
elseif a:type is? 'warn'
|
||||
return 'W'
|
||||
endif
|
||||
|
||||
return 'I'
|
||||
endfunction
|
||||
|
||||
function! ale_linters#dockerfile#dockerfile_lint#Handle(buffer, lines) abort
|
||||
try
|
||||
let l:data = json_decode(join(a:lines, ''))
|
||||
catch
|
||||
return []
|
||||
endtry
|
||||
|
||||
if empty(l:data)
|
||||
" Should never happen, but it's better to be on the safe side
|
||||
return []
|
||||
endif
|
||||
|
||||
let l:messages = []
|
||||
|
||||
for l:type in ['error', 'warn', 'info']
|
||||
for l:object in l:data[l:type]['data']
|
||||
let l:line = get(l:object, 'line', -1)
|
||||
let l:message = l:object['message']
|
||||
|
||||
if get(l:object, 'description', 'None') isnot# 'None'
|
||||
let l:message = l:message . '. ' . l:object['description']
|
||||
endif
|
||||
|
||||
call add(l:messages, {
|
||||
\ 'lnum': l:line,
|
||||
\ 'text': l:message,
|
||||
\ 'type': ale_linters#dockerfile#dockerfile_lint#GetType(l:type),
|
||||
\})
|
||||
endfor
|
||||
endfor
|
||||
|
||||
return l:messages
|
||||
endfunction
|
||||
|
||||
function! ale_linters#dockerfile#dockerfile_lint#GetCommand(buffer) abort
|
||||
return '%e' . ale#Pad(ale#Var(a:buffer, 'dockerfile_dockerfile_lint_options'))
|
||||
\ . ' -p -j -f'
|
||||
\ . ' %t'
|
||||
endfunction
|
||||
|
||||
call ale#linter#Define('dockerfile', {
|
||||
\ 'name': 'dockerfile_lint',
|
||||
\ 'executable_callback': ale#VarFunc('dockerfile_dockerfile_lint_executable'),
|
||||
\ 'command_callback': 'ale_linters#dockerfile#dockerfile_lint#GetCommand',
|
||||
\ 'callback': 'ale_linters#dockerfile#dockerfile_lint#Handle',
|
||||
\})
|
|
@ -2,6 +2,29 @@
|
|||
ALE Dockerfile Integration *ale-dockerfile-options*
|
||||
|
||||
|
||||
===============================================================================
|
||||
dockerfile_lint *ale-dockerfile-dockerfile_lint*
|
||||
|
||||
g:ale_dockerfile_dockerfile_lint_executable
|
||||
*g:ale_dockerfile_dockerfile_lint_executable*
|
||||
*b:ale_dockerfile_dockerfile_lint_executable*
|
||||
Type: |String|
|
||||
Default: `'dockerfile_lint'`
|
||||
|
||||
This variable can be changed to specify the executable used to run
|
||||
dockerfile_lint.
|
||||
|
||||
|
||||
g:ale_dockerfile_dockerfile_lint_options
|
||||
*g:ale_dockerfile_dockerfile_lint_options*
|
||||
*b:ale_dockerfile_dockerfile_lint_options*
|
||||
Type: |String|
|
||||
Default: `''`
|
||||
|
||||
This variable can be changed to add additional command-line arguments to
|
||||
the dockerfile lint invocation - like custom rule file definitions.
|
||||
|
||||
|
||||
===============================================================================
|
||||
hadolint *ale-dockerfile-hadolint*
|
||||
|
||||
|
|
|
@ -75,6 +75,7 @@ CONTENTS *ale-contents*
|
|||
dartanalyzer........................|ale-dart-dartanalyzer|
|
||||
dartfmt.............................|ale-dart-dartfmt|
|
||||
dockerfile............................|ale-dockerfile-options|
|
||||
dockerfile_lint.....................|ale-dockerfile-dockerfile_lint|
|
||||
hadolint............................|ale-dockerfile-hadolint|
|
||||
elixir................................|ale-elixir-options|
|
||||
mix.................................|ale-elixir-mix|
|
||||
|
@ -407,7 +408,7 @@ Notes:
|
|||
* D: `dls`, `dmd`, `uncrustify`
|
||||
* Dafny: `dafny`!!
|
||||
* Dart: `dartanalyzer`!!, `language_server`, dartfmt!!
|
||||
* Dockerfile: `hadolint`
|
||||
* Dockerfile: `dockerfile_lint`, `hadolint`
|
||||
* Elixir: `credo`, `dialyxir`, `dogma`, `mix`!!, `elixir-ls`
|
||||
* Elm: `elm-format, elm-make`
|
||||
* Erb: `erb`, `erubi`, `erubis`
|
||||
|
|
|
@ -0,0 +1,19 @@
|
|||
Before:
|
||||
call ale#assert#SetUpLinterTest('dockerfile', 'dockerfile_lint')
|
||||
|
||||
After:
|
||||
call ale#assert#TearDownLinterTest()
|
||||
|
||||
Execute(The default command should be correct):
|
||||
AssertLinter 'dockerfile_lint', ale#Escape('dockerfile_lint') . ' -p -j -f %t'
|
||||
|
||||
Execute(The executable should be configurable):
|
||||
let b:ale_dockerfile_dockerfile_lint_executable = 'foobar'
|
||||
|
||||
AssertLinter 'foobar', ale#Escape('foobar') . ' -p -j -f %t'
|
||||
|
||||
Execute(The options should be configurable):
|
||||
let b:ale_dockerfile_dockerfile_lint_options = '-r additional.yaml'
|
||||
|
||||
AssertLinter 'dockerfile_lint', ale#Escape('dockerfile_lint') . ' -r additional.yaml -p -j -f %t'
|
||||
|
108
test/handler/test_dockerfile_lint_handler.vader
Normal file
108
test/handler/test_dockerfile_lint_handler.vader
Normal file
|
@ -0,0 +1,108 @@
|
|||
Before:
|
||||
runtime ale_linters/dockerfile/dockerfile_lint.vim
|
||||
|
||||
After:
|
||||
call ale#linter#Reset()
|
||||
|
||||
Execute(The dockerfile_lint handler should handle broken JSON):
|
||||
AssertEqual
|
||||
\ [],
|
||||
\ ale_linters#dockerfile#dockerfile_lint#Handle(bufnr(''), ["{asdf"])
|
||||
|
||||
Execute(The dockerfile_lint handler should handle an empty string response):
|
||||
AssertEqual
|
||||
\ [],
|
||||
\ ale_linters#dockerfile#dockerfile_lint#Handle(bufnr(''), [])
|
||||
|
||||
Execute(The dockerfile_lint handler should handle an empty result, even if it shouldn't happen):
|
||||
AssertEqual
|
||||
\ [],
|
||||
\ ale_linters#dockerfile#dockerfile_lint#Handle(bufnr(''), ["{}"])
|
||||
|
||||
Execute(The dockerfile_lint handler should handle a normal example):
|
||||
AssertEqual
|
||||
\ [
|
||||
\ {
|
||||
\ 'lnum': -1,
|
||||
\ 'type': 'E',
|
||||
\ 'text': "Required LABEL name/key 'Name' is not defined",
|
||||
\ },
|
||||
\ {
|
||||
\ 'lnum': -1,
|
||||
\ 'type': 'E',
|
||||
\ 'text': "Required LABEL name/key 'Version' is not defined",
|
||||
\ },
|
||||
\ {
|
||||
\ 'lnum': 3,
|
||||
\ 'type': 'I',
|
||||
\ 'text': "the MAINTAINER command is deprecated. MAINTAINER is deprecated in favor of using LABEL since Docker v1.13.0",
|
||||
\ },
|
||||
\ {
|
||||
\ 'lnum': -1,
|
||||
\ 'type': 'I',
|
||||
\ 'text': "There is no 'CMD' instruction",
|
||||
\ },
|
||||
\ ],
|
||||
\ ale_linters#dockerfile#dockerfile_lint#Handle(bufnr(''), [
|
||||
\ '{',
|
||||
\ ' "error": {',
|
||||
\ ' "count": 2,',
|
||||
\ ' "data": [',
|
||||
\ ' {',
|
||||
\ " \"message\": \"Required LABEL name/key 'Name' is not defined\",",
|
||||
\ ' "line": -1,',
|
||||
\ ' "level": "error",',
|
||||
\ ' "lineContent": "",',
|
||||
\ ' "reference_url": [',
|
||||
\ ' "http://docs.projectatomic.io/container-best-practices/#",',
|
||||
\ ' "_recommended_labels_for_your_project"',
|
||||
\ ' ]',
|
||||
\ ' },',
|
||||
\ ' {',
|
||||
\ " \"message\": \"Required LABEL name/key 'Version' is not defined\",",
|
||||
\ ' "line": -1,',
|
||||
\ ' "level": "error",',
|
||||
\ ' "lineContent": "",',
|
||||
\ ' "reference_url": [',
|
||||
\ ' "http://docs.projectatomic.io/container-best-practices/#",',
|
||||
\ ' "_recommended_labels_for_your_project"',
|
||||
\ ' ]',
|
||||
\ ' }',
|
||||
\ ' ]',
|
||||
\ ' },',
|
||||
\ ' "warn": {',
|
||||
\ ' "count": 0,',
|
||||
\ ' "data": []',
|
||||
\ ' },',
|
||||
\ ' "info": {',
|
||||
\ ' "count": 2,',
|
||||
\ ' "data": [',
|
||||
\ ' {',
|
||||
\ ' "label": "maintainer_deprecated",',
|
||||
\ ' "regex": {},',
|
||||
\ ' "level": "info",',
|
||||
\ ' "message": "the MAINTAINER command is deprecated",',
|
||||
\ ' "description": "MAINTAINER is deprecated in favor of using LABEL since Docker v1.13.0",',
|
||||
\ ' "reference_url": [',
|
||||
\ ' "https://github.com/docker/cli/blob/master/docs/deprecated.md",',
|
||||
\ ' "#maintainer-in-dockerfile"',
|
||||
\ ' ],',
|
||||
\ ' "lineContent": "MAINTAINER Alexander Olofsson <ace@haxalot.com>",',
|
||||
\ ' "line": 3',
|
||||
\ ' },',
|
||||
\ ' {',
|
||||
\ ' "instruction": "CMD",',
|
||||
\ ' "count": 1,',
|
||||
\ ' "level": "info",',
|
||||
\ " \"message\": \"There is no 'CMD' instruction\",",
|
||||
\ ' "description": "None",',
|
||||
\ ' "reference_url": [',
|
||||
\ ' "https://docs.docker.com/engine/reference/builder/",',
|
||||
\ ' "#cmd"',
|
||||
\ ' ]',
|
||||
\ ' }',
|
||||
\ ' ]',
|
||||
\ ' },',
|
||||
\ ' "summary": []',
|
||||
\ '}',
|
||||
\ ])
|
Reference in a new issue