Skip to content

Commit 1a6170f

Browse files
committed
fix(make): silence emmylua warnings in parallel test runner
The previous version of scripts/parallel_test.lua triggered 17 warnings under emmylua_check 0.23.1 (param-type-mismatch, need-check-nil, etc.) which made CI fail because `make emmylua-check` runs with --warnings-as-errors. Adjust LuaCATS annotations and tighten nil handling so the runner lints cleanly while keeping the same execution semantics: exit-code propagation from each worker, contiguous per-spec log output, and `JOBS` workers in flight at most.
1 parent 5f2aced commit 1a6170f

1 file changed

Lines changed: 79 additions & 68 deletions

File tree

scripts/parallel_test.lua

Lines changed: 79 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -10,25 +10,37 @@
1010
-- every requested nvim binary, so CI correctly fails when any spec
1111
-- fails.
1212

13-
local fn = vim.fn
13+
---@class parallel_test.worker
14+
---@field id integer
15+
---@field spec string
16+
---@field cmd string[]
17+
---@field env table<string, string>
18+
---@field buf string[]
19+
---@field started boolean
20+
---@field finished boolean
21+
---@field code integer
22+
---@field signal integer
1423

15-
---@class parallel_test_opts
24+
---@class parallel_test.opts
1625
---@field jobs integer
1726
---@field glob? string
1827
---@field filter? string
1928
---@field serial boolean
2029
---@field nvim_execs string[]
2130

2231
---@param args string[]
23-
---@return parallel_test_opts
32+
---@return parallel_test.opts
2433
local function parse_args(args)
34+
---@type parallel_test.opts
2535
local opts = { jobs = 0, serial = false, nvim_execs = {} }
2636
local i = 1
2737
while i <= #args do
2838
local a = args[i]
2939
if a == "--jobs" or a == "-j" then
3040
i = i + 1
31-
opts.jobs = tonumber(args[i]) or 0
41+
local raw = args[i] and tonumber(args[i]) or nil
42+
---@cast raw integer?
43+
opts.jobs = raw or 0
3244
elseif a == "--glob" then
3345
i = i + 1
3446
opts.glob = args[i]
@@ -49,34 +61,38 @@ Options:
4961
--help, -h Show this help
5062
]])
5163
os.exit(0)
52-
elseif a:sub(1, 1) == "-" then
64+
elseif type(a) == "string" and a:sub(1, 1) == "-" then
5365
io.stderr:write("parallel_test: unknown option: " .. a .. "\n")
5466
os.exit(2)
55-
else
67+
elseif type(a) == "string" then
5668
table.insert(opts.nvim_execs, a)
5769
end
5870
i = i + 1
5971
end
6072

6173
if opts.jobs <= 0 then
62-
if vim.uv and vim.uv.os_getenv("NUMBER_OF_PROCESSORS") then
63-
opts.jobs = tonumber(vim.uv.os_getenv("NUMBER_OF_PROCESSORS")) or 1
74+
local env = vim.uv and vim.uv.os_getenv("NUMBER_OF_PROCESSORS") or nil
75+
if env then
76+
local raw = tonumber(env)
77+
---@cast raw integer?
78+
opts.jobs = raw or 1
6479
elseif jit and jit.os == "Windows" then
65-
opts.jobs = tonumber(vim.uv.os_getenv("NUMBER_OF_PROCESSORS")) or 4
80+
opts.jobs = 4
6681
else
67-
-- POSIX fallback: count online processors.
68-
local n = 0
82+
local count = 0
6983
local f = io.open("/proc/cpuinfo", "r")
7084
if f then
7185
for line in f:lines() do
72-
if line:match("^processor%s*:") then n = n + 1 end
86+
if type(line) == "string" and line:match("^processor%s*:") then
87+
count = count + 1
88+
end
7389
end
7490
f:close()
7591
end
76-
opts.jobs = n > 0 and n or 4
92+
opts.jobs = count > 0 and count or 4
7793
end
7894
end
79-
opts.jobs = math.max(1, opts.jobs)
95+
if opts.jobs < 1 then opts.jobs = 1 end
8096
return opts
8197
end
8298

@@ -95,36 +111,24 @@ local function list_specs(root, pattern)
95111
end
96112

97113
---@param nvim_exec string
98-
---@param spec string
99114
---@return string[]
100-
local function build_cmd(nvim_exec, spec)
115+
local function build_cmd(nvim_exec)
101116
return {
102117
nvim_exec, "--headless", "--noplugin",
103118
"-u", "./scripts/minimal_init.lua",
104119
"-l", "./scripts/make_cli.lua",
105120
}
106121
end
107122

108-
---@class worker
109-
---@field id integer
110-
---@field spec string
111-
---@field cmd string[]
112-
---@field env table<string, string>
113-
---@field buf string[]
114-
---@field started boolean
115-
---@field finished boolean
116-
---@field code integer
117-
---@field signal integer
118-
119-
---@param w worker
123+
---@param w parallel_test.worker
120124
---@return fun(_err: string?, data: string?)
121125
local function make_data_cb(w)
122126
return function(_err, data)
123127
if data then table.insert(w.buf, data) end
124128
end
125129
end
126130

127-
---@param w worker
131+
---@param w parallel_test.worker
128132
---@return fun(obj: vim.SystemCompleted)
129133
local function make_exit_cb(w)
130134
return vim.schedule_wrap(function(obj)
@@ -134,7 +138,7 @@ local function make_exit_cb(w)
134138
end)
135139
end
136140

137-
---@param workers worker[]
141+
---@param workers parallel_test.worker[]
138142
---@param jobs integer
139143
local function drive(workers, jobs)
140144
local next_idx = 1
@@ -143,21 +147,25 @@ local function drive(workers, jobs)
143147
local function spawn_one()
144148
while in_flight < jobs and next_idx <= #workers do
145149
local w = workers[next_idx]
146-
next_idx = next_idx + 1
147-
in_flight = in_flight + 1
148-
w.started = true
149-
vim.system(w.cmd, {
150-
cwd = ".",
151-
text = true,
152-
env = w.env,
153-
stdout = make_data_cb(w),
154-
stderr = make_data_cb(w),
155-
}, vim.schedule_wrap(function(obj)
156-
w.finished = true
157-
w.code = obj.code
158-
w.signal = obj.signal
159-
in_flight = in_flight - 1
160-
end))
150+
if w then
151+
next_idx = next_idx + 1
152+
in_flight = in_flight + 1
153+
w.started = true
154+
vim.system(w.cmd, {
155+
cwd = ".",
156+
text = true,
157+
env = w.env,
158+
stdout = make_data_cb(w),
159+
stderr = make_data_cb(w),
160+
}, vim.schedule_wrap(function(obj)
161+
w.finished = true
162+
w.code = obj.code
163+
w.signal = obj.signal
164+
in_flight = in_flight - 1
165+
end))
166+
else
167+
next_idx = next_idx + 1
168+
end
161169
end
162170
end
163171

@@ -168,12 +176,12 @@ local function drive(workers, jobs)
168176
while true do
169177
local all_done = true
170178
for _, w in ipairs(workers) do
171-
if not w.finished then all_done = false; break end
179+
if w and not w.finished then all_done = false; break end
172180
end
173181
if all_done then break end
174182
vim.wait(200, function()
175183
for _, w in ipairs(workers) do
176-
if not w.finished then return false end
184+
if w and not w.finished then return false end
177185
end
178186
return true
179187
end)
@@ -182,10 +190,9 @@ local function drive(workers, jobs)
182190
vim.wait(50)
183191
end
184192

185-
---@param workers worker[]
186-
---@param opts parallel_test_opts
193+
---@param workers parallel_test.worker[]
187194
---@return integer fails
188-
local function print_and_collect(workers, opts)
195+
local function print_and_collect(workers)
189196
local fails = 0
190197
for _, w in ipairs(workers) do
191198
io.write(string.format("\n----- %s -----\n", w.spec))
@@ -204,7 +211,7 @@ local function print_and_collect(workers, opts)
204211
return fails
205212
end
206213

207-
---@param opts parallel_test_opts
214+
---@param opts parallel_test.opts
208215
---@param nvim_exec string
209216
---@return integer fails
210217
local function run_one_nvim(opts, nvim_exec)
@@ -219,7 +226,7 @@ local function run_one_nvim(opts, nvim_exec)
219226
io.write(string.format("Found %d spec file(s) (jobs=%d)\n", #specs, opts.jobs))
220227
io.flush()
221228

222-
---@type worker[]
229+
---@type parallel_test.worker[]
223230
local workers = {}
224231
for i, spec in ipairs(specs) do
225232
-- Derive the per-spec `glob` (a basename prefix consumed by
@@ -234,7 +241,7 @@ local function run_one_nvim(opts, nvim_exec)
234241
workers[i] = {
235242
id = i,
236243
spec = spec,
237-
cmd = build_cmd(nvim_exec, spec),
244+
cmd = build_cmd(nvim_exec),
238245
env = env,
239246
buf = {},
240247
started = false,
@@ -260,28 +267,32 @@ local function run_one_nvim(opts, nvim_exec)
260267
drive(workers, opts.jobs)
261268
end
262269

263-
local fails = print_and_collect(workers, opts)
270+
local fails = print_and_collect(workers)
264271
io.write(string.format("\n[parallel_test] fails=%d/%d\n", fails, #workers))
265272
io.flush()
266273
return fails
267274
end
268275

276+
---@param opts parallel_test.opts
277+
local function main(opts)
278+
local total_fails = 0
279+
for _, nvim_exec in ipairs(opts.nvim_execs) do
280+
io.write(string.format("\n====== %s ======\n",
281+
vim.fn.system({ nvim_exec, "--version" }):gsub("\n.*$", "")))
282+
io.flush()
283+
total_fails = total_fails + run_one_nvim(opts, nvim_exec)
284+
end
285+
286+
if total_fails > 0 then
287+
io.write(string.format("FAIL: %d spec file(s) failed\n", total_fails))
288+
os.exit(1)
289+
end
290+
io.write("PASS: all spec files green\n")
291+
end
292+
269293
local opts = parse_args(_G.arg)
270294
if #opts.nvim_execs == 0 then
271295
io.stderr:write("parallel_test: at least one NVIM_EXEC is required\n")
272296
os.exit(2)
273297
end
274-
275-
local total_fails = 0
276-
for _, nvim_exec in ipairs(opts.nvim_execs) do
277-
io.write(string.format("\n====== %s ======\n",
278-
fn.system({ nvim_exec, "--version" }):gsub("\n.*$", "")))
279-
io.flush()
280-
total_fails = total_fails + run_one_nvim(opts, nvim_exec)
281-
end
282-
283-
if total_fails > 0 then
284-
io.write(string.format("FAIL: %d spec file(s) failed\n", total_fails))
285-
os.exit(1)
286-
end
287-
io.write("PASS: all spec files green\n")
298+
main(opts)

0 commit comments

Comments
 (0)