From f5bf720b6121e2f74b62f441a79490653eb4fada Mon Sep 17 00:00:00 2001 From: "Harrison (Harry) Cramer" <32515581+harrisoncramer@users.noreply.github.com> Date: Thu, 17 Aug 2023 16:22:53 -0400 Subject: [PATCH] Bugfix: Don't Start Server Right Away (#40) This MR simplifies the plugin quite a bit by only attempting to start the Go server after you specifically try to run a command. This streamlines working on feature branches and removes the need for a `base_branch` property entirely. --- README.md | 10 --- cmd/main.go | 2 +- lua/gitlab/comment.lua | 3 - lua/gitlab/discussions.lua | 2 - lua/gitlab/init.lua | 168 ++++++++++++++++++++----------------- lua/gitlab/keymaps.lua | 26 ------ lua/gitlab/state.lua | 1 - lua/gitlab/summary.lua | 1 - lua/gitlab/utils/init.lua | 34 -------- 9 files changed, 91 insertions(+), 156 deletions(-) diff --git a/README.md b/README.md index 2facb96..705e18e 100644 --- a/README.md +++ b/README.md @@ -71,18 +71,8 @@ If you don't want to write your authentication token into a dotfile, you may pro export GITLAB_TOKEN="your_gitlab_token" ``` -By default, the plugin will interact with MRs against a "main" branch. You can configure this by passing in the `base_branch` option to the `.gitlab.nvim` configuration file for your project. - -``` -project_id=112415 -auth_token=your_gitlab_token -gitlab_url=https://my-personal-gitlab-instance.com/ -base_branch=master -``` - ## Configuring the Plugin - Here is the default setup function. All of these values are optional, and if you call this function with no values the defaults will be used: ```lua diff --git a/cmd/main.go b/cmd/main.go index e81cc44..4b1a577 100644 --- a/cmd/main.go +++ b/cmd/main.go @@ -25,7 +25,7 @@ func main() { var c Client if err := c.init(branchName); err != nil { - log.Fatalf("Failure: Failed to initialize client: %v", err) + log.Fatalf("Failed to initialize Gitlab client: %v", err) } m := http.NewServeMux() diff --git a/lua/gitlab/comment.lua b/lua/gitlab/comment.lua index 32c71ef..e87c377 100644 --- a/lua/gitlab/comment.lua +++ b/lua/gitlab/comment.lua @@ -13,14 +13,12 @@ local edit_popup = Popup(u.create_popup_state("Edit Comment", "80%", "80 -- Function that fires to open the comment popup M.create_comment = function() - if u.base_invalid() then return end comment_popup:mount() keymaps.set_popup_keymaps(comment_popup, M.confirm_create_comment) end -- Actually sends the comment to Gitlab M.confirm_create_comment = function(text) - if u.base_invalid() then return end local relative_file_path = u.get_relative_file_path() local current_line_number = u.get_current_line_number() if relative_file_path == nil then return end @@ -110,7 +108,6 @@ end -- Function that opens the edit popup from the discussion tree M.edit_comment = function() - if u.base_invalid() then return end local current_node = state.tree:get_node() local note_node = discussions.get_note_node(current_node) local root_node = discussions.get_root_node(current_node) diff --git a/lua/gitlab/discussions.lua b/lua/gitlab/discussions.lua index 67968d2..fb5cd40 100644 --- a/lua/gitlab/discussions.lua +++ b/lua/gitlab/discussions.lua @@ -11,7 +11,6 @@ local M = {} local replyPopup = Popup(u.create_popup_state("Reply", "80%", "80%")) M.reply = function(discussion_id) - if u.base_invalid() then return end replyPopup:mount() keymaps.set_popup_keymaps(replyPopup, M.send_reply(discussion_id)) end @@ -28,7 +27,6 @@ end -- Places all of the discussions into a readable list M.list_discussions = function() - if u.base_invalid() then return end job.run_job("discussions", "GET", nil, function(data) if type(data.discussions) ~= "table" then vim.notify("No discussions for this MR") diff --git a/lua/gitlab/init.lua b/lua/gitlab/init.lua index 2118c58..e2fd0af 100644 --- a/lua/gitlab/init.lua +++ b/lua/gitlab/init.lua @@ -7,55 +7,10 @@ local comment = require("gitlab.comment") local job = require("gitlab.job") local u = require("gitlab.utils") --- Function names prefixed with "ensure" will ensure the plugin's state --- is initialized prior to running other calls. These functions run --- API calls if the state isn't initialized, which will set state containing --- information that's necessary for other API calls, like description, --- author, reviewer, etc. -local ensureState = function(callback) - return function() - if type(state.INFO) ~= "table" then - job.run_job("info", "GET", nil, function(data) - state.INFO = data.info - callback() - end) - else - callback() - end - end -end - -local ensureProjectMembers = function(callback) - return function() - if type(state.PROJECT_MEMBERS) ~= "table" then - job.run_job("members", "GET", nil, function(data) - state.PROJECT_MEMBERS = data.ProjectMembers - callback() - end) - else - callback() - end - end -end - --- Root Module Scope local M = {} -M.summary = ensureState(summary.summary) -M.approve = ensureState(job.approve) -M.revoke = ensureState(job.revoke) -M.list_discussions = ensureState(discussions.list_discussions) -M.create_comment = ensureState(comment.create_comment) -M.edit_comment = ensureState(comment.edit_comment) -M.delete_comment = ensureState(comment.delete_comment) -M.toggle_resolved = ensureState(comment.toggle_resolved) -M.add_reviewer = ensureProjectMembers(ensureState(assignees_and_reviewers.add_reviewer)) -M.delete_reviewer = ensureProjectMembers(ensureState(assignees_and_reviewers.delete_reviewer)) -M.add_assignee = ensureProjectMembers(ensureState(assignees_and_reviewers.add_assignee)) -M.delete_assignee = ensureProjectMembers(ensureState(assignees_and_reviewers.delete_assignee)) -M.reply = ensureState(discussions.reply) -M.state = state +M.args = nil --- Builds the binary (if not built); starts the Go server; sets the keymaps +-- Builds the binary (if not built) and sets the plugin arguments M.setup = function(args) if args == nil then args = {} end local file_path = u.current_file_path() @@ -67,34 +22,81 @@ M.setup = function(args) if binary_exists == nil then M.build() end if not M.setPluginConfiguration(args) then return end -- Return if not a valid gitlab project + M.args = args -- The ensureState function won't start without args +end +-- Function names prefixed with "ensure" will ensure the plugin's state +-- is initialized prior to running other calls. These functions run +-- API calls if the state isn't initialized, which will set state containing +-- information that's necessary for other API calls, like description, +-- author, reviewer, etc. - local command = state.BIN - .. " " - .. state.PROJECT_ID - .. " " - .. state.GITLAB_URL - .. " " - .. state.PORT - .. " " - .. state.AUTH_TOKEN - .. " " - .. state.LOG_PATH - - vim.fn.jobstart(command, { - on_stdout = function(job_id) - if job_id <= 0 then - vim.notify("Could not start gitlab.nvim binary", vim.log.levels.ERROR) - return - else - keymaps.set_keymap_keys(args.keymaps) - keymaps.set_keymaps() - end - end, - on_stderr = function(_, error) - vim.notify(error[1], vim.log.levels.ERROR) +-- This plugin will start the Go server and will call the "info" +-- endpoint and set the state of the MR. +M.go_server_running = false +M.ensureState = function(callback) + return function() + if not M.args then + vim.notify("The gitlab.nvim state was not set. Do you have a .gitlab.nvim file configured?", vim.log.levels.ERROR) + return end - }) + + if M.go_server_running then + callback() + return + end + + local command = state.BIN + .. " " + .. state.PROJECT_ID + .. " " + .. state.GITLAB_URL + .. " " + .. state.PORT + .. " " + .. state.AUTH_TOKEN + .. " " + .. state.LOG_PATH + + vim.fn.jobstart(command, { + on_stdout = function(job_id) + if job_id <= 0 then + vim.notify("Could not start gitlab.nvim binary", vim.log.levels.ERROR) + return + else + -- Once the Go binary has go_server_running, call the info endpoint to set global state + keymaps.set_keymap_keys(M.args.keymaps) + M.go_server_running = true + job.run_job("info", "GET", nil, function(data) + state.INFO = data.info + callback() + end) + end + end, + on_stderr = function(_, errors) + local err_msg = '' + for _, err in ipairs(errors) do + if err ~= "" and err ~= nil then + err_msg = err_msg .. err .. "\n" + end + end + vim.notify(err_msg, vim.log.levels.ERROR) + end + }) + end +end + +M.ensureProjectMembers = function(callback) + return function() + if type(state.PROJECT_MEMBERS) ~= "table" then + job.run_job("members", "GET", nil, function(data) + state.PROJECT_MEMBERS = data.ProjectMembers + callback() + end) + else + callback() + end + end end -- Builds the Go binary @@ -127,21 +129,15 @@ M.setPluginConfiguration = function(args) local project_id = property["project_id"] local gitlab_url = property["gitlab_url"] - local base_branch = property["base_branch"] local auth_token = property["auth_token"] state.PROJECT_ID = project_id state.AUTH_TOKEN = auth_token or os.getenv("GITLAB_TOKEN") state.GITLAB_URL = gitlab_url or "https://gitlab.com" - state.BASE_BRANCH = base_branch or "main" local current_branch_raw = io.popen("git rev-parse --abbrev-ref HEAD"):read("*a") local current_branch = string.gsub(current_branch_raw, "\n", "") - if current_branch == state.BASE_BRANCH then - return false - end - if state.AUTH_TOKEN == nil then error("Missing authentication token for Gitlab") end @@ -177,4 +173,20 @@ M.setPluginConfiguration = function(args) return true end +-- Root Module Scope +M.summary = M.ensureState(summary.summary) +M.approve = M.ensureState(job.approve) +M.revoke = M.ensureState(job.revoke) +M.list_discussions = M.ensureState(discussions.list_discussions) +M.create_comment = M.ensureState(comment.create_comment) +M.edit_comment = M.ensureState(comment.edit_comment) +M.delete_comment = M.ensureState(comment.delete_comment) +M.toggle_resolved = M.ensureState(comment.toggle_resolved) +M.reply = M.ensureState(discussions.reply) +M.add_reviewer = M.ensureProjectMembers(M.ensureState(assignees_and_reviewers.add_reviewer)) +M.delete_reviewer = M.ensureProjectMembers(M.ensureState(assignees_and_reviewers.delete_reviewer)) +M.add_assignee = M.ensureProjectMembers(M.ensureState(assignees_and_reviewers.add_assignee)) +M.delete_assignee = M.ensureProjectMembers(M.ensureState(assignees_and_reviewers.delete_assignee)) +M.state = state + return M diff --git a/lua/gitlab/keymaps.lua b/lua/gitlab/keymaps.lua index 55e5f35..a29c801 100644 --- a/lua/gitlab/keymaps.lua +++ b/lua/gitlab/keymaps.lua @@ -19,30 +19,4 @@ M.set_keymap_keys = function(keyTable) state.keymaps = u.merge_tables(state.keymaps, keyTable) end -M.set_keymaps = function() - local ok, _ = pcall(require, "diffview") - vim.keymap.set("n", state.keymaps.review.toggle, function() - if not ok then - require("notify")("You must have diffview.nvim installed to use this command!", "error") - return - end - local isDiff = vim.fn.getwinvar(nil, "&diff") - local bufName = vim.api.nvim_buf_get_name(0) - local has_develop = u.branch_exists("main") -- TODO: Write this function - if not has_develop then - require("notify")('No ' .. state.BASE_BRANCH .. ' branch, cannot review.', "error") - return - end - if isDiff ~= 0 or u.string_starts(bufName, "diff") then - vim.cmd.tabclose() - vim.cmd.tabprev() - else - vim.cmd.DiffviewOpen(state.BASE_BRANCH) - u.press_enter() - end - end) -end - - - return M diff --git a/lua/gitlab/state.lua b/lua/gitlab/state.lua index 44fb363..ff7ec74 100644 --- a/lua/gitlab/state.lua +++ b/lua/gitlab/state.lua @@ -5,7 +5,6 @@ M.BIN = nil M.PROJECT_ID = nil M.ACTIVE_DISCUSSION = nil M.ACTIVE_NOTE = nil -M.BASE_BRANCH = "main" M.keymaps = { popup = { exit = "", diff --git a/lua/gitlab/summary.lua b/lua/gitlab/summary.lua index 31d1feb..36d21e6 100644 --- a/lua/gitlab/summary.lua +++ b/lua/gitlab/summary.lua @@ -7,7 +7,6 @@ local descriptionPopup = Popup(u.create_popup_state("Loading Description...", "8 local M = {} M.summary = function() - if u.base_invalid() then return end descriptionPopup:mount() local currentBuffer = vim.api.nvim_get_current_buf() local title = state.INFO.title diff --git a/lua/gitlab/utils/init.lua b/lua/gitlab/utils/init.lua index 5ef7ad3..0854a18 100644 --- a/lua/gitlab/utils/init.lua +++ b/lua/gitlab/utils/init.lua @@ -54,19 +54,6 @@ local function get_buffer_text(bufnr) return text end -local feature_branch_exists = function(base_branch) - local is_git_branch = io.popen("git rev-parse --is-inside-work-tree 2>/dev/null"):read("*a") - if is_git_branch == "true\n" then - for line in io.popen("git branch 2>/dev/null"):lines() do - line = line:gsub("%s+", "") - if line == base_branch then - return true - end - end - end - return false -end - local string_starts = function(str, start) return str:sub(1, #start) == start end @@ -75,25 +62,6 @@ local press_enter = function() vim.api.nvim_feedkeys(vim.api.nvim_replace_termcodes("", false, true, true), "n", false) end -local base_invalid = function() - local current_branch_raw = io.popen("git rev-parse --abbrev-ref HEAD"):read("*a") - local current_branch = string.gsub(current_branch_raw, "\n", "") - - if current_branch == "main" or current_branch == "master" then - vim.notify('On ' .. current_branch .. ' branch, no MRs available', vim.log.levels.ERROR) - return true - end - - local base = state.BASE_BRANCH - local hasBaseBranch = feature_branch_exists(base) - if not hasBaseBranch then - vim.notify( - 'Could not fetch feature branch. Please check that you have the correct base_branch value set in your .gitlab.nvim configuration file', - vim.log.levels.ERROR) - return true - end -end - local format_date = function(date_string) local date_table = os.date("!*t") local year, month, day, hour, min, sec = date_string:match("(%d+)-(%d+)-(%d+)T(%d+):(%d+):(%d+)") @@ -302,10 +270,8 @@ M.join_tables = join_tables M.get_relative_file_path = get_relative_file_path M.get_current_line_number = get_current_line_number M.get_buffer_text = get_buffer_text -M.feature_branch_exists = feature_branch_exists M.press_enter = press_enter M.string_starts = string_starts -M.base_invalid = base_invalid M.format_date = format_date M.add_comment_sign = add_comment_sign M.jump_to_file = jump_to_file