From ee4bcb77c1c0c5725569c0cf740a2b2074f80c6a Mon Sep 17 00:00:00 2001 From: Harrison Cramer Date: Fri, 16 Oct 2026 16:25:52 -0400 Subject: [PATCH 01/14] fix: load git-helpers after plugins install --- lua/plugins/diffview.lua | 3 ++- lua/plugins/snacks/changed-files.lua | 3 +-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/lua/plugins/diffview.lua b/lua/plugins/diffview.lua index eed55fc..ddc50cb 100644 --- a/lua/plugins/diffview.lua +++ b/lua/plugins/diffview.lua @@ -5,7 +5,6 @@ local M = { vim.opt.fillchars:append({ diff = "╱" }) local actions = require("diffview.actions") local diffview = require("diffview") - local git_helpers = require("git-helpers") -- Diffview changes. Can be used to stage/unstage files. vim.keymap.set("n", "gs", function() @@ -30,6 +29,7 @@ local M = { -- View entire changes versus a specific branch. vim.keymap.set("n", "gdd", function() + local git_helpers = require("git-helpers") git_helpers.branch_input(function(branch) vim.cmd(string.format("DiffviewOpen origin/%s...HEAD -- %s", branch, git_helpers.ignore_paths)) end) @@ -394,6 +394,7 @@ local M = { "n", "go", function() + local git_helpers = require("git-helpers") local hash = git_helpers.get_hash() if hash == nil then return diff --git a/lua/plugins/snacks/changed-files.lua b/lua/plugins/snacks/changed-files.lua index af13c15..d5c8fd6 100644 --- a/lua/plugins/snacks/changed-files.lua +++ b/lua/plugins/snacks/changed-files.lua @@ -1,5 +1,3 @@ -local git_helpers = require("../../git-helpers") - local ChangedFiles = {} ChangedFiles.__index = ChangedFiles @@ -24,6 +22,7 @@ function ChangedFiles:formatted() end function ChangedFiles:get_all() + local git_helpers = require("../../git-helpers") self.all_files = git_helpers.changed_files(self.branch) return self.all_files end From 87027391e4593f0d974229072b8aa130fe168d08 Mon Sep 17 00:00:00 2001 From: Harrison Cramer Date: Fri, 16 Oct 2026 16:25:52 -0400 Subject: [PATCH 02/14] ci: add Ubuntu ARM64 fresh install check --- check-linux | 8 +++++ ci/Dockerfile | 50 ++++++++++++++++++++++++++ ci/check-start | 7 ++++ ci/check-start.lua | 88 ++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 153 insertions(+) create mode 100755 check-linux create mode 100644 ci/Dockerfile create mode 100755 ci/check-start create mode 100644 ci/check-start.lua diff --git a/check-linux b/check-linux new file mode 100755 index 0000000..a154c41 --- /dev/null +++ b/check-linux @@ -0,0 +1,8 @@ +#!/usr/bin/env bash +set -euo pipefail + +cd "$(dirname "$0")" + +docker build --platform linux/arm64 -t nvim-linux-check ci +docker run --rm --platform linux/arm64 -v "$PWD:/src:ro" nvim-linux-check \ + bash -c 'mkdir -p ~/.config && cp -R /src ~/.config/nvim && cd ~/.config/nvim && ./check-tools && ci/check-start' diff --git a/ci/Dockerfile b/ci/Dockerfile new file mode 100644 index 0000000..cfcec69 --- /dev/null +++ b/ci/Dockerfile @@ -0,0 +1,50 @@ +FROM ubuntu:24.04 + +ARG NVIM_VERSION=0.12.4 +ARG NVIM_SHA256=ceb7e88c6b681f0515d135dcdfad54f5eb4373b25ce6172197cd9a69c758063f +ARG TREE_SITTER_VERSION=0.26.9 +ARG TREE_SITTER_SHA256=c8feeb32115958cb44442ca4d68f6d66cf7605dbd65681e62342181ebdd6db3b +ARG NODE_VERSION=24.18.0 +ARG NODE_SHA256=6b4484c2190274175df9aa8f28e2d758a819cb1c1fe6ab481e2f95b463ab8508 +ARG GO_VERSION=1.26.4 +ARG GO_SHA256=ef758ae7c6cf9267c9c0ef080b8965f453d89ab2d25d9eb22de4405925238768 +ARG GOLANGCI_LINT_VERSION=2.12.2 +ARG GOLANGCI_LINT_SHA256=44cd40a8c76c86755375adfeea52cfd3533cb43d7bd647771e0ae065e166df3a + +RUN apt-get update \ + && apt-get install -y --no-install-recommends ca-certificates git curl unzip build-essential ripgrep \ + && rm -rf /var/lib/apt/lists/* + +RUN curl -fsSLo /tmp/nvim.tar.gz "https://github.com/neovim/neovim/releases/download/v${NVIM_VERSION}/nvim-linux-arm64.tar.gz" \ + && echo "${NVIM_SHA256} /tmp/nvim.tar.gz" | sha256sum -c - \ + && tar -xzf /tmp/nvim.tar.gz -C /opt \ + && ln -s /opt/nvim-linux-arm64/bin/nvim /usr/local/bin/nvim \ + && rm /tmp/nvim.tar.gz + +RUN curl -fsSLo /tmp/tree-sitter.gz "https://github.com/tree-sitter/tree-sitter/releases/download/v${TREE_SITTER_VERSION}/tree-sitter-linux-arm64.gz" \ + && echo "${TREE_SITTER_SHA256} /tmp/tree-sitter.gz" | sha256sum -c - \ + && gunzip -c /tmp/tree-sitter.gz > /usr/local/bin/tree-sitter \ + && chmod +x /usr/local/bin/tree-sitter \ + && rm /tmp/tree-sitter.gz + +RUN curl -fsSLo /tmp/node.tar.gz "https://nodejs.org/dist/v${NODE_VERSION}/node-v${NODE_VERSION}-linux-arm64.tar.gz" \ + && echo "${NODE_SHA256} /tmp/node.tar.gz" | sha256sum -c - \ + && mkdir /opt/node \ + && tar -xzf /tmp/node.tar.gz -C /opt/node --strip-components=1 \ + && rm /tmp/node.tar.gz + +RUN curl -fsSLo /tmp/go.tar.gz "https://go.dev/dl/go${GO_VERSION}.linux-arm64.tar.gz" \ + && echo "${GO_SHA256} /tmp/go.tar.gz" | sha256sum -c - \ + && tar -xzf /tmp/go.tar.gz -C /usr/local \ + && rm /tmp/go.tar.gz + +RUN curl -fsSLo /tmp/golangci-lint.tar.gz "https://github.com/golangci/golangci-lint/releases/download/v${GOLANGCI_LINT_VERSION}/golangci-lint-${GOLANGCI_LINT_VERSION}-linux-arm64.tar.gz" \ + && echo "${GOLANGCI_LINT_SHA256} /tmp/golangci-lint.tar.gz" | sha256sum -c - \ + && tar -xzf /tmp/golangci-lint.tar.gz -C /usr/local/bin --strip-components=1 "golangci-lint-${GOLANGCI_LINT_VERSION}-linux-arm64/golangci-lint" \ + && rm /tmp/golangci-lint.tar.gz + +ENV PATH=/opt/node/bin:/usr/local/go/bin:$PATH + +RUN mkdir -p /var/lib/komrad && useradd --create-home --home-dir /var/lib/komrad/home komrad +USER komrad +WORKDIR /var/lib/komrad/home diff --git a/ci/check-start b/ci/check-start new file mode 100755 index 0000000..beb0025 --- /dev/null +++ b/ci/check-start @@ -0,0 +1,7 @@ +#!/usr/bin/env bash +set -euo pipefail + +check="$(cd "$(dirname "$0")" && pwd)/check-start.lua" + +nvim --headless --cmd "luafile $check" "+Lazy! restore" +nvim --headless --cmd "luafile $check" diff --git a/ci/check-start.lua b/ci/check-start.lua new file mode 100644 index 0000000..659b191 --- /dev/null +++ b/ci/check-start.lua @@ -0,0 +1,88 @@ +local timeout_ms = 20 * 60 * 1000 + +local failures = {} +local treesitter_pending = 0 +local mason_done = false + +local function load_without_preload(name) + for i = 2, #package.loaders do + local loader = package.loaders[i](name) + if type(loader) == "function" then + return loader(name) + end + end + error("module not found: " .. name) +end + +package.preload["nvim-treesitter"] = function(name) + local mod = load_without_preload(name) + local install = mod.install + mod.install = function(...) + local task = install(...) + treesitter_pending = treesitter_pending + 1 + task:await(function(err, ok) + treesitter_pending = treesitter_pending - 1 + if err or not ok then + table.insert(failures, "treesitter install failed: " .. tostring(err or "see messages")) + end + end) + return task + end + return mod +end + +vim.api.nvim_create_autocmd("User", { + pattern = "MasonToolsUpdateCompleted", + once = true, + callback = function() + mason_done = true + end, +}) + +local function errors() + local found = vim.list_extend({}, failures) + local messages = vim.fn.execute("messages") + if messages:match("E%d+:") or messages:match("[Ee]rror") or messages:match("stack traceback") then + table.insert(found, vim.trim(messages)) + end + local ok, snacks = pcall(require, "snacks") + if ok and snacks.notifier then + for _, n in ipairs(snacks.notifier.get_history()) do + if n.level == "error" then + table.insert(found, n.msg) + end + end + end + return found +end + +local function settled() + return (mason_done and treesitter_pending == 0) or #errors() > 0 +end + +local function finish() + local found = errors() + if not mason_done then + table.insert(found, "Mason installs did not finish") + end + if treesitter_pending > 0 then + table.insert(found, "treesitter installs did not finish") + end + if #found == 0 then + io.stdout:write("nvim started clean\n") + vim.cmd("qall!") + else + io.stdout:write("nvim started with errors:\n" .. table.concat(found, "\n") .. "\n") + vim.cmd("cquit 1") + end +end + +vim.api.nvim_create_autocmd("VimEnter", { + once = true, + callback = function() + vim.schedule(function() + vim.wait(timeout_ms, settled, 500) + vim.defer_fn(finish, 1000) + end) + end, +}) From fd729463bec7fb6b1f6d546cfaa48474e51aa31d Mon Sep 17 00:00:00 2001 From: Harrison Cramer Date: Fri, 16 Oct 2026 16:25:52 -0400 Subject: [PATCH 03/14] ci: run fresh install check in GitHub Actions --- .github/workflows/check.yml | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) create mode 100644 .github/workflows/check.yml diff --git a/.github/workflows/check.yml b/.github/workflows/check.yml new file mode 100644 index 0000000..b324c41 --- /dev/null +++ b/.github/workflows/check.yml @@ -0,0 +1,17 @@ +name: check + +on: + pull_request: + push: + branches: [main] + +permissions: + contents: read + +jobs: + linux: + runs-on: ubuntu-24.04-arm + timeout-minutes: 30 + steps: + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + - run: ./check-linux From c190ce90a24cf9232f84cd744a5e804488497949 Mon Sep 17 00:00:00 2001 From: Harrison Cramer Date: Fri, 16 Oct 2026 16:25:52 -0400 Subject: [PATCH 04/14] docs: describe the Linux check --- README.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/README.md b/README.md index 64a6ef8..2d1f920 100644 --- a/README.md +++ b/README.md @@ -25,6 +25,10 @@ Run `./check-tools` to see what is missing or too old. It never installs anythin A few commands shell out to optional programs that the editor can start without. When one is missing, the command that needs it shows a warning and does nothing. +# Linux check + +Run `./check-linux` to prove a fresh install works on Ubuntu 24.04 ARM64. It needs Docker. It builds an image with Neovim and the required programs, restores the plugins from lazy-lock.json, and waits for the Mason and treesitter installs to finish. It fails if Neovim reports an error then or on a second start. The image leaves out the optional programs, so the check also proves the editor starts without them. CI runs the same check on every pull request. + # Quickstart 1. Clone this repository to your Neovim configuration path: `git clone https://github.com/harrisoncramer/nvim.git ~/.config/nvim` From fe607b7fbde13b432c3c95e3b93d0b8a843370de Mon Sep 17 00:00:00 2001 From: Harrison Cramer Date: Fri, 16 Oct 2026 16:34:00 -0400 Subject: [PATCH 05/14] ci: pin Ubuntu base image digest --- ci/Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ci/Dockerfile b/ci/Dockerfile index cfcec69..c3cb5a7 100644 --- a/ci/Dockerfile +++ b/ci/Dockerfile @@ -1,4 +1,4 @@ -FROM ubuntu:24.04 +FROM ubuntu:24.04@sha256:534baea6a22c03a63003dbc8dbe78fe34bc0d7e595d9a9dc9834884ff530eb55 ARG NVIM_VERSION=0.12.4 ARG NVIM_SHA256=ceb7e88c6b681f0515d135dcdfad54f5eb4373b25ce6172197cd9a69c758063f From 6551c49d27bc28957f0993d08755178039021cfc Mon Sep 17 00:00:00 2001 From: Harrison Cramer Date: Fri, 16 Oct 2026 16:36:23 -0400 Subject: [PATCH 06/14] fix(bqf): build fzf with its install script --- lua/plugins/bqf/init.lua | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/lua/plugins/bqf/init.lua b/lua/plugins/bqf/init.lua index bea82b8..38f5df2 100644 --- a/lua/plugins/bqf/init.lua +++ b/lua/plugins/bqf/init.lua @@ -58,9 +58,7 @@ return { dependencies = { { "junegunn/fzf", - build = function() - vim.fn["fzf#install"]() - end, + build = "./install --bin", }, }, config = { From d8875c92b7307496b370ae41a3f78d181868602f Mon Sep 17 00:00:00 2001 From: Harrison Cramer Date: Fri, 16 Oct 2026 16:36:23 -0400 Subject: [PATCH 07/14] ci: fail on lazy install and build errors --- ci/check-start.lua | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/ci/check-start.lua b/ci/check-start.lua index 659b191..85f3466 100644 --- a/ci/check-start.lua +++ b/ci/check-start.lua @@ -39,8 +39,27 @@ vim.api.nvim_create_autocmd("User", { end, }) +local function lazy_failures() + local found = {} + local ok, config = pcall(require, "lazy.core.config") + if not ok then + return found + end + for name, plugin in pairs(config.plugins) do + if not plugin.virtual and not plugin._.installed then + table.insert(found, name .. " is not installed") + end + for _, task in ipairs(plugin._.tasks or {}) do + if task:has_errors() then + table.insert(found, name .. " " .. task.name .. " failed: " .. task:output(vim.log.levels.ERROR)) + end + end + end + return found +end + local function errors() - local found = vim.list_extend({}, failures) + local found = vim.list_extend(lazy_failures(), failures) local messages = vim.fn.execute("messages") if messages:match("E%d+:") or messages:match("[Ee]rror") or messages:match("stack traceback") then table.insert(found, vim.trim(messages)) From 637c8c8881fcdbc6780c673344e75c80fdb371a0 Mon Sep 17 00:00:00 2001 From: Harrison Cramer Date: Fri, 16 Oct 2026 16:39:32 -0400 Subject: [PATCH 08/14] ci: record errors reported through the nvim API --- ci/check-start.lua | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/ci/check-start.lua b/ci/check-start.lua index 85f3466..a075421 100644 --- a/ci/check-start.lua +++ b/ci/check-start.lua @@ -4,6 +4,28 @@ local failures = {} local treesitter_pending = 0 local mason_done = false +local function record(msg) + table.insert(failures, vim.trim(tostring(msg))) +end + +for _, name in ipairs({ "nvim_err_write", "nvim_err_writeln" }) do + local original = vim.api[name] + vim.api[name] = function(msg) + record(msg) + return original(msg) + end +end + +local echo = vim.api.nvim_echo +vim.api.nvim_echo = function(chunks, history, opts) + if opts and opts.err then + record(table.concat(vim.tbl_map(function(chunk) + return chunk[1] + end, chunks))) + end + return echo(chunks, history, opts) +end + local function load_without_preload(name) for i = 2, #package.loaders do local loader = package.loaders[i](name) From 4d282f850a93148e5298dac2986e32867dc67f19 Mon Sep 17 00:00:00 2001 From: Harrison Cramer Date: Fri, 16 Oct 2026 16:43:14 -0400 Subject: [PATCH 09/14] fix(bqf): fail the fzf build when its install script fails --- lua/plugins/bqf/init.lua | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/lua/plugins/bqf/init.lua b/lua/plugins/bqf/init.lua index 38f5df2..bce7793 100644 --- a/lua/plugins/bqf/init.lua +++ b/lua/plugins/bqf/init.lua @@ -58,7 +58,12 @@ return { dependencies = { { "junegunn/fzf", - build = "./install --bin", + build = function(plugin) + local result = vim.system({ "./install", "--bin" }, { cwd = plugin.dir }):wait() + if result.code ~= 0 then + error(result.stdout .. result.stderr) + end + end, }, }, config = { From d3b2695f82e91f83df1097c109b7039dd043fc57 Mon Sep 17 00:00:00 2001 From: Harrison Cramer Date: Fri, 16 Oct 2026 16:48:21 -0400 Subject: [PATCH 10/14] refactor(ci): simplify check-start hook path --- ci/check-start | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/ci/check-start b/ci/check-start index beb0025..414e0d6 100755 --- a/ci/check-start +++ b/ci/check-start @@ -1,7 +1,7 @@ #!/usr/bin/env bash set -euo pipefail -check="$(cd "$(dirname "$0")" && pwd)/check-start.lua" +hook="$(dirname "$0")/check-start.lua" -nvim --headless --cmd "luafile $check" "+Lazy! restore" -nvim --headless --cmd "luafile $check" +nvim --headless --cmd "luafile $hook" "+Lazy! restore" +nvim --headless --cmd "luafile $hook" From 4969ed9693cd6e78971cff025cd0546d988dc53a Mon Sep 17 00:00:00 2001 From: Harrison Cramer Date: Fri, 16 Oct 2026 16:49:00 -0400 Subject: [PATCH 11/14] refactor(ci): record treesitter failures through record --- ci/check-start.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ci/check-start.lua b/ci/check-start.lua index a075421..36d0240 100644 --- a/ci/check-start.lua +++ b/ci/check-start.lua @@ -45,7 +45,7 @@ package.preload["nvim-treesitter"] = function(name) task:await(function(err, ok) treesitter_pending = treesitter_pending - 1 if err or not ok then - table.insert(failures, "treesitter install failed: " .. tostring(err or "see messages")) + record("treesitter install failed: " .. tostring(err or "see messages")) end end) return task From 0eb7b7439d0c54516c87f5b03c92169b198a9fd2 Mon Sep 17 00:00:00 2001 From: Harrison Cramer Date: Fri, 16 Oct 2026 16:49:41 -0400 Subject: [PATCH 12/14] refactor(ci): name the notifier history loop variable --- ci/check-start.lua | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/ci/check-start.lua b/ci/check-start.lua index 36d0240..d9e7820 100644 --- a/ci/check-start.lua +++ b/ci/check-start.lua @@ -88,9 +88,9 @@ local function errors() end local ok, snacks = pcall(require, "snacks") if ok and snacks.notifier then - for _, n in ipairs(snacks.notifier.get_history()) do - if n.level == "error" then - table.insert(found, n.msg) + for _, notification in ipairs(snacks.notifier.get_history()) do + if notification.level == "error" then + table.insert(found, notification.msg) end end end From 629f0015df394330093c511c7428befd4b9a589e Mon Sep 17 00:00:00 2001 From: Harrison Cramer Date: Fri, 16 Oct 2026 16:49:47 -0400 Subject: [PATCH 13/14] docs: trim the Linux check section --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 2d1f920..7009ec0 100644 --- a/README.md +++ b/README.md @@ -27,7 +27,7 @@ A few commands shell out to optional programs that the editor can start without. # Linux check -Run `./check-linux` to prove a fresh install works on Ubuntu 24.04 ARM64. It needs Docker. It builds an image with Neovim and the required programs, restores the plugins from lazy-lock.json, and waits for the Mason and treesitter installs to finish. It fails if Neovim reports an error then or on a second start. The image leaves out the optional programs, so the check also proves the editor starts without them. CI runs the same check on every pull request. +Run `./check-linux` to check that a fresh install starts clean on Ubuntu 24.04 ARM64. It needs Docker. The image has only the required programs, so the check also proves the editor starts without the optional ones. CI runs it on every pull request. # Quickstart From 1f4cdac70d981481a91a5a441b3347de564703ce Mon Sep 17 00:00:00 2001 From: Harrison Cramer Date: Fri, 16 Oct 2026 18:43:07 -0400 Subject: [PATCH 14/14] ci: remove the Linux fresh install check --- .github/workflows/check.yml | 17 ----- README.md | 4 -- check-linux | 8 --- ci/Dockerfile | 50 -------------- ci/check-start | 7 -- ci/check-start.lua | 129 ------------------------------------ 6 files changed, 215 deletions(-) delete mode 100644 .github/workflows/check.yml delete mode 100755 check-linux delete mode 100644 ci/Dockerfile delete mode 100755 ci/check-start delete mode 100644 ci/check-start.lua diff --git a/.github/workflows/check.yml b/.github/workflows/check.yml deleted file mode 100644 index b324c41..0000000 --- a/.github/workflows/check.yml +++ /dev/null @@ -1,17 +0,0 @@ -name: check - -on: - pull_request: - push: - branches: [main] - -permissions: - contents: read - -jobs: - linux: - runs-on: ubuntu-24.04-arm - timeout-minutes: 30 - steps: - - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - - run: ./check-linux diff --git a/README.md b/README.md index 7009ec0..64a6ef8 100644 --- a/README.md +++ b/README.md @@ -25,10 +25,6 @@ Run `./check-tools` to see what is missing or too old. It never installs anythin A few commands shell out to optional programs that the editor can start without. When one is missing, the command that needs it shows a warning and does nothing. -# Linux check - -Run `./check-linux` to check that a fresh install starts clean on Ubuntu 24.04 ARM64. It needs Docker. The image has only the required programs, so the check also proves the editor starts without the optional ones. CI runs it on every pull request. - # Quickstart 1. Clone this repository to your Neovim configuration path: `git clone https://github.com/harrisoncramer/nvim.git ~/.config/nvim` diff --git a/check-linux b/check-linux deleted file mode 100755 index a154c41..0000000 --- a/check-linux +++ /dev/null @@ -1,8 +0,0 @@ -#!/usr/bin/env bash -set -euo pipefail - -cd "$(dirname "$0")" - -docker build --platform linux/arm64 -t nvim-linux-check ci -docker run --rm --platform linux/arm64 -v "$PWD:/src:ro" nvim-linux-check \ - bash -c 'mkdir -p ~/.config && cp -R /src ~/.config/nvim && cd ~/.config/nvim && ./check-tools && ci/check-start' diff --git a/ci/Dockerfile b/ci/Dockerfile deleted file mode 100644 index c3cb5a7..0000000 --- a/ci/Dockerfile +++ /dev/null @@ -1,50 +0,0 @@ -FROM ubuntu:24.04@sha256:534baea6a22c03a63003dbc8dbe78fe34bc0d7e595d9a9dc9834884ff530eb55 - -ARG NVIM_VERSION=0.12.4 -ARG NVIM_SHA256=ceb7e88c6b681f0515d135dcdfad54f5eb4373b25ce6172197cd9a69c758063f -ARG TREE_SITTER_VERSION=0.26.9 -ARG TREE_SITTER_SHA256=c8feeb32115958cb44442ca4d68f6d66cf7605dbd65681e62342181ebdd6db3b -ARG NODE_VERSION=24.18.0 -ARG NODE_SHA256=6b4484c2190274175df9aa8f28e2d758a819cb1c1fe6ab481e2f95b463ab8508 -ARG GO_VERSION=1.26.4 -ARG GO_SHA256=ef758ae7c6cf9267c9c0ef080b8965f453d89ab2d25d9eb22de4405925238768 -ARG GOLANGCI_LINT_VERSION=2.12.2 -ARG GOLANGCI_LINT_SHA256=44cd40a8c76c86755375adfeea52cfd3533cb43d7bd647771e0ae065e166df3a - -RUN apt-get update \ - && apt-get install -y --no-install-recommends ca-certificates git curl unzip build-essential ripgrep \ - && rm -rf /var/lib/apt/lists/* - -RUN curl -fsSLo /tmp/nvim.tar.gz "https://github.com/neovim/neovim/releases/download/v${NVIM_VERSION}/nvim-linux-arm64.tar.gz" \ - && echo "${NVIM_SHA256} /tmp/nvim.tar.gz" | sha256sum -c - \ - && tar -xzf /tmp/nvim.tar.gz -C /opt \ - && ln -s /opt/nvim-linux-arm64/bin/nvim /usr/local/bin/nvim \ - && rm /tmp/nvim.tar.gz - -RUN curl -fsSLo /tmp/tree-sitter.gz "https://github.com/tree-sitter/tree-sitter/releases/download/v${TREE_SITTER_VERSION}/tree-sitter-linux-arm64.gz" \ - && echo "${TREE_SITTER_SHA256} /tmp/tree-sitter.gz" | sha256sum -c - \ - && gunzip -c /tmp/tree-sitter.gz > /usr/local/bin/tree-sitter \ - && chmod +x /usr/local/bin/tree-sitter \ - && rm /tmp/tree-sitter.gz - -RUN curl -fsSLo /tmp/node.tar.gz "https://nodejs.org/dist/v${NODE_VERSION}/node-v${NODE_VERSION}-linux-arm64.tar.gz" \ - && echo "${NODE_SHA256} /tmp/node.tar.gz" | sha256sum -c - \ - && mkdir /opt/node \ - && tar -xzf /tmp/node.tar.gz -C /opt/node --strip-components=1 \ - && rm /tmp/node.tar.gz - -RUN curl -fsSLo /tmp/go.tar.gz "https://go.dev/dl/go${GO_VERSION}.linux-arm64.tar.gz" \ - && echo "${GO_SHA256} /tmp/go.tar.gz" | sha256sum -c - \ - && tar -xzf /tmp/go.tar.gz -C /usr/local \ - && rm /tmp/go.tar.gz - -RUN curl -fsSLo /tmp/golangci-lint.tar.gz "https://github.com/golangci/golangci-lint/releases/download/v${GOLANGCI_LINT_VERSION}/golangci-lint-${GOLANGCI_LINT_VERSION}-linux-arm64.tar.gz" \ - && echo "${GOLANGCI_LINT_SHA256} /tmp/golangci-lint.tar.gz" | sha256sum -c - \ - && tar -xzf /tmp/golangci-lint.tar.gz -C /usr/local/bin --strip-components=1 "golangci-lint-${GOLANGCI_LINT_VERSION}-linux-arm64/golangci-lint" \ - && rm /tmp/golangci-lint.tar.gz - -ENV PATH=/opt/node/bin:/usr/local/go/bin:$PATH - -RUN mkdir -p /var/lib/komrad && useradd --create-home --home-dir /var/lib/komrad/home komrad -USER komrad -WORKDIR /var/lib/komrad/home diff --git a/ci/check-start b/ci/check-start deleted file mode 100755 index 414e0d6..0000000 --- a/ci/check-start +++ /dev/null @@ -1,7 +0,0 @@ -#!/usr/bin/env bash -set -euo pipefail - -hook="$(dirname "$0")/check-start.lua" - -nvim --headless --cmd "luafile $hook" "+Lazy! restore" -nvim --headless --cmd "luafile $hook" diff --git a/ci/check-start.lua b/ci/check-start.lua deleted file mode 100644 index d9e7820..0000000 --- a/ci/check-start.lua +++ /dev/null @@ -1,129 +0,0 @@ -local timeout_ms = 20 * 60 * 1000 - -local failures = {} -local treesitter_pending = 0 -local mason_done = false - -local function record(msg) - table.insert(failures, vim.trim(tostring(msg))) -end - -for _, name in ipairs({ "nvim_err_write", "nvim_err_writeln" }) do - local original = vim.api[name] - vim.api[name] = function(msg) - record(msg) - return original(msg) - end -end - -local echo = vim.api.nvim_echo -vim.api.nvim_echo = function(chunks, history, opts) - if opts and opts.err then - record(table.concat(vim.tbl_map(function(chunk) - return chunk[1] - end, chunks))) - end - return echo(chunks, history, opts) -end - -local function load_without_preload(name) - for i = 2, #package.loaders do - local loader = package.loaders[i](name) - if type(loader) == "function" then - return loader(name) - end - end - error("module not found: " .. name) -end - -package.preload["nvim-treesitter"] = function(name) - local mod = load_without_preload(name) - local install = mod.install - mod.install = function(...) - local task = install(...) - treesitter_pending = treesitter_pending + 1 - task:await(function(err, ok) - treesitter_pending = treesitter_pending - 1 - if err or not ok then - record("treesitter install failed: " .. tostring(err or "see messages")) - end - end) - return task - end - return mod -end - -vim.api.nvim_create_autocmd("User", { - pattern = "MasonToolsUpdateCompleted", - once = true, - callback = function() - mason_done = true - end, -}) - -local function lazy_failures() - local found = {} - local ok, config = pcall(require, "lazy.core.config") - if not ok then - return found - end - for name, plugin in pairs(config.plugins) do - if not plugin.virtual and not plugin._.installed then - table.insert(found, name .. " is not installed") - end - for _, task in ipairs(plugin._.tasks or {}) do - if task:has_errors() then - table.insert(found, name .. " " .. task.name .. " failed: " .. task:output(vim.log.levels.ERROR)) - end - end - end - return found -end - -local function errors() - local found = vim.list_extend(lazy_failures(), failures) - local messages = vim.fn.execute("messages") - if messages:match("E%d+:") or messages:match("[Ee]rror") or messages:match("stack traceback") then - table.insert(found, vim.trim(messages)) - end - local ok, snacks = pcall(require, "snacks") - if ok and snacks.notifier then - for _, notification in ipairs(snacks.notifier.get_history()) do - if notification.level == "error" then - table.insert(found, notification.msg) - end - end - end - return found -end - -local function settled() - return (mason_done and treesitter_pending == 0) or #errors() > 0 -end - -local function finish() - local found = errors() - if not mason_done then - table.insert(found, "Mason installs did not finish") - end - if treesitter_pending > 0 then - table.insert(found, "treesitter installs did not finish") - end - if #found == 0 then - io.stdout:write("nvim started clean\n") - vim.cmd("qall!") - else - io.stdout:write("nvim started with errors:\n" .. table.concat(found, "\n") .. "\n") - vim.cmd("cquit 1") - end -end - -vim.api.nvim_create_autocmd("VimEnter", { - once = true, - callback = function() - vim.schedule(function() - vim.wait(timeout_ms, settled, 500) - vim.defer_fn(finish, 1000) - end) - end, -})