From 5a3cfbbdf50bc3e82e8ceca486a6bbda201f99d9 Mon Sep 17 00:00:00 2001 From: Chris Weyl Date: Mon, 3 Jul 2017 09:37:32 -0500 Subject: [PATCH] Allow `hadolint` linter to run via docker image (#720) * Add documentation for hadolint (doc/ale-hadolint.txt) * Allow `hadolint` linter to run via docker image These changes enable the `hadolint` linter to run via the author's docker image, if present. Three modes are supported: * never use docker; * always use docker; and * use docker as a failback. --- ale_linters/dockerfile/hadolint.vim | 44 +++++++++++++- doc/ale-dockerfile.txt | 37 ++++++++++++ test/test_dockerfile_hadolint_linter.vader | 69 ++++++++++++++++++++++ 3 files changed, 148 insertions(+), 2 deletions(-) create mode 100644 doc/ale-dockerfile.txt create mode 100644 test/test_dockerfile_hadolint_linter.vader diff --git a/ale_linters/dockerfile/hadolint.vim b/ale_linters/dockerfile/hadolint.vim index 1ac94ce..4063bf1 100644 --- a/ale_linters/dockerfile/hadolint.vim +++ b/ale_linters/dockerfile/hadolint.vim @@ -1,5 +1,9 @@ " Author: hauleth - https://github.com/hauleth +" always, yes, never +call ale#Set('dockerfile_hadolint_use_docker', 'never') +call ale#Set('dockerfile_hadolint_docker_image', 'lukasmartinelli/hadolint') + function! ale_linters#dockerfile#hadolint#Handle(buffer, lines) abort " Matches patterns line the following: " @@ -29,9 +33,45 @@ function! ale_linters#dockerfile#hadolint#Handle(buffer, lines) abort return l:output endfunction +" This is a little different than the typical 'executable' callback. We want +" to afford the user the chance to say always use docker, never use docker, +" and use docker if the hadolint executable is not present on the system. +" +" In the case of neither docker nor hadolint executables being present, it +" really doesn't matter which we return -- either will have the effect of +" 'nope, can't use this linter!'. + +function! ale_linters#dockerfile#hadolint#GetExecutable(buffer) abort + let l:use_docker = ale#Var(a:buffer, 'dockerfile_hadolint_use_docker') + + " check for mandatory directives + if l:use_docker ==# 'never' + return 'hadolint' + elseif l:use_docker ==# 'always' + return 'docker' + endif + + " if we reach here, we want to use 'hadolint' if present... + if executable('hadolint') + return 'hadolint' + endif + + "... and 'docker' as a fallback. + return 'docker' +endfunction + +function! ale_linters#dockerfile#hadolint#GetCommand(buffer) abort + let l:command = ale_linters#dockerfile#hadolint#GetExecutable(a:buffer) + if l:command ==# 'docker' + return 'docker run --rm -i ' . ale#Var(a:buffer, 'dockerfile_hadolint_docker_image') + endif + return 'hadolint -' +endfunction + + call ale#linter#Define('dockerfile', { \ 'name': 'hadolint', -\ 'executable': 'hadolint', -\ 'command': 'hadolint -', +\ 'executable_callback': 'ale_linters#dockerfile#hadolint#GetExecutable', +\ 'command_callback': 'ale_linters#dockerfile#hadolint#GetCommand', \ 'callback': 'ale_linters#dockerfile#hadolint#Handle', \}) diff --git a/doc/ale-dockerfile.txt b/doc/ale-dockerfile.txt new file mode 100644 index 0000000..e87a3aa --- /dev/null +++ b/doc/ale-dockerfile.txt @@ -0,0 +1,37 @@ +=============================================================================== +ALE Dockerfile Integration *ale-dockerfile-options* + + +------------------------------------------------------------------------------- +hadolint *ale-dockerfile-hadolint* + + hadolint can be found at: https://github.com/lukasmartinelli/hadolint + + +g:ale_dockerfile_hadolint_use_docker *g:ale_dockerfile_hadolint_use_docker* + *b:ale_dockerfile_hadolint_use_docker* + Type: |String| + Default: `'never'` + + This variable controls if docker and the hadolint image are used to run this + linter: if 'never', docker will never be used; 'always' means docker will + always be used; 'yes' and docker will be used if the hadolint executable + cannot be found. + + For now, the default is 'never'. This may change as ale's support for using + docker to lint evolves. + + +g:ale_dockerfile_hadolint_image *g:ale_dockerfile_hadolint_image* + *b:ale_dockerfile_hadolint_image* + Type: |String| + Default: `'lukasmartinelli/hadolint'` + + This variable controls the docker image used to run hadolint. The default + is hadolint's author's build, and can be found at: + + https://hub.docker.com/r/lukasmartinelli/hadolint/ + + +------------------------------------------------------------------------------- + vim:tw=78:ts=2:sts=2:sw=2:ft=help:norl: diff --git a/test/test_dockerfile_hadolint_linter.vader b/test/test_dockerfile_hadolint_linter.vader new file mode 100644 index 0000000..7262c5b --- /dev/null +++ b/test/test_dockerfile_hadolint_linter.vader @@ -0,0 +1,69 @@ +" NOTE: We use the 'b:' forms below to ensure that we're properly using +" ale#Var() + +Given dockerfile: + # + +Before: + Save g:ale_dockerfile_hadolint_use_docker + Save g:ale_dockerfile_hadolint_docker_image + silent! unlet g:ale_dockerfile_hadolint_use_docker + silent! unlet g:ale_dockerfile_hadolint_docker_image + + " enable loading inside test container + silent! cd /testplugin + source ale_linters/dockerfile/hadolint.vim + + +After: + Restore + silent! unlet b:ale_dockerfile_hadolint_use_docker + silent! unlet b:ale_dockerfile_hadolint_docker_image + + +Execute(linter honors ..._use_docker correctly): + + " default: never + AssertEqual + \ 'hadolint', + \ ale_linters#dockerfile#hadolint#GetExecutable(bufnr('')) + + " explicit never + let b:ale_dockerfile_hadolint_use_docker = 'never' + AssertEqual + \ 'hadolint', + \ ale_linters#dockerfile#hadolint#GetExecutable(bufnr('')) + + let b:ale_dockerfile_hadolint_use_docker = 'always' + AssertEqual + \ 'docker', + \ ale_linters#dockerfile#hadolint#GetExecutable(bufnr('')) + + " hadolint if present, otherwise docker + let command = 'docker' + if executable('hadolint') + let command = 'hadolint' + endif + + let b:ale_dockerfile_hadolint_use_docker = 'yes' + AssertEqual + \ command, + \ ale_linters#dockerfile#hadolint#GetExecutable(bufnr('')) + + +Execute(command is correct when using docker): + let b:ale_dockerfile_hadolint_use_docker = 'always' + + AssertEqual + \ "docker run --rm -i lukasmartinelli/hadolint", + \ ale_linters#dockerfile#hadolint#GetCommand(bufnr('')) + + +Execute(command is correct when not docker): + let b:ale_dockerfile_hadolint_use_docker = 'never' + + AssertEqual + \ "hadolint -", + \ ale_linters#dockerfile#hadolint#GetCommand(bufnr('')) + +" fin...