From 0c69750eaaf896b75e1d8f30df5f94153d4ee75a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20F=2E=20Bortl=C3=ADk?= Date: Thu, 27 Feb 2025 18:02:54 +0100 Subject: [PATCH 1/9] Fix: Disable retries in the gitlab client Remove setting `retryClient.RetryMax` to 0 as it has no effect. --- cmd/app/client.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmd/app/client.go b/cmd/app/client.go index a599397c..d2caea93 100644 --- a/cmd/app/client.go +++ b/cmd/app/client.go @@ -68,8 +68,8 @@ func NewClient() (*Client, error) { retryClient := retryablehttp.NewClient() retryClient.HTTPClient.Transport = tr - retryClient.RetryMax = 0 gitlabOptions = append(gitlabOptions, gitlab.WithHTTPClient(retryClient.HTTPClient)) + gitlabOptions = append(gitlabOptions, gitlab.WithoutRetries()) client, err := gitlab.NewClient(pluginOptions.AuthToken, gitlabOptions...) From 938f2191023c97d0a13e7a70cb751dc912754939 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20F=2E=20Bortl=C3=ADk?= Date: Fri, 28 Feb 2025 23:19:41 +0100 Subject: [PATCH 2/9] Feat: Fetch the remote branch before checking it's up-to-date --- lua/gitlab/git.lua | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/lua/gitlab/git.lua b/lua/gitlab/git.lua index a633c86d..302f5952 100644 --- a/lua/gitlab/git.lua +++ b/lua/gitlab/git.lua @@ -58,12 +58,29 @@ M.get_remote_branch = function() return run_system({ "git", "rev-parse", "--abbrev-ref", "--symbolic-full-name", "@{u}" }) end +---Fetch the remote branch +---@param remote_branch string The name of the repo and branch to fetch (e.g., "origin/some_branch") +---@return boolean fetch_successfull False if an error occurred while fetching, true otherwise. +M.fetch_remote_branch = function(remote_branch) + local remote, branch = string.match(remote_branch, "([^/]+)/(.*)") + local _, fetch_err = run_system({ "git", "fetch", remote, branch }) + if fetch_err ~= nil then + require("gitlab.utils").notify("Error fetching remote-tracking branch: " .. fetch_err, vim.log.levels.ERROR) + return false + end + return true +end + ---Determines whether the tracking branch is ahead of or behind the current branch, and warns the user if so ---@param current_branch string ---@param remote_branch string ---@param log_level number ---@return boolean M.get_ahead_behind = function(current_branch, remote_branch, log_level) + if not M.fetch_remote_branch(remote_branch) then + return false + end + local u = require("gitlab.utils") local result, err = run_system({ "git", "rev-list", "--left-right", "--count", current_branch .. "..." .. remote_branch }) From ef11f8cff58a59e7f682db1a2ff4394a81002232 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20F=2E=20Bortl=C3=ADk?= Date: Fri, 28 Feb 2025 23:21:03 +0100 Subject: [PATCH 3/9] Feat: Check branch up-to-date before publishing drafts --- lua/gitlab/actions/draft_notes/init.lua | 3 +++ 1 file changed, 3 insertions(+) diff --git a/lua/gitlab/actions/draft_notes/init.lua b/lua/gitlab/actions/draft_notes/init.lua index e23665e9..d3aa4865 100755 --- a/lua/gitlab/actions/draft_notes/init.lua +++ b/lua/gitlab/actions/draft_notes/init.lua @@ -85,6 +85,9 @@ end ---Publishes all draft notes and comments. Re-renders all discussion views. M.confirm_publish_all_drafts = function() + if not git.check_current_branch_up_to_date_on_remote(vim.log.levels.ERROR) then + return + end local body = { publish_all = true } job.run_job("/mr/draft_notes/publish", "POST", body, function(data) u.notify(data.message, vim.log.levels.INFO) From b216c4b600c482a118b2f0c3c3ca2ff78f3a60c6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20F=2E=20Bortl=C3=ADk?= Date: Fri, 28 Feb 2025 23:29:42 +0100 Subject: [PATCH 4/9] Feat: Run on_error_callback when publishing drafts fails --- lua/gitlab/actions/draft_notes/init.lua | 10 ++++++++-- lua/gitlab/job.lua | 8 ++++++-- 2 files changed, 14 insertions(+), 4 deletions(-) diff --git a/lua/gitlab/actions/draft_notes/init.lua b/lua/gitlab/actions/draft_notes/init.lua index d3aa4865..f91334e6 100755 --- a/lua/gitlab/actions/draft_notes/init.lua +++ b/lua/gitlab/actions/draft_notes/init.lua @@ -4,6 +4,7 @@ -- under lua/gitlab/actions/discussions/init.lua local common = require("gitlab.actions.common") local discussion_tree = require("gitlab.actions.discussions.tree") +local git = require("gitlab.git") local job = require("gitlab.job") local NuiTree = require("nui.tree") local List = require("gitlab.utils.list") @@ -92,8 +93,13 @@ M.confirm_publish_all_drafts = function() job.run_job("/mr/draft_notes/publish", "POST", body, function(data) u.notify(data.message, vim.log.levels.INFO) state.DRAFT_NOTES = {} - local discussions = require("gitlab.actions.discussions") - discussions.rebuild_view(false, true) + require("gitlab.actions.discussions").rebuild_view(false, true) + end, function() + require("gitlab.actions.discussions").rebuild_view(false, true) + u.notify( + "Draft(s) may have been published despite the error. Check the discussion tree. Try publishing drafts individually.", + vim.log.levels.WARN + ) end) end diff --git a/lua/gitlab/job.lua b/lua/gitlab/job.lua index 128591be..33308210 100644 --- a/lua/gitlab/job.lua +++ b/lua/gitlab/job.lua @@ -4,7 +4,7 @@ local Job = require("plenary.job") local u = require("gitlab.utils") local M = {} -M.run_job = function(endpoint, method, body, callback) +M.run_job = function(endpoint, method, body, callback, on_error_callback) local state = require("gitlab.state") local args = { "-s", "-X", (method or "POST"), string.format("localhost:%s", state.settings.port) .. endpoint } @@ -16,7 +16,8 @@ M.run_job = function(endpoint, method, body, callback) -- This handler will handle all responses from the Go server. Anything with a successful -- status will call the callback (if it is supplied for the job). Otherwise, it will print out the - -- success message or error message and details from the Go server. + -- success message or error message and details from the Go server and run the on_error_callback + -- (if supplied for the job). local stderr = {} Job:new({ command = "curl", @@ -53,6 +54,9 @@ M.run_job = function(endpoint, method, body, callback) -- Handle error case local message = string.format("%s: %s", data.message, data.details) u.notify(message, vim.log.levels.ERROR) + if on_error_callback then + on_error_callback(data) + end end end, 0) end, From 17dbfa75f508cc94ca7f8b19777715f927df183a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20F=2E=20Bortl=C3=ADk?= Date: Fri, 28 Feb 2025 23:49:51 +0100 Subject: [PATCH 5/9] refactor: handle error in get_current_branch function --- lua/gitlab/git.lua | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/lua/gitlab/git.lua b/lua/gitlab/git.lua index 302f5952..f48265f1 100644 --- a/lua/gitlab/git.lua +++ b/lua/gitlab/git.lua @@ -121,17 +121,22 @@ M.get_ahead_behind = function(current_branch, remote_branch, log_level) return true -- Checks passed, branch is up-to-date end ----Return the name of the current branch ----@return string|nil, string|nil +---Return the name of the current branch or nil if it can't be retrieved +---@return string|nil M.get_current_branch = function() - return run_system({ "git", "branch", "--show-current" }) + local current_branch, err = run_system({ "git", "branch", "--show-current" }) + if err or not current_branch then + require("gitlab.utils").notify("Could not get current branch: " .. err, vim.log.levels.ERROR) + return nil + end + return current_branch end ---Return the list of possible merge targets. ---@return table|nil M.get_all_merge_targets = function() - local current_branch, err = M.get_current_branch() - if not current_branch or err ~= nil then + local current_branch = M.get_current_branch() + if current_branch == nil then return end return List.new(M.get_all_remote_branches()):filter(function(branch) @@ -177,10 +182,8 @@ end M.check_current_branch_up_to_date_on_remote = function(log_level) local u = require("gitlab.utils") - -- Get current branch - local current_branch, err_current_branch = M.get_current_branch() - if err_current_branch or not current_branch then - u.notify("Could not get current branch: " .. err_current_branch, vim.log.levels.ERROR) + local current_branch = M.get_current_branch() + if current_branch == nil then return false end From b84bf94dbee53fa7a5f6aaefe0057cea80741225 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20F=2E=20Bortl=C3=ADk?= Date: Sat, 1 Mar 2025 00:03:51 +0100 Subject: [PATCH 6/9] refactor: handle error in get_remote_branch function --- lua/gitlab/git.lua | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/lua/gitlab/git.lua b/lua/gitlab/git.lua index f48265f1..224f5d6d 100644 --- a/lua/gitlab/git.lua +++ b/lua/gitlab/git.lua @@ -52,10 +52,15 @@ M.switch_branch = function(branch) return run_system({ "git", "checkout", "-q", branch }) end ----Fetches the name of the remote tracking branch for the current branch ----@return string|nil, string|nil +---Returns the name of the remote-tracking branch for the current branch or nil if it can't be found +---@return string|nil M.get_remote_branch = function() - return run_system({ "git", "rev-parse", "--abbrev-ref", "--symbolic-full-name", "@{u}" }) + local remote_branch, err = run_system({ "git", "rev-parse", "--abbrev-ref", "--symbolic-full-name", "@{u}" }) + if err or not remote_branch then + require("gitlab.utils").notify("Could not get remote branch: " .. err, vim.log.levels.ERROR) + return nil + end + return remote_branch end ---Fetch the remote branch @@ -180,17 +185,13 @@ end ---@param log_level integer ---@return boolean M.check_current_branch_up_to_date_on_remote = function(log_level) - local u = require("gitlab.utils") - local current_branch = M.get_current_branch() if current_branch == nil then return false end - -- Get remote tracking branch - local remote_branch, err_remote_branch = M.get_remote_branch() - if err_remote_branch or not remote_branch then - u.notify("Could not get remote branch: " .. err_remote_branch, vim.log.levels.ERROR) + local remote_branch = M.get_remote_branch() + if remote_branch == nil then return false end From 1e7fc6780d28d4b4bf0bbfe2ff1ec5740098c295 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20F=2E=20Bortl=C3=ADk?= Date: Sat, 1 Mar 2025 00:04:58 +0100 Subject: [PATCH 7/9] fix: the empty string doesn't evaluate to false --- lua/gitlab/git.lua | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lua/gitlab/git.lua b/lua/gitlab/git.lua index 224f5d6d..04aa2b42 100644 --- a/lua/gitlab/git.lua +++ b/lua/gitlab/git.lua @@ -56,7 +56,7 @@ end ---@return string|nil M.get_remote_branch = function() local remote_branch, err = run_system({ "git", "rev-parse", "--abbrev-ref", "--symbolic-full-name", "@{u}" }) - if err or not remote_branch then + if err or remote_branch == "" then require("gitlab.utils").notify("Could not get remote branch: " .. err, vim.log.levels.ERROR) return nil end @@ -130,7 +130,7 @@ end ---@return string|nil M.get_current_branch = function() local current_branch, err = run_system({ "git", "branch", "--show-current" }) - if err or not current_branch then + if err or current_branch == "" then require("gitlab.utils").notify("Could not get current branch: " .. err, vim.log.levels.ERROR) return nil end From c4ef505a5a4be388871e5bafaa39a69c343ddf8d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20F=2E=20Bortl=C3=ADk?= Date: Sat, 1 Mar 2025 00:07:30 +0100 Subject: [PATCH 8/9] refactor: only require utils when they are needed --- lua/gitlab/git.lua | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/lua/gitlab/git.lua b/lua/gitlab/git.lua index 04aa2b42..ba42546e 100644 --- a/lua/gitlab/git.lua +++ b/lua/gitlab/git.lua @@ -6,11 +6,9 @@ local M = {} ---@param command table ---@return string|nil, string|nil local run_system = function(command) - -- Load here to prevent loop - local u = require("gitlab.utils") local result = vim.fn.trim(vim.fn.system(command)) if vim.v.shell_error ~= 0 then - u.notify(result, vim.log.levels.ERROR) + require("gitlab.utils").notify(result, vim.log.levels.ERROR) return nil, result end return result, nil From d523ea2b1c4c963576fe77766f4304a6035c29de Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20F=2E=20Bortl=C3=ADk?= Date: Sat, 1 Mar 2025 00:39:58 +0100 Subject: [PATCH 9/9] Feat: Fetch remote branch before publishing single draft --- lua/gitlab/actions/draft_notes/init.lua | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/lua/gitlab/actions/draft_notes/init.lua b/lua/gitlab/actions/draft_notes/init.lua index f91334e6..5348f198 100755 --- a/lua/gitlab/actions/draft_notes/init.lua +++ b/lua/gitlab/actions/draft_notes/init.lua @@ -108,6 +108,9 @@ end ---and re-render it. ---@param tree NuiTree M.confirm_publish_draft = function(tree) + if not git.check_current_branch_up_to_date_on_remote(vim.log.levels.ERROR) then + return + end local current_node = tree:get_node() local note_node = common.get_note_node(tree, current_node) local root_node = common.get_root_node(tree, current_node) @@ -120,12 +123,13 @@ M.confirm_publish_draft = function(tree) ---@type integer local note_id = note_node.is_root and root_node.id or note_node.id local body = { note = note_id } + local unlinked = tree.bufnr == require("gitlab.actions.discussions").unlinked_bufnr job.run_job("/mr/draft_notes/publish", "POST", body, function(data) u.notify(data.message, vim.log.levels.INFO) - - local discussions = require("gitlab.actions.discussions") - local unlinked = tree.bufnr == discussions.unlinked_bufnr M.rebuild_view(unlinked) + end, function() + M.rebuild_view(unlinked) + u.notify("Draft may have been published despite the error. Check the discussion tree.", vim.log.levels.WARN) end) end