feat(forge): add validate option for forge ref validation on write (#138)
Problem: Typos in forge refs like `gh:user/repo#42` silently persist — there's no feedback when a ref points to a nonexistent issue. Solution: Add `forge.validate` config option. When enabled, `diff.apply()` returns new/changed `ForgeRef[]` and `forge.validate_refs()` fetches metadata for each, logging specific warnings for not-found, auth, or CLI-missing errors.
This commit is contained in:
parent
61d84f85b8
commit
f198358819
6 changed files with 163 additions and 19 deletions
|
|
@ -243,30 +243,51 @@ function M.format_label(ref, cache)
|
|||
return text, hl
|
||||
end
|
||||
|
||||
---@class pending.ForgeFetchError
|
||||
---@field code 'not_found'|'auth'|'cli_missing'|'network'
|
||||
---@field message string
|
||||
|
||||
---@param ref pending.ForgeRef
|
||||
---@param callback fun(cache: pending.ForgeCache?)
|
||||
---@param callback fun(cache: pending.ForgeCache?, err: pending.ForgeFetchError?)
|
||||
function M.fetch_metadata(ref, callback)
|
||||
local args = M._api_args(ref)
|
||||
local backend = _by_name[ref.forge]
|
||||
|
||||
if backend and vim.fn.executable(backend.cli) == 0 then
|
||||
vim.schedule(function()
|
||||
local forge_cfg = config.get().forge or {}
|
||||
if forge_cfg.warn_missing_cli ~= false and not backend._warned then
|
||||
backend._warned = true
|
||||
log.warn(('%s not installed'):format(backend.cli))
|
||||
end
|
||||
callback(nil, { code = 'cli_missing', message = backend.cli .. ' not installed' })
|
||||
end)
|
||||
return
|
||||
end
|
||||
|
||||
vim.system(args, { text = true }, function(result)
|
||||
if result.code ~= 0 or not result.stdout or result.stdout == '' then
|
||||
local forge_cfg = config.get().forge or {}
|
||||
local backend = _by_name[ref.forge]
|
||||
if backend and forge_cfg.warn_missing_cli ~= false and not backend._warned then
|
||||
backend._warned = true
|
||||
vim.system(backend.auth_status_args, { text = true }, function(auth_result)
|
||||
vim.schedule(function()
|
||||
if auth_result.code ~= 0 then
|
||||
log.warn(('%s not authenticated — run `%s`'):format(backend.cli, backend.auth_cmd))
|
||||
end
|
||||
callback(nil)
|
||||
end)
|
||||
end)
|
||||
else
|
||||
vim.schedule(function()
|
||||
callback(nil)
|
||||
end)
|
||||
local stderr = result.stderr or ''
|
||||
local err_code = 'network' ---@type 'not_found'|'auth'|'network'
|
||||
if stderr:find('404') or stderr:find('Not Found') then
|
||||
err_code = 'not_found'
|
||||
elseif stderr:find('401') or stderr:find('requires authentication') then
|
||||
err_code = 'auth'
|
||||
end
|
||||
vim.schedule(function()
|
||||
local forge_cfg = config.get().forge or {}
|
||||
if
|
||||
backend
|
||||
and forge_cfg.warn_missing_cli ~= false
|
||||
and not backend._warned
|
||||
then
|
||||
backend._warned = true
|
||||
log.warn(
|
||||
('%s not found or not authenticated — run `%s`'):format(backend.cli, backend.auth_cmd)
|
||||
)
|
||||
end
|
||||
callback(nil, { code = err_code, message = stderr })
|
||||
end)
|
||||
return
|
||||
end
|
||||
local ok, decoded = pcall(vim.json.decode, result.stdout)
|
||||
|
|
@ -567,4 +588,31 @@ M.register({
|
|||
end,
|
||||
})
|
||||
|
||||
---@param refs pending.ForgeRef[]
|
||||
function M.validate_refs(refs)
|
||||
local forge_cfg = config.get().forge or {}
|
||||
if not forge_cfg.validate then
|
||||
return
|
||||
end
|
||||
for _, ref in ipairs(refs) do
|
||||
M.fetch_metadata(ref, function(_, err)
|
||||
if err then
|
||||
local label = ref.owner .. '/' .. ref.repo .. '#' .. ref.number
|
||||
local backend = _by_name[ref.forge]
|
||||
if err.code == 'not_found' then
|
||||
log.warn(('%s not found — check owner, repo, and number'):format(label))
|
||||
elseif err.code == 'auth' then
|
||||
local cmd = backend and backend.auth_cmd or 'auth'
|
||||
log.warn(('%s: not authenticated — run `%s`'):format(label, cmd))
|
||||
elseif err.code == 'cli_missing' then
|
||||
local cli = backend and backend.cli or 'cli'
|
||||
log.warn(('%s: %s not installed'):format(label, cli))
|
||||
else
|
||||
log.warn(('%s: validation failed'):format(label))
|
||||
end
|
||||
end
|
||||
end)
|
||||
end
|
||||
end
|
||||
|
||||
return M
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue