• removes the <esc> keybinding for popups which was causing folks to lose their changes • deprecates the backup register. • updates go-gitlab to latest in order to get "drafts" functionality • fixes issues with labels not deleting correctly • creates a new data() function to get data from the plugin directly, see :h gitlab.nvim.data • fixes issues with line values not being computed directly, blocking jumps to/from discussion tree This is a #MINOR release.
234 lines
6.6 KiB
Lua
234 lines
6.6 KiB
Lua
-- This module is responsible for the MR pipeline
|
|
-- This lets the user see the current status of the pipeline
|
|
-- and retrigger the pipeline from within the editor
|
|
local Popup = require("nui.popup")
|
|
local state = require("gitlab.state")
|
|
local job = require("gitlab.job")
|
|
local u = require("gitlab.utils")
|
|
local M = {
|
|
pipeline_jobs = nil,
|
|
latest_pipeline = nil,
|
|
pipeline_popup = nil,
|
|
}
|
|
|
|
local function get_latest_pipeline()
|
|
local pipeline = state.PIPELINE and state.PIPELINE.latest_pipeline
|
|
if type(pipeline) ~= "table" or (type(pipeline) == "table" and u.table_size(pipeline) == 0) then
|
|
u.notify("Pipeline not found", vim.log.levels.WARN)
|
|
return
|
|
end
|
|
return pipeline
|
|
end
|
|
|
|
local function get_pipeline_jobs()
|
|
M.latest_pipeline = get_latest_pipeline()
|
|
if not M.latest_pipeline then
|
|
return
|
|
end
|
|
return u.reverse(type(state.PIPELINE.jobs) == "table" and state.PIPELINE.jobs or {})
|
|
end
|
|
|
|
-- The function will render the Pipeline state in a popup
|
|
M.open = function()
|
|
M.pipeline_jobs = get_pipeline_jobs()
|
|
M.latest_pipeline = get_latest_pipeline()
|
|
if M.latest_pipeline == nil then
|
|
return
|
|
end
|
|
|
|
local width = string.len(M.latest_pipeline.web_url) + 10
|
|
local height = 6 + #M.pipeline_jobs + 3
|
|
|
|
local pipeline_popup =
|
|
Popup(u.create_popup_state("Loading Pipeline...", state.settings.popup.pipeline, width, height, 60))
|
|
M.pipeline_popup = pipeline_popup
|
|
pipeline_popup:mount()
|
|
|
|
local bufnr = vim.api.nvim_get_current_buf()
|
|
vim.opt_local.wrap = false
|
|
|
|
local lines = {}
|
|
|
|
u.switch_can_edit_buf(bufnr, true)
|
|
table.insert(lines, "Status: " .. M.get_pipeline_status(false))
|
|
table.insert(lines, "")
|
|
table.insert(lines, string.format("Last Run: %s", u.time_since(M.latest_pipeline.created_at)))
|
|
table.insert(lines, string.format("Url: %s", M.latest_pipeline.web_url))
|
|
table.insert(lines, string.format("Triggered By: %s", M.latest_pipeline.source))
|
|
|
|
table.insert(lines, "")
|
|
table.insert(lines, "Jobs:")
|
|
|
|
local longest_title = u.get_longest_string(u.map(M.pipeline_jobs, function(v)
|
|
return v.name
|
|
end))
|
|
|
|
local function row_offset(name)
|
|
local offset = longest_title - string.len(name)
|
|
local res = string.rep(" ", offset + 5)
|
|
return res
|
|
end
|
|
|
|
for _, pipeline_job in ipairs(M.pipeline_jobs) do
|
|
local offset = row_offset(pipeline_job.name)
|
|
local row = string.format(
|
|
"%s%s %s (%s)",
|
|
pipeline_job.name,
|
|
offset,
|
|
state.settings.pipeline[pipeline_job.status] or "*",
|
|
pipeline_job.status or ""
|
|
)
|
|
|
|
table.insert(lines, row)
|
|
end
|
|
|
|
vim.schedule(function()
|
|
vim.api.nvim_buf_set_lines(bufnr, 0, -1, false, lines)
|
|
M.color_status(M.latest_pipeline.status, bufnr, lines[1], 1)
|
|
|
|
for i, pipeline_job in ipairs(M.pipeline_jobs) do
|
|
M.color_status(pipeline_job.status, bufnr, lines[7 + i], 7 + i)
|
|
end
|
|
|
|
pipeline_popup.border:set_text("top", "Pipeline Status", "center")
|
|
state.set_popup_keymaps(pipeline_popup, M.retrigger, M.see_logs)
|
|
u.switch_can_edit_buf(bufnr, false)
|
|
end)
|
|
end
|
|
|
|
M.retrigger = function()
|
|
M.latest_pipeline = get_latest_pipeline()
|
|
if not M.latest_pipeline then
|
|
return
|
|
end
|
|
if M.latest_pipeline.status ~= "failed" then
|
|
u.notify("Pipeline is not in a failed state!", vim.log.levels.WARN)
|
|
return
|
|
end
|
|
|
|
job.run_job("/pipeline/" .. M.latest_pipeline.id, "POST", nil, function()
|
|
u.notify("Pipeline re-triggered!", vim.log.levels.INFO)
|
|
end)
|
|
end
|
|
|
|
M.see_logs = function()
|
|
local bufnr = vim.api.nvim_get_current_buf()
|
|
local linnr = vim.api.nvim_win_get_cursor(0)[1]
|
|
local text = u.get_line_content(bufnr, linnr)
|
|
|
|
local job_name = string.match(text, "(.-)%s%s%s%s%s")
|
|
|
|
if job_name == nil then
|
|
u.notify("Cannot find job name", vim.log.levels.ERROR)
|
|
return
|
|
end
|
|
|
|
local j = nil
|
|
for _, pipeline_job in ipairs(M.pipeline_jobs) do
|
|
if pipeline_job.name == job_name then
|
|
j = pipeline_job
|
|
end
|
|
end
|
|
|
|
if j == nil then
|
|
u.notify("Cannot find job in state", vim.log.levels.ERROR)
|
|
return
|
|
end
|
|
|
|
local body = { job_id = j.id }
|
|
job.run_job("/job", "GET", body, function(data)
|
|
local file = data.file
|
|
if file == "" then
|
|
u.notify("Log trace is empty", vim.log.levels.WARN)
|
|
return
|
|
end
|
|
|
|
local lines = {}
|
|
for line in u.split_by_new_lines(file) do
|
|
table.insert(lines, line)
|
|
end
|
|
|
|
if #lines == 0 then
|
|
u.notify("Log trace lines could not be parsed", vim.log.levels.ERROR)
|
|
return
|
|
end
|
|
|
|
M.pipeline_popup:unmount()
|
|
|
|
vim.cmd.tabnew()
|
|
bufnr = vim.api.nvim_get_current_buf()
|
|
vim.api.nvim_buf_set_lines(bufnr, 0, -1, false, lines)
|
|
|
|
local temp_file = os.tmpname()
|
|
local job_file_path = string.format(temp_file, j.id)
|
|
|
|
vim.cmd("w! " .. job_file_path)
|
|
vim.cmd("term cat " .. job_file_path)
|
|
|
|
vim.api.nvim_buf_set_name(0, job_name)
|
|
end)
|
|
end
|
|
|
|
---Returns the user-defined symbol representing the status
|
|
---of the current pipeline. Takes an optional argument to
|
|
---colorize the pipeline icon.
|
|
---@param wrap_with_color boolean
|
|
---@return string
|
|
M.get_pipeline_icon = function(wrap_with_color)
|
|
M.latest_pipeline = get_latest_pipeline()
|
|
if not M.latest_pipeline then
|
|
return ""
|
|
end
|
|
local symbol = state.settings.pipeline[M.latest_pipeline.status]
|
|
if not wrap_with_color then
|
|
return symbol
|
|
end
|
|
if M.latest_pipeline.status == "failed" then
|
|
return "%#DiagnosticError#" .. symbol
|
|
end
|
|
if M.latest_pipeline.status == "success" then
|
|
return "%#DiagnosticOk#" .. symbol
|
|
end
|
|
return "%#DiagnosticWarn#" .. symbol
|
|
end
|
|
|
|
---Returns the status of the latest pipeline and the symbol
|
|
--representing the status of the current pipeline. Takes an optional argument to
|
|
---colorize the pipeline icon.
|
|
---@param wrap_with_color boolean
|
|
---@return string
|
|
M.get_pipeline_status = function(wrap_with_color)
|
|
M.latest_pipeline = get_latest_pipeline()
|
|
if not M.latest_pipeline then
|
|
return ""
|
|
end
|
|
return string.format("%s (%s)", M.get_pipeline_icon(wrap_with_color), M.latest_pipeline.status)
|
|
end
|
|
|
|
M.color_status = function(status, bufnr, status_line, linnr)
|
|
local ns_id = vim.api.nvim_create_namespace("GitlabNamespace")
|
|
vim.cmd(string.format("highlight default StatusHighlight guifg=%s", state.settings.pipeline[status]))
|
|
|
|
local status_to_color_map = {
|
|
created = "DiagnosticWarn",
|
|
pending = "DiagnosticWarn",
|
|
preparing = "DiagnosticWarn",
|
|
scheduled = "DiagnosticWarn",
|
|
running = "DiagnosticWarn",
|
|
canceled = "DiagnosticWarn",
|
|
skipped = "DiagnosticWarn",
|
|
failed = "DiagnosticError",
|
|
success = "DiagnosticOK",
|
|
}
|
|
|
|
vim.api.nvim_buf_set_extmark(
|
|
bufnr,
|
|
ns_id,
|
|
linnr - 1,
|
|
0,
|
|
{ end_row = linnr - 1, end_col = string.len(status_line), hl_group = status_to_color_map[status] }
|
|
)
|
|
end
|
|
|
|
return M
|