Skip to content

Commit 508a394

Browse files
authored
Fix: Checking whether comment can be created (#434)
1 parent 606d931 commit 508a394

File tree

6 files changed

+142
-119
lines changed

6 files changed

+142
-119
lines changed

lua/gitlab/actions/comment.lua

Lines changed: 85 additions & 89 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@
33
--- to this module the data required to make the API calls
44
local Popup = require("nui.popup")
55
local Layout = require("nui.layout")
6-
local diffview_lib = require("diffview.lib")
76
local state = require("gitlab.state")
87
local job = require("gitlab.job")
98
local u = require("gitlab.utils")
@@ -47,6 +46,18 @@ local confirm_create_comment = function(text, visual_range, unlinked, discussion
4746
return
4847
end
4948

49+
-- Creating a draft reply, in response to a discussion ID
50+
if discussion_id ~= nil and is_draft then
51+
local body = { comment = text, discussion_id = discussion_id }
52+
job.run_job("/mr/draft_notes/", "POST", body, function()
53+
u.notify("Draft reply created!", vim.log.levels.INFO)
54+
draft_notes.load_draft_notes(function()
55+
discussions.rebuild_view(unlinked)
56+
end)
57+
end)
58+
return
59+
end
60+
5061
-- Creating a note (unlinked comment)
5162
if unlinked and discussion_id == nil then
5263
local body = { comment = text }
@@ -90,18 +101,6 @@ local confirm_create_comment = function(text, visual_range, unlinked, discussion
90101
line_range = location_data.line_range,
91102
}
92103

93-
-- Creating a draft reply, in response to a discussion ID
94-
if discussion_id ~= nil and is_draft then
95-
local body = { comment = text, discussion_id = discussion_id, position = position_data }
96-
job.run_job("/mr/draft_notes/", "POST", body, function()
97-
u.notify("Draft reply created!", vim.log.levels.INFO)
98-
draft_notes.load_draft_notes(function()
99-
discussions.rebuild_view(unlinked)
100-
end)
101-
end)
102-
return
103-
end
104-
105104
-- Creating a new comment (linked to specific changes)
106105
local body = u.merge({ type = "text", comment = text }, position_data)
107106
local endpoint = is_draft and "/mr/draft_notes/" or "/mr/comment"
@@ -158,46 +157,8 @@ end
158157
---multi-line comment. It also sets up the basic keybindings for switching between
159158
---window panes, and for the non-primary sections.
160159
---@param opts LayoutOpts
161-
---@return NuiLayout|nil
160+
---@return NuiLayout
162161
M.create_comment_layout = function(opts)
163-
if opts.unlinked ~= true and opts.discussion_id == nil then
164-
-- Check that diffview is initialized
165-
if reviewer.tabnr == nil then
166-
u.notify("Reviewer must be initialized first", vim.log.levels.ERROR)
167-
return
168-
end
169-
170-
-- Check that Diffview is the current view
171-
local view = diffview_lib.get_current_view()
172-
if view == nil and not opts.reply then
173-
u.notify("Comments should be left in the reviewer pane", vim.log.levels.ERROR)
174-
return
175-
end
176-
177-
-- Check that we are in the diffview tab
178-
local tabnr = vim.api.nvim_get_current_tabpage()
179-
if tabnr ~= reviewer.tabnr then
180-
u.notify("Line location can only be determined within reviewer window", vim.log.levels.ERROR)
181-
return
182-
end
183-
184-
-- Check that the file has not been renamed
185-
if reviewer.is_file_renamed() and not reviewer.does_file_have_changes() then
186-
u.notify("Commenting on (unchanged) renamed or moved files is not supported", vim.log.levels.WARN)
187-
return
188-
end
189-
190-
-- Check that we are hovering over the code
191-
local filetype = vim.bo[0].filetype
192-
if not opts.reply and (filetype == "DiffviewFiles" or filetype == "gitlab") then
193-
u.notify(
194-
"Comments can only be left on the code. To leave unlinked comments, use gitlab.create_note() instead",
195-
vim.log.levels.ERROR
196-
)
197-
return
198-
end
199-
end
200-
201162
local popup_settings = state.settings.popup
202163
local title
203164
local user_settings
@@ -262,53 +223,31 @@ end
262223
--- This function will open a comment popup in order to create a comment on the changed/updated
263224
--- line in the current MR
264225
M.create_comment = function()
265-
local has_clean_tree, err = git.has_clean_tree()
266-
if err ~= nil then
267-
return
268-
end
269-
270-
local is_modified = vim.bo[0].modified
271-
if state.settings.reviewer_settings.diffview.imply_local and (is_modified or not has_clean_tree) then
272-
u.notify(
273-
"Cannot leave comments on changed files. \n Please stash all local changes or push them to the feature branch.",
274-
vim.log.levels.WARN
275-
)
276-
return
277-
end
278-
279-
if not M.sha_exists() then
226+
if not M.can_create_comment(false) then
280227
return
281228
end
282229

283230
local layout = M.create_comment_layout({ ranged = false, unlinked = false })
284-
if layout ~= nil then
285-
layout:mount()
286-
end
231+
layout:mount()
287232
end
288233

289234
--- This function will open a multi-line comment popup in order to create a multi-line comment
290235
--- on the changed/updated line in the current MR
291236
M.create_multiline_comment = function()
292-
if not u.check_visual_mode() then
293-
return
294-
end
295-
if not M.sha_exists() then
237+
if not M.can_create_comment(true) then
238+
u.press_escape()
296239
return
297240
end
298241

299242
local layout = M.create_comment_layout({ ranged = true, unlinked = false })
300-
if layout ~= nil then
301-
layout:mount()
302-
end
243+
layout:mount()
303244
end
304245

305246
--- This function will open a a popup to create a "note" (e.g. unlinked comment)
306247
--- on the changed/updated line in the current MR
307248
M.create_note = function()
308249
local layout = M.create_comment_layout({ ranged = false, unlinked = true })
309-
if layout ~= nil then
310-
layout:mount()
311-
end
250+
layout:mount()
312251
end
313252

314253
---Given the current visually selected area of text, builds text to fill in the
@@ -353,28 +292,85 @@ end
353292
--- on the changed/updated line in the current MR
354293
--- See: https://docs.gitlab.com/ee/user/project/merge_requests/reviews/suggestions.html
355294
M.create_comment_suggestion = function()
356-
if not u.check_visual_mode() then
357-
return
358-
end
359-
if not M.sha_exists() then
295+
if not M.can_create_comment(true) then
296+
u.press_escape()
360297
return
361298
end
362299

363300
local suggestion_lines, range_length = build_suggestion()
364301

365302
local layout = M.create_comment_layout({ ranged = range_length > 0, unlinked = false })
366-
if layout ~= nil then
367-
layout:mount()
368-
else
369-
return -- Failure in creating the comment layout
370-
end
303+
layout:mount()
304+
371305
vim.schedule(function()
372306
if suggestion_lines then
373307
vim.api.nvim_buf_set_lines(M.comment_popup.bufnr, 0, -1, false, suggestion_lines)
374308
end
375309
end)
376310
end
377311

312+
---Returns true if it's possible to create an Inline Comment
313+
---@param must_be_visual boolean True if current mode must be visual
314+
---@return boolean
315+
M.can_create_comment = function(must_be_visual)
316+
-- Check that diffview is initialized
317+
if reviewer.tabnr == nil then
318+
u.notify("Reviewer must be initialized first", vim.log.levels.ERROR)
319+
return false
320+
end
321+
322+
-- Check that we are in the Diffview tab
323+
local tabnr = vim.api.nvim_get_current_tabpage()
324+
if tabnr ~= reviewer.tabnr then
325+
u.notify("Comments can only be left in the reviewer pane", vim.log.levels.ERROR)
326+
return false
327+
end
328+
329+
-- Check that we are hovering over the code
330+
local filetype = vim.bo[0].filetype
331+
if filetype == "DiffviewFiles" or filetype == "gitlab" then
332+
u.notify(
333+
"Comments can only be left on the code. To leave unlinked comments, use gitlab.create_note() instead",
334+
vim.log.levels.ERROR
335+
)
336+
return false
337+
end
338+
339+
-- Check that the file has not been renamed
340+
if reviewer.is_file_renamed() and not reviewer.does_file_have_changes() then
341+
u.notify("Commenting on (unchanged) renamed or moved files is not supported", vim.log.levels.ERROR)
342+
return false
343+
end
344+
345+
-- Check that we are in a valid buffer
346+
if not M.sha_exists() then
347+
return false
348+
end
349+
350+
-- Check that there aren't saved modifications
351+
local file = reviewer.get_current_file_path()
352+
if file == nil then
353+
return false
354+
end
355+
local has_changes, err = git.has_changes(file)
356+
if err ~= nil then
357+
return false
358+
end
359+
-- Check that there aren't unsaved modifications
360+
local is_modified = vim.bo[0].modified
361+
if state.settings.reviewer_settings.diffview.imply_local and (is_modified or has_changes) then
362+
u.notify("Cannot leave comments on changed files, please stash or commit and push", vim.log.levels.ERROR)
363+
return false
364+
end
365+
366+
-- Check we're in visual mode for code suggestions and multiline comments
367+
if must_be_visual and not u.check_visual_mode() then
368+
return false
369+
end
370+
371+
return true
372+
end
373+
378374
---Checks to see whether you are commenting on a valid buffer. The Diffview plugin names non-existent
379375
---buffers as 'null'
380376
---@return boolean

lua/gitlab/actions/discussions/init.lua

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -253,9 +253,7 @@ M.reply = function(tree)
253253
reply = true,
254254
})
255255

256-
if layout then
257-
layout:mount()
258-
end
256+
layout:mount()
259257
end
260258

261259
-- This function (settings.keymaps.discussion_tree.delete_comment) will trigger a popup prompting you to delete the current comment

lua/gitlab/actions/merge_requests.lua

Lines changed: 13 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -12,14 +12,6 @@ local M = {}
1212
---Opens up a select menu that lets you choose a different merge request.
1313
---@param opts ChooseMergeRequestOptions|nil
1414
M.choose_merge_request = function(opts)
15-
local has_clean_tree, clean_tree_err = git.has_clean_tree()
16-
if clean_tree_err ~= nil then
17-
return
18-
elseif has_clean_tree ~= "" then
19-
u.notify("Your local branch has changes, please stash or commit and push", vim.log.levels.ERROR)
20-
return
21-
end
22-
2315
if opts == nil then
2416
opts = state.settings.choose_merge_request
2517
end
@@ -38,6 +30,19 @@ M.choose_merge_request = function(opts)
3830
reviewer.close()
3931
end
4032

33+
if choice.source_branch ~= git.get_current_branch() then
34+
local has_clean_tree, clean_tree_err = git.has_clean_tree()
35+
if clean_tree_err ~= nil then
36+
return
37+
elseif not has_clean_tree then
38+
u.notify(
39+
"Cannot switch branch when working tree has changes, please stash or commit and push",
40+
vim.log.levels.ERROR
41+
)
42+
return
43+
end
44+
end
45+
4146
vim.schedule(function()
4247
local _, branch_switch_err = git.switch_branch(choice.source_branch)
4348
if branch_switch_err ~= nil then

lua/gitlab/git.lua

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -25,10 +25,19 @@ M.branches = function(args)
2525
return run_system(u.combine({ "git", "branch" }, args or {}))
2626
end
2727

28-
---Checks whether the tree has any changes that haven't been pushed to the remote
29-
---@return string|nil, string|nil
28+
---Returns true if the working tree hasn't got any changes that haven't been commited
29+
---@return boolean, string|nil
3030
M.has_clean_tree = function()
31-
return run_system({ "git", "status", "--short", "--untracked-files=no" })
31+
local changes, err = run_system({ "git", "status", "--short", "--untracked-files=no" })
32+
return changes == "", err
33+
end
34+
35+
---Returns true if the `file` has got any uncommitted changes
36+
---@param file string File to check for changes
37+
---@return boolean, string|nil
38+
M.has_changes = function(file)
39+
local changes, err = run_system({ "git", "status", "--short", "--untracked-files=no", "--", file })
40+
return changes ~= "", err
3241
end
3342

3443
---Gets the base directory of the current project

lua/gitlab/reviewer/init.lua

Lines changed: 20 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -42,26 +42,28 @@ M.open = function()
4242
end
4343

4444
local diffview_open_command = "DiffviewOpen"
45-
local has_clean_tree, err = git.has_clean_tree()
46-
if err ~= nil then
47-
return
48-
end
49-
if state.settings.reviewer_settings.diffview.imply_local and has_clean_tree then
50-
diffview_open_command = diffview_open_command .. " --imply-local"
45+
46+
if state.settings.reviewer_settings.diffview.imply_local then
47+
local has_clean_tree, err = git.has_clean_tree()
48+
if err ~= nil then
49+
return
50+
end
51+
if has_clean_tree then
52+
diffview_open_command = diffview_open_command .. " --imply-local"
53+
else
54+
u.notify(
55+
"Your working tree has changes, cannot use 'imply_local' setting for gitlab reviews.\n Stash or commit all changes to use.",
56+
vim.log.levels.WARN
57+
)
58+
state.settings.reviewer_settings.diffview.imply_local = false
59+
end
5160
end
5261

5362
vim.api.nvim_command(string.format("%s %s..%s", diffview_open_command, diff_refs.base_sha, diff_refs.head_sha))
5463

5564
M.is_open = true
5665
M.tabnr = vim.api.nvim_get_current_tabpage()
5766

58-
if state.settings.reviewer_settings.diffview.imply_local and not has_clean_tree then
59-
u.notify(
60-
"There are uncommited changes in the working tree, cannot use 'imply_local' setting for gitlab reviews.\n Stash or commit all changes to use.",
61-
vim.log.levels.WARN
62-
)
63-
end
64-
6567
if state.settings.discussion_diagnostic ~= nil or state.settings.discussion_sign ~= nil then
6668
u.notify(
6769
"Diagnostics are now configured as settings.discussion_signs, see :h gitlab.nvim.signs-and-diagnostics",
@@ -289,12 +291,16 @@ end
289291
M.execute_callback = function(callback)
290292
return function()
291293
vim.api.nvim_cmd({ cmd = "normal", bang = true, args = { "'[V']" } }, {})
292-
vim.api.nvim_cmd(
294+
local _, err = pcall(
295+
vim.api.nvim_cmd,
293296
{ cmd = "lua", args = { ("require'gitlab'.%s()"):format(callback) }, mods = { lockmarks = true } },
294297
{}
295298
)
296299
vim.api.nvim_win_set_cursor(M.old_winnr, M.old_cursor_position)
297300
vim.opt.operatorfunc = M.old_opfunc
301+
if err ~= "" then
302+
u.notify_vim_error(err, vim.log.levels.ERROR)
303+
end
298304
end
299305
end
300306

0 commit comments

Comments
 (0)