mirror of
https://github.com/zoriya/jj.nvim.git
synced 2026-08-15 23:53:18 +00:00
refactor!: Migrate runners cmd from string to argv (#134)
Migrate command execution to structured argv lists across the plugin, replacing shell-string command construction with `vim.system` argv execution. The runner API now exposes argv-based execution as the default path:
- `runner.execute_command` -> `runner.execute`
- `runner.execute_command_async` -> `runner.execute_async`
- `runner.execute_command_raw` -> `runner.execute_raw`
- `runner.execute_command_raw_async` -> `runner.execute_raw_async`
- `runner.execute_command_sync` was removed; use `runner.execute` and handle the result directly
BREAKING CHANGES:
- `cmd.new({ args = ... })` now requires `args` as `string[]` argv tokens, not a single string.
- `cmd.log({ ... })` now uses `raw_flags` as `string[]` for raw passthrough flags; `raw = "..."` is no longer supported.
- Direct users of `jj.core.runner` must migrate from the old `execute_command*` string helpers to the new argv-based `execute*` helpers.
This commit is contained in:
+49
-43
@@ -10,6 +10,7 @@ package.path = package.path .. ";lua/?.lua;lua/?/init.lua"
|
||||
local parser = require("jj.core.parser")
|
||||
|
||||
local utils = require("jj.utils")
|
||||
local jj_args = require("jj.core.args")
|
||||
|
||||
local tests_passed = 0
|
||||
local tests_failed = 0
|
||||
@@ -529,37 +530,33 @@ print("\n=== Running build_log_cmd tests ===\n")
|
||||
local log = require("jj.cmd.log")
|
||||
|
||||
run_test("build_log_cmd: raw_flags with --no-pager does not duplicate it", function()
|
||||
local cmd = log.build_log_cmd({ raw_flags = "--no-pager --limit 18" })
|
||||
-- Should contain exactly one --no-pager
|
||||
local _, count = cmd:gsub("%-%-no%-pager", "")
|
||||
assert_equals(1, count, "Expected exactly one --no-pager")
|
||||
assert_equals("jj log --no-pager --limit 18", cmd)
|
||||
local cmd = log.build_log_cmd({ raw_flags = { "--no-pager", "--limit", "18" } })
|
||||
assert_table_equals({ "jj", "log", "--no-pager", "--limit", "18" }, cmd)
|
||||
end)
|
||||
|
||||
run_test("build_log_cmd: raw_flags without --no-pager works normally", function()
|
||||
local cmd = log.build_log_cmd({ raw_flags = "--limit 18" })
|
||||
assert_equals("jj log --no-pager --limit 18", cmd)
|
||||
local cmd = log.build_log_cmd({ raw_flags = { "--limit", "18" } })
|
||||
assert_table_equals({ "jj", "log", "--no-pager", "--limit", "18" }, cmd)
|
||||
end)
|
||||
|
||||
run_test("build_log_cmd: raw_flags that is only --no-pager", function()
|
||||
local cmd = log.build_log_cmd({ raw_flags = "--no-pager" })
|
||||
assert_equals("jj log --no-pager", cmd)
|
||||
local cmd = log.build_log_cmd({ raw_flags = { "--no-pager" } })
|
||||
assert_table_equals({ "jj", "log", "--no-pager" }, cmd)
|
||||
end)
|
||||
|
||||
run_test("build_log_cmd: structured opts with limit", function()
|
||||
local cmd = log.build_log_cmd({ limit = 10 })
|
||||
assert_equals(true, cmd:find("--limit 10") ~= nil, "Expected --limit 10 in command")
|
||||
assert_equals(true, cmd:find("--no%-pager") ~= nil, "Expected --no-pager in command")
|
||||
assert_table_equals({ "jj", "log", "--no-pager", "--limit", "10" }, cmd)
|
||||
end)
|
||||
|
||||
run_test("build_log_cmd: structured opts with revisions", function()
|
||||
local cmd = log.build_log_cmd({ revisions = "main" })
|
||||
assert_equals(true, cmd:find("--revisions main") ~= nil, "Expected --revisions main in command")
|
||||
assert_table_equals({ "jj", "log", "--no-pager", "--revisions", "main" }, cmd)
|
||||
end)
|
||||
|
||||
run_test("build_log_cmd: default opts produces valid command", function()
|
||||
local cmd = log.build_log_cmd({})
|
||||
assert_equals(true, cmd:find("^jj log %-%-no%-pager") ~= nil, "Expected command to start with jj log --no-pager")
|
||||
assert_table_equals({ "jj", "log", "--no-pager" }, cmd)
|
||||
end)
|
||||
|
||||
print("\n=== Running resolve arg parsing tests ===\n")
|
||||
@@ -623,14 +620,14 @@ end)
|
||||
|
||||
local resolve = require("jj.cmd.resolve")
|
||||
|
||||
run_test("resolve: shellescapes args for external execution", function()
|
||||
run_test("resolve: passes jj-quoted argv for external execution", function()
|
||||
local runner = require("jj.core.runner")
|
||||
local original_execute_command_async = runner.execute_command_async
|
||||
local original_execute_argv_async = runner.execute_async
|
||||
local original_notify = utils.notify
|
||||
local original_ensure_jj = utils.ensure_jj
|
||||
|
||||
local captured_cmd = nil
|
||||
runner.execute_command_async = function(cmd)
|
||||
runner.execute_async = function(cmd)
|
||||
captured_cmd = cmd
|
||||
end
|
||||
utils.notify = function() end
|
||||
@@ -645,13 +642,19 @@ run_test("resolve: shellescapes args for external execution", function()
|
||||
filesets = { "dir with spaces/", "glob:*" },
|
||||
external = true,
|
||||
})
|
||||
assert_equals(
|
||||
"'jj' 'resolve' '--revision' 'abc 123' '--tool' 'my tool' 'dir with spaces/' 'glob:*'",
|
||||
captured_cmd
|
||||
)
|
||||
assert_table_equals({
|
||||
"jj",
|
||||
"resolve",
|
||||
"--revision",
|
||||
"abc 123",
|
||||
"--tool",
|
||||
"my tool",
|
||||
jj_args.fileset("dir with spaces/"),
|
||||
jj_args.fileset("glob:*"),
|
||||
}, captured_cmd)
|
||||
end)
|
||||
|
||||
runner.execute_command_async = original_execute_command_async
|
||||
runner.execute_async = original_execute_argv_async
|
||||
utils.notify = original_notify
|
||||
utils.ensure_jj = original_ensure_jj
|
||||
if not ok then
|
||||
@@ -659,7 +662,7 @@ run_test("resolve: shellescapes args for external execution", function()
|
||||
end
|
||||
end)
|
||||
|
||||
run_test("resolve: passes argv for floating execution", function()
|
||||
run_test("resolve: passes jj-quoted filesets for floating execution", function()
|
||||
local terminal = require("jj.ui.terminal")
|
||||
local original_run_floating = terminal.run_floating
|
||||
local original_notify = utils.notify
|
||||
@@ -687,8 +690,8 @@ run_test("resolve: passes argv for floating execution", function()
|
||||
"abc 123",
|
||||
"--tool",
|
||||
"my tool",
|
||||
"dir with spaces/",
|
||||
"glob:*",
|
||||
jj_args.fileset("dir with spaces/"),
|
||||
jj_args.fileset("glob:*"),
|
||||
}, captured_cmd)
|
||||
end)
|
||||
|
||||
@@ -704,10 +707,10 @@ print("\n=== Running utils helper tests ===\n")
|
||||
|
||||
run_test("is_change_conflicted: returns true when jj reports conflict", function()
|
||||
local runner = require("jj.core.runner")
|
||||
local original_execute_command = runner.execute_command
|
||||
local original_execute_argv = runner.execute
|
||||
|
||||
runner.execute_command = function(cmd, error_prefix, input, silent)
|
||||
assert_equals("jj log --no-graph -r 'abc123' -T 'conflict' --quiet", cmd)
|
||||
runner.execute = function(argv, error_prefix, input, silent)
|
||||
assert_table_equals({ "jj", "log", "--no-graph", "-r", "abc123", "-T", "conflict", "--quiet" }, argv)
|
||||
assert_equals("Error checking if revset has conflicts", error_prefix)
|
||||
assert_is_nil(input)
|
||||
assert_equals(true, silent)
|
||||
@@ -717,7 +720,7 @@ run_test("is_change_conflicted: returns true when jj reports conflict", function
|
||||
local ok, err = pcall(function()
|
||||
assert_equals(true, utils.is_change_conflicted("abc123"))
|
||||
end)
|
||||
runner.execute_command = original_execute_command
|
||||
runner.execute = original_execute_argv
|
||||
if not ok then
|
||||
error(err)
|
||||
end
|
||||
@@ -725,16 +728,16 @@ end)
|
||||
|
||||
run_test("is_change_conflicted: returns false when jj reports no conflict", function()
|
||||
local runner = require("jj.core.runner")
|
||||
local original_execute_command = runner.execute_command
|
||||
local original_execute_argv = runner.execute
|
||||
|
||||
runner.execute_command = function()
|
||||
runner.execute = function()
|
||||
return "false\n", true
|
||||
end
|
||||
|
||||
local ok, err = pcall(function()
|
||||
assert_equals(false, utils.is_change_conflicted("abc123"))
|
||||
end)
|
||||
runner.execute_command = original_execute_command
|
||||
runner.execute = original_execute_argv
|
||||
if not ok then
|
||||
error(err)
|
||||
end
|
||||
@@ -742,16 +745,16 @@ end)
|
||||
|
||||
run_test("is_change_conflicted: returns false when jj command fails", function()
|
||||
local runner = require("jj.core.runner")
|
||||
local original_execute_command = runner.execute_command
|
||||
local original_execute_argv = runner.execute
|
||||
|
||||
runner.execute_command = function()
|
||||
runner.execute = function()
|
||||
return nil, false
|
||||
end
|
||||
|
||||
local ok, err = pcall(function()
|
||||
assert_equals(false, utils.is_change_conflicted("abc123"))
|
||||
end)
|
||||
runner.execute_command = original_execute_command
|
||||
runner.execute = original_execute_argv
|
||||
if not ok then
|
||||
error(err)
|
||||
end
|
||||
@@ -870,8 +873,9 @@ print("\n=== Running get_file_content tests ===\n")
|
||||
|
||||
run_test("get_file_content: reads existing file content", function()
|
||||
local runner = require("jj.core.runner")
|
||||
local original = runner.execute_command_raw
|
||||
runner.execute_command_raw = function()
|
||||
local original = runner.execute_raw
|
||||
runner.execute_raw = function(cmd)
|
||||
assert_table_equals({ "jj", "file", "show", "-r", "abc123", jj_args.fileset("src/file.py") }, cmd)
|
||||
return "a\nb\n", true, ""
|
||||
end
|
||||
local ok_test, err = pcall(function()
|
||||
@@ -881,7 +885,7 @@ run_test("get_file_content: reads existing file content", function()
|
||||
assert_equals(true, ok)
|
||||
assert_equals(false, absent)
|
||||
end)
|
||||
runner.execute_command_raw = original
|
||||
runner.execute_raw = original
|
||||
if not ok_test then
|
||||
error(err)
|
||||
end
|
||||
@@ -889,8 +893,9 @@ end)
|
||||
|
||||
run_test("get_file_content: absent path in revision reports absent (not a read error)", function()
|
||||
local runner = require("jj.core.runner")
|
||||
local original = runner.execute_command_raw
|
||||
runner.execute_command_raw = function()
|
||||
local original = runner.execute_raw
|
||||
runner.execute_raw = function(cmd)
|
||||
assert_table_equals({ "jj", "file", "show", "-r", "abc123", jj_args.fileset("src/new_file.py") }, cmd)
|
||||
return nil, false, "Error: No such path: src/new_file.py\n"
|
||||
end
|
||||
local ok_test, err = pcall(function()
|
||||
@@ -900,7 +905,7 @@ run_test("get_file_content: absent path in revision reports absent (not a read e
|
||||
assert_equals(false, ok)
|
||||
assert_equals(true, absent)
|
||||
end)
|
||||
runner.execute_command_raw = original
|
||||
runner.execute_raw = original
|
||||
if not ok_test then
|
||||
error(err)
|
||||
end
|
||||
@@ -908,8 +913,9 @@ end)
|
||||
|
||||
run_test("get_file_content: genuine read error returns failure without absent", function()
|
||||
local runner = require("jj.core.runner")
|
||||
local original = runner.execute_command_raw
|
||||
runner.execute_command_raw = function()
|
||||
local original = runner.execute_raw
|
||||
runner.execute_raw = function(cmd)
|
||||
assert_table_equals({ "jj", "file", "show", "-r", "nope", jj_args.fileset("src/file.py") }, cmd)
|
||||
return nil, false, "Error: Revision `nope` doesn't exist\n"
|
||||
end
|
||||
local ok_test, err = pcall(function()
|
||||
@@ -917,7 +923,7 @@ run_test("get_file_content: genuine read error returns failure without absent",
|
||||
assert_equals(false, ok)
|
||||
assert_equals(false, absent)
|
||||
end)
|
||||
runner.execute_command_raw = original
|
||||
runner.execute_raw = original
|
||||
if not ok_test then
|
||||
error(err)
|
||||
end
|
||||
|
||||
Reference in New Issue
Block a user