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:
30
.github/workflows/.luarc.json
vendored
30
.github/workflows/.luarc.json
vendored
@@ -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
|
||||
}
|
||||
}
|
||||
30
.github/workflows/lua.yaml
vendored
30
.github/workflows/lua.yaml
vendored
@@ -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
|
||||
|
||||
2
Makefile
2
Makefile
@@ -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
21
luarc.json.template
Normal 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
|
||||
}
|
||||
}
|
||||
@@ -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
187
scripts/setup-deps.sh
Executable 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 "$@"
|
||||
Reference in New Issue
Block a user