My External Storage

Nov 18, 2019 - 4 minute read - Comments - Go Vim

[Go] "vim-go: [golangci-lint] FAIL"エラーが出てvim-goでgolangci-lintが動かない

公私でGoを書くときはVimを使っている。
ファイル保存時にgolangci-lintを実行するように設定しているのだが、表題のエラーが出て静的解析が実行されなかったので原因調査・解決した。

TL;DR

  • VimでGoを書いているとき、vim-go: [golangci-lint] FAILエラーがでてgolangci-lintが失敗するようになった
  • :messagesを見てもわからなかった
  • :GoMetaLinterコマンドを実行したところ、本当のエラーメッセージがわかった
    • level=error msg="Running error: --enable-all and --disable-all options must not be combined"
  • .golangci.ymlの設定を修正して解決した

エラーが出てvim-goでgolangci-lintが動かない

公私でGoを書くときはVimを使っている。

私のVimでは(golangci-lintを使う設定をして、)GoMetaLinterAutoSaveToggleオプションを有効にしているので、ファイル保存時にgolangci-lintが実行される。

ここで、あるGoのプロジェクトで作業しているときだけ、ファイル保存時にvim-go: [golangci-lint] FAILとエラーメッセージが表示されるだけで静的解析が実行されなくなった。

原因調査: :GoMetaLinterコマンドを直接実行してみる

コマンドラインから直接golangci-lintコマンドを実行しても正常に実行できていた。
:messagesコマンドでVimが出力しているログを見ても、何が問題でgolangci-lintコマンドが失敗しているのかよくわからなかった。

起動直後にファイルを保存してエラーが出た状態で:messagesコマンドでログをみても以下の通り。

Messages maintainer: Bram Moolenaar <Bram@vim.org>
"main.go" 100L, 2767C
vim-go: initializing gopls
"main.go" 100L, 2767C written
vim-go: [golangci-lint] dispatched
vim-go: [golangci-lint] FAIL

ここで、vim-goを利用しているVimでは、:GoMetaLinterコマンドを使うことで、明示的にgolangci-lintを実行できる。

:GoMetaLinterコマンドを実行してみたところ、以下のようなエラーメッセージを確認することができた。

level=error msg="Running error: --enable-all and --disable-all options must not be combined"

どうやら、プロジェクトに配置してある.golangci.ymlに記載されている設定と、vim-gogolangci-lintコマンドを呼び出すときのオプションが競合しているのが原因だった。 vim-gogolangci-lintコマンドを呼び出すとき以下のように実行コマンドを組み立てる。この中で、--disable-allオプションを指定している。

  • https://github.com/fatih/vim-go/blob/75fa6fe70c5b9d7f7856bc26972d9ee97d99f7db/autoload/go/lint.vim#L242-L254

    function! s:golangcilintcmd(bin_path)
    let cmd = [a:bin_path]
    let cmd += ["run"]
    let cmd += ["--print-issued-lines=false"]
    let cmd += ['--build-tags', go#config#BuildTags()]
    let cmd += ["--disable-all"]
    " do not use the default exclude patterns, because doing so causes golint
    " problems about missing doc strings to be ignored and other things that
    " golint identifies.
    let cmd += ["--exclude-use-default=false"]
    
    return cmd
    endfunction

今回、プロジェクトで設置してある.golangci.ymlファイルではenable-allをベースに静的解析の設定を組み立てていため、enable-alldisable-all設定が競合していた。

linters:
  enable-all: true
  disable:
    - funlen
    - dogsled

解決方法:.golangci.ymlの設定を修正する

今回は以下の理由により、.golangci.yml側の設定方法を修正することで対応した。

  • Vim側のgolangci-lintコマンドの呼び出し時の設定を変更する方法がよくわからなかった
  • enable-allベースで設定していると、golangci-lintコマンドが新しいツールをサポートしたとき、意図せず有効化される
  • disable-allしたあと、明示的に利用する静的解析ツールを指定したほうがヒューマンリーダブルな設定になる

golangci-lintコマンドはgolangci-lint lintersコマンドでそのプロジェクト上(ディレクトリ上)の静的解析の設定を確認することができる。 なので、一度enable-allベースの設定でgolangci-lint lintersコマンドを実行し、ファイルに出力を保存しておいた。

$ golangci-lint linters
Enabled by your configuration linters:
bodyclose: checks whether HTTP response body is closed successfully [fast: true, auto-fix: false]
deadcode: Finds unused code [fast: true, auto-fix: false]
...

Disabled by your configuration linters:
depguard: Go linter that checks if package imports are in a list of acceptable packages [fast: true, auto-fix: false]
dogsled: Checks assignments with too many blank identifiers (e.g. x, _, _, _, := f()) [fast: true, auto-fix: false]
...

その後、disable-allベースの設定に書き直し、golangci-lint lintersコマンドの結果が以前と同じであることを確認した。

終わりに

私のVimの設定は一応golangci-lintgoplsを利用するように設定しているのだが、一度整理したほうがよいかなと思いつつズルズル使っている。 LSP系のプラグイン経由でgoplsを実行するほうがいろいろ設定できるらしいので、一度整理しようかなあ。

参考

関連記事