feat(typecheck): add local mode mirroring github to lua-typecheck.sh

This implements mode mirroring github workflow in scripts/lua-typecheck.sh
so that it can run locally.

A supporting script scripts/setup_deps.sh is created to define and
download/clone dependencies (plugins), as well as download luals, neovim
runtime, and create luarc.json. setup_deps.sh is now the only and
authoritative source of dependencies and luals version. Neovim version
still comes from lua.yaml.

To fetch neovim version from lua.yaml as well as figure out the right
source of neovim package, dependency on yq is introduced when running
locally in "managed" mode.

Dependencies, neovim runtime, and luals are downloaded to
target/tests subdirectory on local machine. luarc.json is created
from a template there as well.

The ability to run against the live system is preserved with "--live"
option. In this case it assumes that neovim is using lazy package
manager and optionally Mason, so if luals is not present in path the
script will try to see if it is installed by Mason.

When running in github CI neovim is set up through github action while
dependencies and luals are handled by the scripts.
This commit is contained in:
Dmitry Torokhov
2025-07-30 14:21:10 -07:00
committed by yetone
parent 6d372a9135
commit 59a518cf86
6 changed files with 346 additions and 71 deletions

View File

@@ -1,30 +0,0 @@
{
"$schema": "https://raw.githubusercontent.com/sumneko/vscode-lua/master/setting/schema.json",
"runtime": {
"version": "LuaJIT",
"pathStrict": true
},
"workspace": {
"library": [
"$VIMRUNTIME/lua",
"$VIMRUNTIME/lua/vim/lsp",
"$PWD/lua",
"${3rd}/luv/library",
"$DEPS_PATH/lazy.nvim/lua",
"$DEPS_PATH/dressing.nvim/lua",
"$DEPS_PATH/snacks.nvim/lua",
"$DEPS_PATH/plenary.nvim/lua",
"$DEPS_PATH/nui.nvim/lua",
"$DEPS_PATH/mini.pick/lua",
"$DEPS_PATH/telescope.nvim/lua",
"$DEPS_PATH/nvim-cmp/lua",
"$DEPS_PATH/fzf-lua/lua",
"$DEPS_PATH/nvim-web-devicons/lua",
"$DEPS_PATH/copilot.lua/lua"
],
"ignoreDir": [
"/lua"
],
"checkThirdParty": false
}
}

View File

@@ -69,38 +69,8 @@ jobs:
neovim: true
version: ${{ matrix.nvim_version }}
- name: Install luals
run: |
mkdir -p luals
curl -L "https://github.com/LuaLS/lua-language-server/releases/download/${{ matrix.luals_version }}/lua-language-server-${{ matrix.luals_version }}-linux-x64.tar.gz" | tar zx --directory luals
- run: echo "luals/bin" >> "$GITHUB_PATH"
- name: Checkout dependencies
run: |
mkdir -p deps
DEPS=(
"folke/neodev.nvim"
"nvim-lua/plenary.nvim"
"MunifTanjim/nui.nvim"
"stevearc/dressing.nvim"
"folke/snacks.nvim"
"echasnovski/mini.nvim"
"nvim-telescope/telescope.nvim"
"hrsh7th/nvim-cmp"
"ibhagwan/fzf-lua"
"nvim-tree/nvim-web-devicons"
"zbirenbaum/copilot.lua"
"folke/lazy.nvim"
)
for dep in "${DEPS[@]}"; do
repo_name=$(echo $dep | cut -d'/' -f2)
git clone --depth 1 "https://github.com/${dep}.git" "deps/${repo_name}"
done
- name: Typecheck
env:
VIMRUNTIME: /home/runner/nvim-${{ matrix.nvim_version }}/share/nvim/runtime
DEPS_PATH: /home/runner/work/avante.nvim/avante.nvim/deps/
run: |
make lua-typecheck

View File

@@ -102,7 +102,7 @@ lint: luacheck luastylecheck ruststylecheck rustlint
.PHONY: lua-typecheck
lua-typecheck:
bash ./scripts/lua-typecheck.sh
@./scripts/lua-typecheck.sh
.PHONY: build-image
build-image:

21
luarc.json.template Normal file
View File

@@ -0,0 +1,21 @@
{
"$schema": "https://raw.githubusercontent.com/sumneko/vscode-lua/master/setting/schema.json",
"runtime": {
"version": "LuaJIT",
"pathStrict": true
},
"workspace": {
"library": [
"$VIMRUNTIME/lua",
"$VIMRUNTIME/lua/vim/lsp",
"$PWD/lua",
"${3rd}/luv/library",
"$DEPS_PATH/luvit-meta/library"
{{DEPS}}
],
"ignoreDir": [
"/lua"
],
"checkThirdParty": false
}
}

View File

@@ -1,15 +1,142 @@
#!/bin/env bash
#!/usr/bin/env bash
set -e
if [ -z "${VIMRUNTIME}" ]; then
export VIMRUNTIME=$(nvim --headless --noplugin -u NONE -c "echo \$VIMRUNTIME" +qa 2>&1)
fi
# This script performs a Lua typecheck, with different behaviors for local and CI environments.
#
# It supports two local modes:
# 1. Default (Managed): Downloads all dependencies into a project-local ./target/deps directory.
# 2. --live: Uses the system's installed `nvim` and `lua-language-server`. It does not
# manage plugin dependencies, assuming the user has them configured.
echo "VIMRUNTIME: ${VIMRUNTIME}"
verbose=false
if [ -z "${DEPS_PATH}" ]; then
export DEPS_PATH=${HOME}/.local/share/nvim/lazy/
fi
log() {
echo "$1" >&2
}
echo "DEPS_PATH: ${DEPS_PATH}"
log_verbose() {
if [ "$verbose" = "true" ]; then
echo "$1" >&2
fi
}
lua-language-server --check=${PWD}/lua --configpath=${PWD}/.github/workflows/.luarc.json --checklevel=Information
die() {
echo "Error: $1" >&2
exit 1
}
handle_live_mode() {
export DEPS_PATH="$HOME/.local/share/nvim/lazy"
log_verbose "Setting DEPS_PATH for live mode to: $DEPS_PATH"
command -v nvim &>/dev/null || die "nvim command not found. Please install Neovim."
if command -v lua-language-server &>/dev/null; then
log_verbose "Found lua-language-server in PATH."
else
log_verbose "lua-language-server not found in PATH. Checking Mason..."
local mason_luals_path="$HOME/.local/share/nvim/mason/bin/lua-language-server"
if [ -x "$mason_luals_path" ]; then
log_verbose "Found lua-language-server in Mason packages."
export PATH="$HOME/.local/share/nvim/mason/bin:$PATH"
else
die "lua-language-server not found in PATH or in Mason packages. Please install it."
fi
fi
# $VIMRUNTIME is not supposed to be expanded below
# shellcheck disable=SC2016
VIMRUNTIME="$(nvim --headless --noplugin -u NONE -c 'echo $VIMRUNTIME' +qa 2>&1)"
export VIMRUNTIME
}
manage_plugin_dependencies() {
local deps_dir=$1
local setup_deps_flags=$2
log "Cloning/updating dependencies to $deps_dir..."
./scripts/setup-deps.sh "$setup_deps_flags" clone "$deps_dir"
export DEPS_PATH="$deps_dir"
log_verbose "Set DEPS_PATH to $DEPS_PATH"
}
run_typechecker() {
local config_path=$1
if [ -z "$VIMRUNTIME" ]; then
die "VIMRUNTIME is not set. Cannot proceed."
fi
if [ -z "$config_path" ]; then
die "Luarc config path is not set. Cannot proceed."
fi
command -v lua-language-server &>/dev/null || die "lua-language-server not found in PATH."
log "Running Lua typechecker..."
lua-language-server --check="$PWD/lua" \
--loglevel=trace \
--configpath="$config_path" \
--checklevel=Information
log_verbose "Typecheck complete."
}
main() {
local dest_dir="$PWD/target/tests"
local luarc_path="$dest_dir/luarc.json"
local mode="managed"
local setup_deps_flags=""
for arg in "$@"; do
case $arg in
--live)
mode="live"
shift
;;
--verbose|-v)
verbose=true
setup_deps_flags="--verbose"
shift
;;
esac
done
if [ "$GITHUB_ACTIONS" = "true" ]; then
mode="ci"
# Always be verbose in CI
setup_deps_flags="--verbose"
fi
log "mode: $mode"
if [ "$mode" == "live" ]; then
handle_live_mode
else
log "Setting up environment in: $dest_dir"
mkdir -p "$dest_dir"
if [ "$mode" == "managed" ]; then
log "Installing nvim runtime..."
VIMRUNTIME="$(./scripts/setup-deps.sh "$setup_deps_flags" install-nvim "$dest_dir")"
export VIMRUNTIME
log_verbose "Installed nvim runtime at: $VIMRUNTIME"
fi
log "Installing lua-language-server..."
local luals_bin_path
luals_bin_path="$(./scripts/setup-deps.sh "$setup_deps_flags" install-luals "$dest_dir")"
export PATH="$luals_bin_path:$PATH"
log_verbose "Added $luals_bin_path to PATH"
local deps_dir="$dest_dir/deps"
log "Cloning/updating dependencies to $deps_dir..."
./scripts/setup-deps.sh "$setup_deps_flags" clone "$deps_dir"
export DEPS_PATH="$deps_dir"
log_verbose "Set DEPS_PATH to $DEPS_PATH"
fi
./scripts/setup-deps.sh $setup_deps_flags generate-luarc "$luarc_path"
log "VIMRUNTIME: $VIMRUNTIME"
log "DEPS_PATH: $DEPS_PATH"
run_typechecker "$luarc_path"
}
main "$@"

187
scripts/setup-deps.sh Executable file
View File

@@ -0,0 +1,187 @@
#!/bin/bash
DEPS=(
"folke/neodev.nvim"
"nvim-lua/plenary.nvim"
"MunifTanjim/nui.nvim"
"stevearc/dressing.nvim"
"folke/snacks.nvim"
"echasnovski/mini.nvim"
"nvim-telescope/telescope.nvim"
"hrsh7th/nvim-cmp"
"ibhagwan/fzf-lua"
"nvim-tree/nvim-web-devicons"
"zbirenbaum/copilot.lua"
"folke/lazy.nvim"
)
LUALS_VERSION="3.13.6"
verbose=false
log() {
echo "$1" >&2
}
log_verbose() {
if [ "$verbose" = "true" ]; then
echo "$1" >&2
fi
}
clone_deps() {
local deps_dir=${1:-"$PWD/deps"}
log_verbose "Cloning dependencies into: $deps_dir"
mkdir -p "$deps_dir"
for dep in "${DEPS[@]}"; do
repo_name="$(echo "$dep" | cut -d'/' -f2)"
local repo_path="$deps_dir/$repo_name"
if [ -d "$repo_path/.git" ]; then
log_verbose "Updating existing repository: $repo_path"
(
cd "$repo_path"
git fetch -q
if git show-ref --verify --quiet refs/remotes/origin/main; then
git reset -q --hard origin/main
elif git show-ref --verify --quiet refs/remotes/origin/master; then
git reset -q --hard origin/master
else
log "Could not find main or master branch for $repo_name"
fi
)
else
if [ -d "$repo_path" ]; then
log_verbose "Directory '$repo_path' exists but is not a git repository. Removing and re-cloning."
rm -rf "$repo_path"
fi
log_verbose "Cloning new repository: $dep to $repo_path"
git clone -q --depth 1 "https://github.com/${dep}.git" "$repo_path"
fi
done
}
install_luals() {
local dest_dir=${1:-"$PWD/target/tests"}
local luals_url_template="https://github.com/LuaLS/lua-language-server/releases/download/__VERSION__/lua-language-server-__VERSION__-linux-x64.tar.gz"
local luals_download_url="${luals_url_template//__VERSION__/$LUALS_VERSION}"
local luals_dir="$dest_dir/lua-language-server-${LUALS_VERSION}"
if [ ! -d "$luals_dir" ]; then
log "Installing lua-language-server ${LUALS_VERSION}..."
mkdir -p "$luals_dir"
curl -sSL "${luals_download_url}" | tar zx --directory "$luals_dir"
else
log_verbose "lua-language-server is already installed in $luals_dir"
fi
echo "$luals_dir/bin"
}
install_nvim_runtime() {
local dest_dir=${1:-"$PWD/target/tests"}
command -v yq &>/dev/null || die "yq is not installed for parsing GitHub API responses."
local nvim_version
nvim_version="$(yq -r '.jobs.typecheck.strategy.matrix.nvim_version[0]' .github/workflows/lua.yaml)"
log_verbose "Parsed nvim version from workflow: $nvim_version"
log_verbose "Resolving ${nvim_version} Neovim release from GitHub API..."
local api_url="https://api.github.com/repos/neovim/neovim/releases"
if [ "$nvim_version" == "stable" ]; then
api_url="$api_url/latest"
else
api_url="$api_url/tags/${nvim_version}"
fi
local release_data
release_data="$(curl -s "$api_url")"
if [ -z "$release_data" ] || echo "$release_data" | yq -e '.message == "Not Found"' > /dev/null; then
die "Failed to fetch release data from GitHub API for version '${nvim_version}'."
fi
# Find the correct asset by regex and extract its name and download URL.
local asset_info
asset_info="$(echo "$release_data" | \
yq -r '.assets[] | select(.name | test("nvim-linux(64|-x86_64)\\.tar\\.gz$")) | .name + " " + .browser_download_url')"
if [ -z "$asset_info" ]; then
die "Could not find a suitable linux tarball asset for version '${nvim_version}'."
fi
local asset_name
local download_url
read -r asset_name download_url <<< "$asset_info"
local actual_version
actual_version="$(echo "$download_url" | grep -E -o 'v[0-9]+\.[0-9]+\.[0-9]+' | head -n 1)"
if [ -z "$actual_version" ]; then
die "Could not resolve a version tag from URL: $download_url"
fi
log_verbose "Resolved Neovim version is ${actual_version}"
local runtime_dir="$dest_dir/nvim-${actual_version}-runtime"
if [ ! -d "$runtime_dir" ]; then
log "Installing Neovim runtime (${actual_version})..."
mkdir -p "$runtime_dir"
curl -sSL "${download_url}" | \
tar xzf - -C "$runtime_dir" --strip-components=4 \
"${asset_name%.tar.gz}/share/nvim/runtime"
else
log_verbose "Neovim runtime (${actual_version}) is already installed"
fi
echo "$runtime_dir"
}
generate_luarc() {
local luarc_path=${1:-"$PWD/target/tests/luarc.json"}
local luarc_template="luarc.json.template"
log_verbose "Generating luarc file at: $luarc_path"
mkdir -p "$(dirname "$luarc_path")"
local lua_deps=""
for dep in "${DEPS[@]}"; do
repo_name="$(echo "$dep" | cut -d'/' -f2)"
lua_deps="${lua_deps},\n \"\$DEPS_PATH/${repo_name}/lua\""
done
sed "s#{{DEPS}}#${lua_deps}#" "$luarc_template" > "$luarc_path"
}
main() {
local command=""
local args=()
# Manual parsing for flags and command
while [[ $# -gt 0 ]]; do
case $1 in
-v|--verbose)
verbose=true
shift
;;
*)
if [ -z "$command" ]; then
command=$1
else
args+=("$1")
fi
shift
;;
esac
done
if [ "$command" == "clone" ]; then
clone_deps "${args[@]}"
elif [ "$command" == "generate-luarc" ]; then
generate_luarc "${args[@]}"
elif [ "$command" == "install-luals" ]; then
install_luals "${args[@]}"
elif [ "$command" == "install-nvim" ]; then
install_nvim_runtime "${args[@]}"
else
echo "Usage: $0 [-v|--verbose] {clone [dir]|generate-luarc [path]|install-luals [dir]|install-nvim [dir]}"
exit 1
fi
}
main "$@"