Skip to content
This repository was archived by the owner on Jan 14, 2026. It is now read-only.

Commit aba543b

Browse files
committed
refactor(gitcommit): migrate git commands to arrays
Replace string shell commands and redirects with arrays in git.lua and command.lua. Replace vim.fn.system with CommandExecutor and replace vim.loop with vim.uv.
1 parent d266bdf commit aba543b

5 files changed

Lines changed: 35 additions & 20 deletions

File tree

‎lua/codecompanion/_extensions/gitcommit/git.lua‎

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -58,8 +58,7 @@ function Git.is_repository()
5858
check_dir = parent
5959
end
6060

61-
local redirect = (vim.uv.os_uname().sysname == "Windows_NT") and " 2>nul" or " 2>/dev/null"
62-
local cmd = "git rev-parse --is-inside-work-tree" .. redirect
61+
local cmd = { "git", "rev-parse", "--is-inside-work-tree" }
6362
local result = vim.fn.system(cmd)
6463
local is_repo = vim.v.shell_error == 0 and vim.trim(result) == "true"
6564

@@ -85,8 +84,7 @@ function Git.is_amending()
8584
return false
8685
end
8786

88-
local redirect = (vim.uv.os_uname().sysname == "Windows_NT") and " 2>nul" or " 2>/dev/null"
89-
vim.fn.system("git rev-parse --verify HEAD" .. redirect)
87+
vim.fn.system({ "git", "rev-parse", "--verify", "HEAD" })
9088
if vim.v.shell_error ~= 0 then
9189
return false
9290
end

‎lua/codecompanion/_extensions/gitcommit/git_utils.lua‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -217,7 +217,7 @@ end
217217
---Check if running on Windows
218218
---@return boolean
219219
function M.is_windows()
220-
return vim.loop.os_uname().sysname == "Windows_NT"
220+
return vim.uv.os_uname().sysname == "Windows_NT"
221221
end
222222

223223
---Quote a string for shell command (cross-platform)

‎lua/codecompanion/_extensions/gitcommit/tools/ai_release_notes.lua‎

Lines changed: 13 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
local prompts = require("codecompanion._extensions.gitcommit.prompts.release_notes")
22
local git_utils = require("codecompanion._extensions.gitcommit.git_utils")
3+
local Command = require("codecompanion._extensions.gitcommit.tools.command")
34

5+
local CommandExecutor = Command.CommandExecutor
46
local shell_quote = git_utils.shell_quote
57

68
---@class CodeCompanion.GitCommit.Tools.AIReleaseNotes: CodeCompanion.Tools.Tool
@@ -51,7 +53,9 @@ Output styles:
5153
- changelog: Developer-focused changelog format
5254
- marketing: User-friendly marketing release notes]]
5355

54-
-- Helper function to get commit details with diffs
56+
---@param from_ref string Starting reference (tag or commit hash)
57+
---@param to_ref string Ending reference (tag or commit hash or HEAD)
58+
---@return table|nil, string|nil Commits array and error message
5559
local function get_detailed_commits(from_ref, to_ref)
5660
-- Git range A..B = commits reachable from B but not from A
5761
-- This correctly excludes from_ref itself and includes up to to_ref
@@ -63,8 +67,8 @@ local function get_detailed_commits(from_ref, to_ref)
6367
local format_str = shell_quote("%H||%s||%an||%b" .. separator)
6468
local commit_cmd = string.format("git log --pretty=format:%s %s", format_str, escaped_range)
6569

66-
local success, output = pcall(vim.fn.system, commit_cmd)
67-
if not success or vim.v.shell_error ~= 0 then
70+
local success, output = CommandExecutor.run(commit_cmd)
71+
if not success then
6872
return nil, "Failed to get commit history"
6973
end
7074

@@ -79,12 +83,12 @@ local function get_detailed_commits(from_ref, to_ref)
7983

8084
for _, entry in ipairs(commit_entries) do
8185
if entry and vim.trim(entry) ~= "" then
82-
-- Find the first non-empty line with commit info
86+
-- Find first non-empty line with commit info
8387
local lines = vim.split(entry, "\n")
8488
local commit_line = nil
8589
local body_start_idx = 1
8690

87-
-- Find the line with the commit info (has || separators)
91+
-- Find line with commit info (has || separators)
8892
for i, line in ipairs(lines) do
8993
if line:match("||") then
9094
commit_line = line
@@ -145,8 +149,8 @@ AIReleaseNotes.cmds = {
145149
-- Get tags if not specified
146150
if not to_tag or not from_tag then
147151
-- Try to get tags sorted by version
148-
local success, tags_output = pcall(vim.fn.system, "git tag --sort=-version:refname")
149-
if success and vim.v.shell_error == 0 and tags_output and vim.trim(tags_output) ~= "" then
152+
local success, tags_output = CommandExecutor.run("git tag --sort=-version:refname")
153+
if success and tags_output and vim.trim(tags_output) ~= "" then
150154
local tags = {}
151155
for tag in tags_output:gmatch("[^\r\n]+") do
152156
local trimmed = vim.trim(tag)
@@ -171,8 +175,8 @@ AIReleaseNotes.cmds = {
171175
elseif #tags == 1 then
172176
-- Only one tag, get first commit as starting point
173177
local first_commit_cmd = "git rev-list --max-parents=0 HEAD"
174-
local fc_success, first_commit_output = pcall(vim.fn.system, first_commit_cmd)
175-
if fc_success and vim.v.shell_error == 0 then
178+
local fc_success, first_commit_output = CommandExecutor.run(first_commit_cmd)
179+
if fc_success and first_commit_output and vim.trim(first_commit_output) ~= "" then
176180
from_tag = vim.trim(first_commit_output):sub(1, 8)
177181
else
178182
-- Fallback to 10 commits ago

‎lua/codecompanion/_extensions/gitcommit/tools/command.lua‎

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -523,10 +523,15 @@ function CommandBuilder.pull(remote, branch, rebase)
523523
end
524524

525525
---Build git rev-parse command (check repo)
526-
---@return string command
526+
---@return string[] command array
527527
function CommandBuilder.is_inside_work_tree()
528-
local redirect = is_windows() and " 2>nul" or " 2>/dev/null"
529-
return "git rev-parse --is-inside-work-tree" .. redirect
528+
return { "git", "rev-parse", "--is-inside-work-tree" }
529+
end
530+
531+
---Build git rev-parse --verify HEAD command
532+
---@return string[] command array
533+
function CommandBuilder.verify_head()
534+
return { "git", "rev-parse", "--verify", "HEAD" }
530535
end
531536

532537
---Build git rev-parse git-dir command
@@ -631,8 +636,8 @@ end
631636
---@return boolean
632637
function CommandExecutor.is_git_repo()
633638
local cmd = CommandBuilder.is_inside_work_tree()
634-
local ok, output = pcall(vim.fn.system, cmd)
635-
return ok and vim.v.shell_error == 0 and vim.trim(output) == "true"
639+
local ok, result = CommandExecutor.run_array(cmd)
640+
return ok and vim.trim(result) == "true"
636641
end
637642

638643
---Execute a git command with repo check

‎tests/test_command_builder.lua‎

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -714,7 +714,15 @@ T["utility"]["is_inside_work_tree"] = function()
714714
local Command = require("codecompanion._extensions.gitcommit.tools.command")
715715
return Command.CommandBuilder.is_inside_work_tree()
716716
]])
717-
h.eq(true, result:find("git rev%-parse %-%-is%-inside%-work%-tree") ~= nil)
717+
h.eq({ "git", "rev-parse", "--is-inside-work-tree" }, result)
718+
end
719+
720+
T["utility"]["verify_head"] = function()
721+
local result = child.lua([[
722+
local Command = require("codecompanion._extensions.gitcommit.tools.command")
723+
return Command.CommandBuilder.verify_head()
724+
]])
725+
h.eq({ "git", "rev-parse", "--verify", "HEAD" }, result)
718726
end
719727

720728
T["utility"]["git_dir"] = function()

0 commit comments

Comments
 (0)