diff --git a/.cbfmt.toml b/.cbfmt.toml new file mode 100644 index 0000000..bd325e4 --- /dev/null +++ b/.cbfmt.toml @@ -0,0 +1,2 @@ +[languages] +lua = ["stylua -s -"] diff --git a/.github/workflows/lua_language_server.yml b/.github/workflows/lua_language_server.yml new file mode 100644 index 0000000..1859c13 --- /dev/null +++ b/.github/workflows/lua_language_server.yml @@ -0,0 +1,56 @@ +name: Lua Language Server Check + +on: + workflow_call: + inputs: + lua_ls_version: + required: true + type: string + neovim_versions: + required: true + type: string + +jobs: + lua-language-server: + name: lua language server + runs-on: ubuntu-22.04 + strategy: + fail-fast: false + matrix: + rev: ${{ fromJson(inputs.neovim_versions) }} + steps: + - uses: actions/checkout@v3 + - run: date +%F > todays-date + - name: Restore cache for Neovim + uses: actions/cache@v3 + with: + path: .ci/neovim + key: ${{ matrix.rev }}-${{ hashFiles('todays-date') }} + - name: Restore cache for vendor dependencies + uses: actions/cache@v3 + with: + path: .ci/vendor + key: ${{ hashFiles('todays-date') }} + - name: Restore cache for lua LS + uses: actions/cache@v3 + with: + path: .ci/lua-ls + key: ${{ inputs.lua_ls_version }} + - name: Prepare + run: | + test -d .ci/neovim || { + mkdir -p .ci/neovim + curl -sL "https://github.com/neovim/neovim/releases/download/${{ matrix.rev }}/nvim-linux64.tar.gz" | tar xzf - --strip-components=1 -C "${PWD}/.ci/neovim" + } + test -d .ci/lua-ls || { + mkdir -p .ci/lua-ls + curl -sL "https://github.com/LuaLS/lua-language-server/releases/download/${{ inputs.lua_ls_version }}/lua-language-server-${{ inputs.lua_ls_version }}-linux-x64.tar.gz" | tar xzf - -C "${PWD}/.ci/lua-ls" + } + + - name: Run check + run: | + export PATH="${PWD}/.ci/neovim/bin:${PATH}" + export PATH="${PWD}/.ci/lua-ls/bin:${PATH}" + export VIM="${PWD}/.ci/neovim/share/nvim/runtime" + nvim --version + make lua-language-server version=${{ matrix.rev == 'nightly' && 'nightly' || 'stable' }} diff --git a/.github/workflows/nightly_check.yml b/.github/workflows/nightly_check.yml new file mode 100644 index 0000000..e972140 --- /dev/null +++ b/.github/workflows/nightly_check.yml @@ -0,0 +1,25 @@ +name: Nightly Neovim Check +# Checks LSP and unit tests against new Neovim nightly once a week + +on: + schedule: + - cron: '30 21 * * 0' # 6:30 AM JST, Monday + workflow_dispatch: + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +jobs: + tests: + uses: ./.github/workflows/tests.yml + with: + neovim_versions: | + [ "nightly" ] + + lua-language-server: + uses: ./.github/workflows/lua_language_server.yml + with: + lua_ls_version: 3.9.1 + neovim_versions: | + [ "nightly" ] diff --git a/.github/workflows/pr_check.yml b/.github/workflows/pr_check.yml index 7687edc..ed78314 100644 --- a/.github/workflows/pr_check.yml +++ b/.github/workflows/pr_check.yml @@ -1,61 +1,81 @@ -name: Pull request check +name: Pull Request Check on: pull_request: +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + jobs: - format: - runs-on: ubuntu-latest + tests: + uses: ./.github/workflows/tests.yml + with: + neovim_versions: | + [ "nightly", "v0.10.0" ] + + lua-language-server: + uses: ./.github/workflows/lua_language_server.yml + with: + lua_ls_version: 3.9.1 + neovim_versions: | + [ "nightly", "v0.10.0" ] + + stylua: + name: stylua + runs-on: ubuntu-22.04 steps: - - uses: actions/checkout@v2 - - uses: JohnnyMorganz/stylua-action@1.0.0 + - uses: actions/checkout@v3 + - uses: JohnnyMorganz/stylua-action@v3 with: token: ${{ secrets.GITHUB_TOKEN }} - args: --check . + version: latest + args: --color always --check . + + luacheck: + name: luacheck + runs-on: ubuntu-22.04 + steps: + - uses: actions/checkout@v3 + + - name: Prepare + run: | + sudo apt-get update + sudo apt-get install -y luarocks + sudo luarocks install luacheck + + - name: Lint + run: sudo make luacheck block-fixup: - runs-on: ubuntu-latest + runs-on: ubuntu-22.04 steps: - uses: actions/checkout@v2 - name: Block Fixup Commit Merge uses: 13rac1/block-fixup-merge-action@v2.0.0 - luacheck: + conventional-commit: runs-on: ubuntu-latest - steps: - - uses: actions/checkout@master - - - uses: leafo/gh-actions-lua@v8.0.0 + - name: Checkout code + uses: actions/checkout@v3 with: - luaVersion: 'luajit-2.1.0-beta3' - - - uses: leafo/gh-actions-luarocks@v4.0.0 - - - name: build - run: | - luarocks install luacheck + fetch-depth: 0 - - name: test + - name: Check Commit Messages run: | - luacheck lua specs - - tests: - strategy: - fail-fast: false - matrix: - version: - - stable - - nightly - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v2 - - name: Install Neovim - uses: rhysd/action-setup-vim@v1 - id: neovim - with: - neovim: true - version: ${{ matrix.version }} - - name: Run tests - run: make specs + commits=$(git log --no-merges --pretty=format:"%s" HEAD~${{ github.event.pull_request.commits }}..HEAD) + bad_commits=() + for commit in "$commits"; do + if ! echo $commit | grep -qE "^(build|chore|ci|docs|feat|fix|perf|refactor|revert|style|test)(\(.+\))?: .+"; then + bad_commits+=("$commit") + fi + done + if [[ ${#bad_commits[@]} -ne 0 ]]; then + echo "The following commits do not follow the Conventional Commit format:" + for bad_commit in "${bad_commits[@]}"; do + echo " - $bad_commit" + done + exit 1 + fi diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml new file mode 100644 index 0000000..0fc33cd --- /dev/null +++ b/.github/workflows/tests.yml @@ -0,0 +1,38 @@ +name: Unit Tests + +on: + workflow_call: + inputs: + neovim_versions: + required: true + type: string + +jobs: + tests: + name: unit tests + runs-on: ubuntu-22.04 + strategy: + fail-fast: false + matrix: + rev: ${{ fromJson(inputs.neovim_versions) }} + steps: + - uses: actions/checkout@v3 + - run: date +%F > todays-date + - name: Restore cache for Neovim + uses: actions/cache@v3 + with: + path: .ci/neovim + key: ${{ matrix.rev }}-${{ hashFiles('todays-date') }} + - name: Prepare + run: | + test -d .ci/neovim || { + mkdir -p .ci/neovim + curl -sL "https://github.com/neovim/neovim/releases/download/${{ matrix.rev }}/nvim-linux64.tar.gz" | tar xzf - --strip-components=1 -C "${PWD}/.ci/neovim" + } + + - name: Run tests + run: | + export PATH="${PWD}/.ci/neovim/bin:${PATH}" + export VIM="${PWD}/.ci/neovim/share/nvim/runtime" + nvim --version + make test diff --git a/.gitignore b/.gitignore index 9ee4a58..d732e44 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ /doc/tags vendor +.ci/* diff --git a/.luacheckrc b/.luacheckrc index 7d82b11..de8f474 100644 --- a/.luacheckrc +++ b/.luacheckrc @@ -1,2 +1,6 @@ -globals = { "vim", "_", "assert", "describe", "before_each", "after_each", "it" } +globals = { "vim", "_", "describe", "it", "after_each", "before_each", "assert" } max_line_length = false + +exclude_files = { + ".ci/vendor", +} diff --git a/.luarc.nightly.json b/.luarc.nightly.json new file mode 100644 index 0000000..e311ce6 --- /dev/null +++ b/.luarc.nightly.json @@ -0,0 +1,18 @@ +{ + "runtime.version": "LuaJIT", + "diagnostics.globals": [ + "it", + "describe", + "before_each", + "after_each", + "setup", + "teardown" + ], + "diagnostics.ignoredFiles": "Disable", + "diagnostics.libraryFiles": "Disable", + "workspace.library": [ + "/usr/local/share/nvim/runtime/lua", + ".ci/neovim/share/nvim/runtime/lua", + ".ci/vendor/pack/vendor/start/neodev.nvim/types/nightly" + ] +} diff --git a/.luarc.stable.json b/.luarc.stable.json new file mode 100644 index 0000000..c1cfac0 --- /dev/null +++ b/.luarc.stable.json @@ -0,0 +1,18 @@ +{ + "runtime.version": "LuaJIT", + "diagnostics.globals": [ + "it", + "describe", + "before_each", + "after_each", + "setup", + "teardown" + ], + "diagnostics.ignoredFiles": "Disable", + "diagnostics.libraryFiles": "Disable", + "workspace.library": [ + "/usr/local/share/nvim/runtime/lua", + ".ci/neovim/share/nvim/runtime/lua", + ".ci/vendor/pack/vendor/start/neodev.nvim/types/stable" + ] +} diff --git a/.styluaignore b/.styluaignore new file mode 100644 index 0000000..d113a58 --- /dev/null +++ b/.styluaignore @@ -0,0 +1 @@ +.ci/* diff --git a/Makefile b/Makefile index f34e254..c81ca8b 100644 --- a/Makefile +++ b/Makefile @@ -2,19 +2,34 @@ ifndef VERBOSE .SILENT: endif -specs: dependencies - @echo "Running lsp-format specs..." +test: dependencies + @echo "Running lsp-format tests..." timeout 300 nvim -e \ --headless \ - -u specs/minimal_init.vim \ - -c "PlenaryBustedDirectory specs/features {minimal_init = 'specs/minimal_init.vim'}" + --noplugin \ + -u specs/spec.lua \ + -c "PlenaryBustedDirectory specs/features {minimal_init = 'specs/spec.lua'}" + +luacheck: + luacheck . + +stylua: + stylua --check . + +lua-language-server: dependencies + rm -rf .ci/lua-language-server-log + lua-language-server --configpath .luarc.$(version).json --logpath .ci/lua-language-server-log --check . + @if jq -e 'if . | length > 0 then true else false end' .ci/lua-language-server-log/check.json > /dev/null; then \ + cat .ci/lua-language-server-log/check.json; \ + exit 1; \ + fi dependencies: - if [ ! -d vendor ]; then \ + if [ ! -d .ci/vendor ]; then \ git clone --depth 1 \ https://github.com/nvim-lua/plenary.nvim \ - vendor/pack/vendor/start/plenary.nvim; \ + .ci/vendor/pack/vendor/start/plenary.nvim; \ git clone --depth 1 \ - https://github.com/neovim/nvim-lspconfig \ - vendor/pack/vendor/start/nvim-lspconfig; \ + https://github.com/folke/neodev.nvim \ + .ci/vendor/pack/vendor/start/neodev.nvim; \ fi diff --git a/specs/features/main_spec.lua b/specs/features/main_spec.lua index 57494ce..a2c6fce 100644 --- a/specs/features/main_spec.lua +++ b/specs/features/main_spec.lua @@ -1,3 +1,4 @@ +assert = require "luassert" local mock = require "luassert.mock" local match = require "luassert.match" local spy = require "luassert.spy" @@ -12,10 +13,10 @@ local mock_client = { setup = function() end, } -vim.lsp.buf_get_clients = function() - local clients = {} - clients[mock_client.name] = mock_client - return clients +---@diagnostic disable-next-line +vim.lsp.get_clients = function(options) + f.buffers[options.bufnr] = { mock_client.id } + return { mock_client } end describe("lsp-format", function() @@ -25,7 +26,7 @@ describe("lsp-format", function() before_each(function() c = mock(mock_client, true) api = mock(vim.api) - c.supports_method = function(_) + c.supports_method = function(_, _) return true end f.setup {} @@ -38,7 +39,7 @@ describe("lsp-format", function() end) it("sends a valid format request", function() - f.format {} + f.format { buf = 1 } assert.stub(c.request).was_called(1) assert.stub(c.request).was_called_with("textDocument/formatting", { options = { @@ -48,26 +49,26 @@ describe("lsp-format", function() textDocument = { uri = "file://", }, - }, match.is_ref(f._handler), 1) + }, match.is_not_nil(), 1) end) it("FormatToggle prevent/allow formatting", function() f.toggle { args = "" } - f.format {} + f.format { buf = 1 } assert.stub(c.request).was_called(0) f.toggle { args = "" } - f.format {} + f.format { buf = 1 } assert.stub(c.request).was_called(1) end) it("FormatDisable/Enable prevent/allow formatting", function() f.disable { args = "" } - f.format {} + f.format { buf = 1 } assert.stub(c.request).was_called(0) f.enable { args = "" } - f.format {} + f.format { buf = 1 } assert.stub(c.request).was_called(1) end) @@ -80,7 +81,7 @@ describe("lsp-format", function() }, } vim.bo.filetype = "lua" - f.format {} + f.format { buf = 1 } assert.stub(c.request).was_called(1) assert.stub(c.request).was_called_with("textDocument/formatting", { options = { @@ -93,11 +94,12 @@ describe("lsp-format", function() textDocument = { uri = "file://", }, - }, match.is_ref(f._handler), 1) + }, match.is_not_nil(), 1) end) it("sends format options", function() f.format { + buf = 1, fargs = { "bool_test", "int_test=1", "string_test=string" }, } assert.stub(c.request).was_called(1) @@ -112,7 +114,7 @@ describe("lsp-format", function() textDocument = { uri = "file://", }, - }, match.is_ref(f._handler), 1) + }, match.is_not_nil(), 1) end) it("overwrites default format options", function() @@ -125,6 +127,7 @@ describe("lsp-format", function() } vim.bo.filetype = "lua" f.format { + buf = 1, fargs = { "bool_test=false", "int_test=2", "string_test=another_string" }, } assert.stub(c.request).was_called(1) @@ -139,7 +142,7 @@ describe("lsp-format", function() textDocument = { uri = "file://", }, - }, match.is_ref(f._handler), 1) + }, match.is_not_nil(), 1) end) it("does not overwrite changes", function() @@ -153,7 +156,7 @@ describe("lsp-format", function() end handler(nil, {}, { bufnr = bufnr, params = params }) end - f.format {} + f.format { buf = 1 } assert.spy(apply_text_edits).was.called(0) end) @@ -168,7 +171,7 @@ describe("lsp-format", function() end handler(nil, {}, { bufnr = bufnr, params = params }) end - f.format { fargs = { "force=true" } } + f.format { buf = 1, fargs = { "force=true" } } assert.spy(apply_text_edits).was.called(1) end) @@ -180,7 +183,7 @@ describe("lsp-format", function() end handler(nil, {}, { bufnr = bufnr, params = params }) end - f.format {} + f.format { buf = 1 } assert.spy(apply_text_edits).was.called(0) end) @@ -192,7 +195,7 @@ describe("lsp-format", function() end handler(nil, {}, { bufnr = bufnr, params = params }) end - f.format { fargs = { "force=true" } } + f.format { buf = 1, fargs = { "force=true" } } assert.spy(apply_text_edits).was.called(1) end) end) diff --git a/specs/minimal_init.vim b/specs/minimal_init.vim deleted file mode 100644 index 3507561..0000000 --- a/specs/minimal_init.vim +++ /dev/null @@ -1,13 +0,0 @@ -set rtp-=~/.config/nvim -set rtp-=~/.local/share/nvim/site -set rtp+=. -set noswapfile - -let $lsp_format = getcwd() -let $specs = getcwd() .. "/specs" -let $vendor = getcwd() .. "/vendor" - -set rtp+=$lsp_format,$specs -set packpath=$vendor - -packloadall diff --git a/specs/spec.lua b/specs/spec.lua new file mode 100644 index 0000000..a7281b5 --- /dev/null +++ b/specs/spec.lua @@ -0,0 +1,8 @@ +vim.api.nvim_command [[set rtp+=.]] + +vim.opt.swapfile = false +local cwd = vim.fn.getcwd() + +vim.api.nvim_command(string.format([[set rtp+=%s,%s/sepcs]], cwd, cwd)) +vim.api.nvim_command(string.format([[set packpath=%s/.ci/vendor]], cwd)) +vim.api.nvim_command [[packloadall]]