diff --git a/ale_linters/terraform/tflint.vim b/ale_linters/terraform/tflint.vim index 6d54a8b1..f57ee6b6 100644 --- a/ale_linters/terraform/tflint.vim +++ b/ale_linters/terraform/tflint.vim @@ -9,23 +9,69 @@ call ale#Set('terraform_tflint_executable', 'tflint') function! ale_linters#terraform#tflint#Handle(buffer, lines) abort let l:output = [] + let l:pattern = '\v^(.*):(\d+),(\d+)-(\d+)?,?(\d+): (.{-1,}); (.+)$' + let l:json = ale#util#FuzzyJSONDecode(a:lines, {}) - for l:error in ale#util#FuzzyJSONDecode(a:lines, []) - if l:error.type is# 'ERROR' - let l:type = 'E' - elseif l:error.type is# 'NOTICE' - let l:type = 'I' - else - let l:type = 'W' - endif + " This is a rough test for tflint's output format + " On versions prior to 0.11 it outputs all errors as a single level list + if type(l:json) is v:t_list + for l:error in l:json + if l:error.type is# 'ERROR' + let l:type = 'E' + elseif l:error.type is# 'NOTICE' + let l:type = 'I' + else + let l:type = 'W' + endif - call add(l:output, { - \ 'lnum': l:error.line, - \ 'text': l:error.message, - \ 'type': l:type, - \ 'code': l:error.detector, - \}) - endfor + call add(l:output, { + \ 'lnum': l:error.line, + \ 'text': l:error.message, + \ 'type': l:type, + \ 'code': l:error.detector, + \}) + endfor + else + for l:error in get(l:json, 'errors', []) + for l:match in ale#util#GetMatches(l:error.message, [l:pattern]) + if l:match[4] is# '' + let l:match[4] = l:match[2] + endif + + call add(l:output, { + \ 'filename': l:match[1], + \ 'lnum': str2nr(l:match[2]), + \ 'col': str2nr(l:match[3]), + \ 'end_lnum': str2nr(l:match[4]), + \ 'end_col': str2nr(l:match[5]), + \ 'text': l:match[7], + \ 'code': l:match[6], + \ 'type': 'E', + \}) + endfor + endfor + + for l:error in get(l:json, 'issues', []) + if l:error.rule.severity is# 'ERROR' + let l:type = 'E' + elseif l:error.rule.severity is# 'NOTICE' + let l:type = 'I' + else + let l:type = 'W' + endif + + call add(l:output, { + \ 'filename': l:error.range.filename, + \ 'lnum': l:error.range.start.line, + \ 'col': l:error.range.start.column, + \ 'end_lnum': l:error.range.end.line, + \ 'end_col': l:error.range.end.column, + \ 'text': l:error.message, + \ 'code': l:error.rule.name, + \ 'type': l:type, + \}) + endfor + endif return l:output endfunction diff --git a/test/handler/test_tflint_handler.vader b/test/handler/test_tflint_handler.vader index 099d0926..6b8173af 100644 --- a/test/handler/test_tflint_handler.vader +++ b/test/handler/test_tflint_handler.vader @@ -4,7 +4,7 @@ Before: After: call ale#linter#Reset() -Execute(The tflint handler should parse items correctly): +Execute(The tflint handler should parse items correctly for pre 0.11): AssertEqual \ [ \ { @@ -29,3 +29,71 @@ Execute(The tflint handler should parse items correctly): \ ale_linters#terraform#tflint#Handle(123, [ \ '[ { "detector": "aws_db_instance_readable_password", "type": "WARNING", "message": "be warned, traveller", "line": 12, "file": "github.com/wata727/example-module/aws_db_instance.tf", "link": "https://github.com/wata727/tflint/blob/master/docs/aws_db_instance_readable_password.md" }, { "detector": "aws_elasticache_cluster_invalid_type", "type": "ERROR", "message": "error message", "line": 9, "file": "github.com/wata727/example-module/aws_elasticache_cluster.tf", "link": "https://github.com/wata727/tflint/blob/master/docs/aws_elasticache_cluster_invalid_type.md" }, { "detector": "aws_instance_not_specified_iam_profile", "type": "NOTICE", "message": "just so ya know", "line": 5, "file": "github.com/wata727/example-module/aws_instance.tf", "link": "https://github.com/wata727/tflint/blob/master/docs/aws_instance_not_specified_iam_profile.md" } ]' \ ]) + +Execute(The tflint handler should parse items correctly): + AssertEqual + \ [ + \ { + \ 'filename': 'github.com/wata727/example-module/aws_instance.tf', + \ 'lnum': 1, + \ 'col': 30, + \ 'end_lnum': 2, + \ 'end_col': 1, + \ 'text': 'A block definition must have block content delimited by "{" and "}", starting on the same line as the block header.', + \ 'code': 'Invalid block definition', + \ 'type': 'E', + \ }, + \ { + \ 'filename': 'github.com/wata727/example-module/aws_instance.tf', + \ 'lnum': 2, + \ 'col': 3, + \ 'end_lnum': 2, + \ 'end_col': 6, + \ 'text': 'An argument named "ami" is not expected here.', + \ 'code': 'Unsupported argument', + \ 'type': 'E', + \ }, + \ { + \ 'filename': 'github.com/wata727/example-module/aws_instance.tf', + \ 'lnum': 3, + \ 'col': 3, + \ 'end_lnum': 1, + \ 'end_col': 6, + \ 'text': 'An argument named "instance_type" is not expected here.', + \ 'code': 'Unsupported argument', + \ 'type': 'E', + \ }, + \ { + \ 'filename': 'github.com/wata727/example-module/aws_db_instance.tf', + \ 'lnum': 12, + \ 'col': 11, + \ 'end_lnum': 12, + \ 'end_col': 21, + \ 'text': 'be warned, traveller', + \ 'code': 'aws_db_instance_readable_password', + \ 'type': 'W', + \ }, + \ { + \ 'filename': 'github.com/wata727/example-module/aws_elasticache_cluster.tf', + \ 'lnum': 9, + \ 'col': 29, + \ 'end_lnum': 9, + \ 'end_col': 29, + \ 'text': 'error message', + \ 'code': 'aws_elasticache_cluster_invalid_type', + \ 'type': 'E', + \ }, + \ { + \ 'filename': 'github.com/wata727/example-module/aws_instance.tf', + \ 'lnum': 5, + \ 'col': 15, + \ 'end_lnum': 5, + \ 'end_col': 25, + \ 'text': 'just so ya know', + \ 'code': 'aws_instance_not_specified_iam_profile', + \ 'type': 'I', + \ }, + \ ], + \ ale_linters#terraform#tflint#Handle(123, [ + \ '{"issues":[{"rule":{"name":"aws_db_instance_readable_password","severity":"WARNING","link":"https://github.com/wata727/tflint/blob/master/docs/aws_db_instance_readable_password.md"},"message":"be warned, traveller","range":{"filename":"github.com/wata727/example-module/aws_db_instance.tf","start":{"line":12,"column":11},"end":{"line":12,"column":21},"callers":[]}},{"rule":{"name":"aws_elasticache_cluster_invalid_type","severity":"ERROR","link":"https://github.com/wata727/tflint/blob/master/docs/aws_elasticache_cluster_invalid_type.md"},"message":"error message","range":{"filename":"github.com/wata727/example-module/aws_elasticache_cluster.tf","start":{"line":9,"column":29},"end":{"line":9,"column":29},"callers":[]}},{"rule":{"name":"aws_instance_not_specified_iam_profile","severity":"NOTICE","link":"https://github.com/wata727/tflint/blob/master/docs/aws_instance_not_specified_iam_profile.md"},"message":"just so ya know","range":{"filename":"github.com/wata727/example-module/aws_instance.tf","start":{"line":5,"column":15},"end":{"line":5,"column":25},"callers":[]}}],"errors":[{"message":"github.com/wata727/example-module/aws_instance.tf:1,30-2,1: Invalid block definition; A block definition must have block content delimited by \"{\" and \"}\", starting on the same line as the block header."},{"message":"github.com/wata727/example-module/aws_instance.tf:2,3-6: Unsupported argument; An argument named \"ami\" is not expected here."},{"message":"github.com/wata727/example-module/aws_instance.tf:3,3-16: Unsupported argument; An argument named \"instance_type\" is not expected here."}]}' + \ ])