diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..f5b6057 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,54 @@ +name: CI + +on: + push: + branches: [main] + pull_request: + branches: [main] + +jobs: + test: + runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + neovim: ['v0.11.0', 'nightly'] + steps: + - uses: actions/checkout@v4 + + - name: Setup Neovim + uses: rhysd/action-setup-vim@v1 + with: + neovim: true + version: ${{ matrix.neovim }} + + - name: Install LuaRocks + run: sudo apt-get install -y luarocks + + - name: Install luacov + run: | + sudo luarocks install luacov + sudo luarocks install luacov-reporter-lcov + + - name: Clone plenary.nvim + run: | + mkdir -p ~/.local/share/nvim/site/pack/vendor/start + git clone --depth 1 https://github.com/nvim-lua/plenary.nvim \ + ~/.local/share/nvim/site/pack/vendor/start/plenary.nvim + + - name: Run tests + run: ./scripts/test.sh + + - name: Run tests with coverage + if: matrix.neovim == 'v0.11.0' + env: + LUA_PATH: '/usr/local/share/lua/5.1/?.lua;/usr/local/share/lua/5.1/?/init.lua;;' + LUA_CPATH: '/usr/local/lib/lua/5.1/?.so;;' + run: ./scripts/test-coverage.sh + + - name: Upload coverage to Codecov + if: matrix.neovim == 'v0.11.0' + uses: codecov/codecov-action@v5 + with: + files: ./lcov.info + fail_ci_if_error: false diff --git a/.luacov b/.luacov new file mode 100644 index 0000000..d0cbe15 --- /dev/null +++ b/.luacov @@ -0,0 +1,9 @@ +return { + include = { + "lua/shelltime/.+%.lua$", + }, + exclude = { + "tests/", + "plugin/", + }, +} diff --git a/scripts/test-coverage.sh b/scripts/test-coverage.sh new file mode 100755 index 0000000..6e409e0 --- /dev/null +++ b/scripts/test-coverage.sh @@ -0,0 +1,29 @@ +#!/bin/bash +# Run tests with code coverage using luacov +# Requires: luacov, luacov-reporter-lcov installed via luarocks + +set -e + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +PROJECT_DIR="$(dirname "$SCRIPT_DIR")" + +cd "$PROJECT_DIR" + +# Clean previous coverage data +rm -f luacov.stats.out luacov.report.out lcov.info + +# Run tests with coverage init (loads luacov before test code) +nvim --headless \ + -u "$PROJECT_DIR/tests/coverage_init.lua" \ + -c "PlenaryBustedDirectory tests/ {minimal_init = 'tests/coverage_init.lua'}" \ + 2>&1 || true + +# Generate lcov report for Codecov +if [ -f luacov.stats.out ]; then + luacov -r lcov -o lcov.info + echo "Coverage report generated: lcov.info" +else + echo "Warning: No coverage stats generated (luacov may not be installed)" + # Don't fail CI if coverage isn't available + exit 0 +fi diff --git a/tests/coverage_init.lua b/tests/coverage_init.lua new file mode 100644 index 0000000..e37c1e6 --- /dev/null +++ b/tests/coverage_init.lua @@ -0,0 +1,23 @@ +-- Coverage init for running tests with luacov +-- This file wraps minimal_init.lua and adds luacov support + +-- Initialize luacov BEFORE loading any other modules +local ok, luacov = pcall(require, 'luacov') +if not ok then + print('Warning: luacov not found, running tests without coverage') +end + +-- Load the regular minimal init +local script_path = debug.getinfo(1, 'S').source:sub(2) +local tests_dir = vim.fn.fnamemodify(script_path, ':h') +dofile(tests_dir .. '/minimal_init.lua') + +-- Save coverage stats on exit +vim.api.nvim_create_autocmd('VimLeavePre', { + callback = function() + if ok and luacov then + local runner = require('luacov.runner') + runner.save_stats() + end + end, +}) diff --git a/tests/minimal_init.lua b/tests/minimal_init.lua index 2cdb591..0e26b4d 100644 --- a/tests/minimal_init.lua +++ b/tests/minimal_init.lua @@ -5,7 +5,11 @@ local plugin_dir = vim.fn.fnamemodify(debug.getinfo(1, 'S').source:sub(2), ':h:h') vim.opt.rtp:prepend(plugin_dir) --- Add tests directory to package path for helpers +-- Add project root to package path for 'tests.helpers' requires +package.path = plugin_dir .. '/?.lua;' .. package.path +package.path = plugin_dir .. '/?/init.lua;' .. package.path + +-- Add tests directory to package path for 'helpers' requires package.path = plugin_dir .. '/tests/?.lua;' .. package.path package.path = plugin_dir .. '/tests/?/init.lua;' .. package.path