FazBrowse GitHub Viewer | Trending |
URL:
| Home
Tools: [Download Repo ZIP]   [Original HTTPS Page]

GitHub Viewer

-- This module is responsible for holding and setting shared state between -- modules, such as keybinding data and other settings and configuration. -- This module is also responsible for ensuring that the state of the plugin -- is valid via dependencies local u = require("gitlab.utils") local List = require("gitlab.utils.list") local M = { ahead_behind = { nil, nil }, -- Initial states of the discussion trees discussion_tree = { last_updated = nil, updating = 0, resolved_expanded = false, unresolved_expanded = false, }, unlinked_discussion_tree = { resolved_expanded = false, unresolved_expanded = false, }, -- Used to set a specific MR when choosing a merge request chosen_mr_iid = 0, } ---Return a gitlab token and a gitlab URL required to connect to Gitlab. ---TODO: Remove the third return value - it is always nil. ---@return string?, string?, string? M.default_auth_provider = function() local git = require("gitlab.git") local base_path, err = M.settings.config_path, nil if base_path == nil then base_path, err = git.base_dir() end if err ~= nil then return "", "" end local config_file_path = base_path .. M.settings.file_separator .. ".gitlab.nvim" local config_file_content = u.read_file(config_file_path, { remove_newlines = true }) local file_properties = {} if config_file_content ~= nil then local file = assert(io.open(config_file_path, "r")) for line in file:lines() do for key, value in string.gmatch(line, "(.-)=(.-)$") do file_properties[key] = value end end end local auth_token = file_properties.auth_token or os.getenv("GITLAB_TOKEN") local gitlab_url = file_properties.gitlab_url or os.getenv("GITLAB_URL") return auth_token, gitlab_url, err end ---The default settings for the plugin. M.settings = { auth_provider = M.default_auth_provider, -- TODO: Remove file_separator, replace with u.path_separator in code. file_separator = u.path_separator, server = { binary = nil, port = nil, }, debug = { request = false, response = false, gitlab_request = false, gitlab_response = false, }, log_path = (vim.fn.stdpath("cache") .. "/gitlab.nvim.log"), config_path = nil, reviewer = "diffview", reviewer_settings = { jump_with_no_diagnostics = false, diffview = { imply_local = false, }, }, connection_settings = { proxy = "", insecure = false, remote = "origin", }, attachment_dir = "", keymaps = { disable_all = false, help = "g?", global = { disable_all = false, add_assignee = "glaa", delete_assignee = "glad", add_label = "glla", delete_label = "glld", add_reviewer = "glra", delete_reviewer = "glrd", approve = "glA", revoke = "glR", merge = "glM", set_auto_merge = "glm", rebase = "glrr", rebase_skip_ci = "glrs", rebase_force = "glrf", create_mr = "glC", choose_merge_request = "glc", start_review = "glS", reload_review = "gl", close_review = "glQ", summary = "gls", copy_mr_url = "glu", open_in_browser = "glo", create_note = "gln", pipeline = "glp", toggle_discussions = "gld", toggle_draft_mode = "glD", publish_all_drafts = "glP", }, popup = { disable_all = false, next_field = "", prev_field = "", perform_action = "ZZ", perform_linewise_action = "ZA", discard_changes = "ZQ", }, discussion_tree = { disable_all = false, add_emoji = "Ea", delete_emoji = "Ed", delete_comment = "dd", edit_comment = "e", reply = "r", toggle_resolved = "-", jump_to_file = "o", jump_to_reviewer = "a", open_in_browser = "b", copy_node_url = "u", switch_view = "c", toggle_tree_type = "i", publish_draft = "P", toggle_date_format = "dt", toggle_draft_mode = "D", toggle_sort_method = "st", toggle_node = "t", toggle_all_discussions = "T", toggle_resolved_discussions = "R", toggle_unresolved_discussions = "U", refresh_data = "", print_node = "p", }, reviewer = { disable_all = false, create_comment = "c", create_suggestion = "s", move_to_discussion_tree = "a", }, }, popup = { width = "40%", height = "60%", position = "50%", border = "rounded", opacity = 1.0, comment = nil, edit = nil, note = nil, help = nil, pipeline = nil, reply = nil, squash_message = nil, create_mr = { width = "95%", height = "95%" }, summary = { width = "95%", height = "95%" }, temp_registers = {}, }, discussion_tree = { expanders = { expanded = " ", collapsed = " ", indentation = " ", }, spinner_chars = { "-", "\\", "|", "/" }, auto_open = true, focus_on_open = true, default_view = "discussions", blacklist = {}, sort_by = "latest_reply", keep_current_open = false, position = "bottom", size = "20%", relative = "editor", resolved = "✓", unresolved = "-", unlinked = "󰌸", draft = "✎", tree_type = "simple", draft_mode = false, relative_date = true, winopts = { number = false, relativenumber = false, breakindent = true, showbreak = "+ ", }, }, emojis = { formatter = nil, version = "4", }, create_mr = { target = nil, template_file = nil, delete_branch = false, squash = false, -- TODO: The "fork" settings could be a config in .gitlab.nvim - they seem to be project-local fork = { enabled = false, forked_project_id = nil, }, title_input = { width = 40, border = "rounded", }, }, rebase_mr = { skip_ci = false, force = false, }, choose_merge_request = { open_reviewer = true, }, info = { enabled = true, horizontal = false, fields = { "author", "created_at", "updated_at", "merge_status", "draft", "conflicts", "assignees", "reviewers", "pipeline", "branch", "target_branch", "auto_merge", "delete_branch", "squash", "labels", "web_url", "mergeability_checks", }, }, mergeability_checks = { statuses = { SUCCESS = "✅", CHECKING = "🔁", FAILED = "❌", WARNING = "⚠️", INACTIVE = "💤", }, checks = { CI_MUST_PASS = "Pipeline must succeed", COMMITS_STATUS = "Source branch exists and contains commits", CONFLICT = "Merge conflicts must be resolved", DISCUSSIONS_NOT_RESOLVED = "Open threads must be resolved", DRAFT_STATUS = "Merge request must not be draft", JIRA_ASSOCIATION_MISSING = "Title or description references a Jira issue", LOCKED_LFS_FILES = "All LFS files must be unlocked", LOCKED_PATHS = "All paths must be unlocked", MERGE_REQUEST_BLOCKED = "Merge request is not blocked", MERGE_TIME = "Merge is not blocked due to a scheduled merge time", NEED_REBASE = "Merge request must be rebased, fast-forward merge is not possible", NOT_APPROVED = "All required approvals must be given", NOT_OPEN = "Merge request must be open", REQUESTED_CHANGES = "Change requests must be approved by the requesting user", SECURITY_POLICY_PIPELINE_CHECK = "Security policy pipeline must succeed", SECURITY_POLICY_VIOLATIONS = "Security policies are satisfied", STATUS_CHECKS_MUST_PASS = "External status checks pass", TITLE_REGEX = "Title matches the expected regex", }, }, discussion_signs = { enabled = true, skip_resolved_discussion = false, severity = vim.diagnostic.severity.INFO, virtual_text = false, use_diagnostic_signs = true, priority = 100, icons = { comment = "→|", range = " |", }, skip_old_revision_discussion = false, }, pipeline = { created = "", pending = "", preparing = "", scheduled = "", running = "", canceled = "↪", skipped = "↪", success = "✓", failed = "", }, colors = { discussion_tree = { username = "Keyword", mention = "WarningMsg", date = "Comment", unlinked = "DiffviewNonText", expander = "DiffviewNonText", directory = "Directory", directory_icon = "DiffviewFolderSign", file_name = "Normal", resolved = "DiagnosticSignOk", unresolved = "DiagnosticSignWarn", draft = "DiffviewReference", draft_mode = "DiagnosticWarn", live_mode = "DiagnosticOk", sort_method = "Keyword", }, }, } ---Set global keymaps. ---To be used when the plugin is initialized. M.set_global_keymaps = function() local keymaps = M.settings.keymaps if keymaps.disable_all or keymaps.global.disable_all then return end -- TODO: Refactor: simplify all the `function() somefunc() end` calls to `somefunc`. if keymaps.global.start_review then vim.keymap.set("n", keymaps.global.start_review, function() require("gitlab").review() end, { desc = "Start Gitlab review", nowait = keymaps.global.start_review_nowait }) end if keymaps.global.reload_review then vim.keymap.set("n", keymaps.global.reload_review, function() require("gitlab").reload_review() end, { desc = "Reload Gitlab review", nowait = keymaps.global.reload_review_nowait }) end if keymaps.global.close_review then vim.keymap.set("n", keymaps.global.close_review, function() require("gitlab").close_review() end, { desc = "Close Gitlab review", nowait = keymaps.global.close_review_nowait }) end if keymaps.global.choose_merge_request then vim.keymap.set("n", keymaps.global.choose_merge_request, function() require("gitlab").choose_merge_request() end, { desc = "Choose MR for review", nowait = keymaps.global.choose_merge_request_nowait }) end if keymaps.global.summary then vim.keymap.set("n", keymaps.global.summary, function() require("gitlab").summary() end, { desc = "Show MR summary", nowait = keymaps.global.summary_nowait }) end if keymaps.global.approve then vim.keymap.set("n", keymaps.global.approve, function() require("gitlab").approve() end, { desc = "Approve MR", nowait = keymaps.global.approve_nowait }) end if keymaps.global.revoke then vim.keymap.set("n", keymaps.global.revoke, function() require("gitlab").revoke() end, { desc = "Revoke approval", nowait = keymaps.global.revoke_nowait }) end if keymaps.global.create_mr then vim.keymap.set("n", keymaps.global.create_mr, function() require("gitlab").create_mr() end, { desc = "Create MR", nowait = keymaps.global.create_mr_nowait }) end if keymaps.global.create_note then vim.keymap.set("n", keymaps.global.create_note, function() require("gitlab").create_note() end, { desc = "Create MR note", nowait = keymaps.global.create_note_nowait }) end if keymaps.global.toggle_discussions then vim.keymap.set("n", keymaps.global.toggle_discussions, function() require("gitlab").toggle_discussions() end, { desc = "Toggle MR discussions", nowait = keymaps.global.toggle_discussions_nowait }) end if keymaps.global.add_assignee then vim.keymap.set("n", keymaps.global.add_assignee, function() require("gitlab").add_assignee() end, { desc = "Add MR assignee", nowait = keymaps.global.add_assignee_nowait }) end if keymaps.global.delete_assignee then vim.keymap.set("n", keymaps.global.delete_assignee, function() require("gitlab").delete_assignee() end, { desc = "Delete MR assignee", nowait = keymaps.global.delete_assignee_nowait }) end if keymaps.global.add_label then vim.keymap.set("n", keymaps.global.add_label, function() require("gitlab").add_label() end, { desc = "Add MR label", nowait = keymaps.global.add_label_nowait }) end if keymaps.global.delete_label then vim.keymap.set("n", keymaps.global.delete_label, function() require("gitlab").delete_label() end, { desc = "Delete MR label", nowait = keymaps.global.delete_label_nowait }) end if keymaps.global.add_reviewer then vim.keymap.set("n", keymaps.global.add_reviewer, function() require("gitlab").add_reviewer() end, { desc = "Add MR reviewer", nowait = keymaps.global.add_reviewer_nowait }) end if keymaps.global.delete_reviewer then vim.keymap.set("n", keymaps.global.delete_reviewer, function() require("gitlab").delete_reviewer() end, { desc = "Delete MR reviewer", nowait = keymaps.global.delete_reviewer_nowait }) end if keymaps.global.pipeline then vim.keymap.set("n", keymaps.global.pipeline, function() require("gitlab").pipeline() end, { desc = "Show MR pipeline status", nowait = keymaps.global.pipeline_nowait }) end if keymaps.global.open_in_browser then vim.keymap.set("n", keymaps.global.open_in_browser, function() require("gitlab").open_in_browser() end, { desc = "Open MR in browser", nowait = keymaps.global.open_in_browser_nowait }) end if keymaps.global.merge then vim.keymap.set("n", keymaps.global.merge, function() require("gitlab").merge() end, { desc = "Merge MR", nowait = keymaps.global.merge_nowait }) end if keymaps.global.set_auto_merge then vim.keymap.set("n", keymaps.global.set_auto_merge, function() require("gitlab").merge({ auto_merge = true }) end, { desc = "Set MR to auto-merge", nowait = keymaps.global.set_auto_merge_nowait }) end if keymaps.global.rebase then vim.keymap.set("n", keymaps.global.rebase, function() require("gitlab").rebase() end, { desc = "Rebase MR", nowait = keymaps.global.rebase_nowait }) end if keymaps.global.rebase_skip_ci then vim.keymap.set("n", keymaps.global.rebase_skip_ci, function() require("gitlab").rebase({ skip_ci = true }) end, { desc = "Rebase MR and skip CI", nowait = keymaps.global.rebase_skip_ci_nowait }) end if keymaps.global.rebase_force then vim.keymap.set("n", keymaps.global.rebase_force, function() require("gitlab").rebase({ force = true }) end, { desc = "Force rebase MR", nowait = keymaps.global.rebase_force_nowait }) end if keymaps.global.copy_mr_url then vim.keymap.set("n", keymaps.global.copy_mr_url, function() require("gitlab").copy_mr_url() end, { desc = "Copy MR url", nowait = keymaps.global.copy_mr_url_nowait }) end if keymaps.global.publish_all_drafts then vim.keymap.set("n", keymaps.global.publish_all_drafts, function() require("gitlab").publish_all_drafts() end, { desc = "Publish all MR comment drafts", nowait = keymaps.global.publish_all_drafts_nowait }) end if keymaps.global.toggle_draft_mode then vim.keymap.set("n", keymaps.global.toggle_draft_mode, function() require("gitlab").toggle_draft_mode() end, { desc = "Toggle MR comment draft mode", nowait = keymaps.global.toggle_draft_mode_nowait }) end end ---Merge user settings into the default settings, overriding the defaults. ---@param args GitlabSettings ---@return GitlabSettings M.merge_settings = function(args) if args.server and args.server.binary ~= nil then M.settings.server.binary_provided = true end M.settings = u.merge(M.settings, args) return M.settings end M.print_settings = function() vim.print(M.settings) end ---Load Gitlab auth token and URL into the settings and notify user if auth token is ---missing. ---@return boolean success True if plugin is already initialized or when initialization succeeds, otherwise false (if auth token is missing) M.set_plugin_configuration = function() if M.initialized then return true end local token, url, err = M.settings.auth_provider() if err ~= nil then return false end M.settings.auth_token = token M.settings.gitlab_url = u.trim_slash(url or "https://gitlab.com") if M.settings.auth_token == nil then vim.notify( "Missing authentication token for Gitlab, please provide it as an environment variable or in the .gitlab.nvim file", vim.log.levels.ERROR ) return false end M.initialized = true return true end -- GitlabDependency definitions to be passed to the async.sequence function, which calls -- them in sequence before performing an action. They are used to set global state -- that's required for each of the actions to occur. ---@type GitlabDependencies M.dependencies = { user = { endpoint = "/users/me", key = "user", state = "USER", refresh = false, }, info = { endpoint = "/mr/info", key = "info", state = "INFO", refresh = false, }, mergeability = { endpoint = "/mr/info/mergeability", key = "mergeability_checks", state = "MERGEABILITY", refresh = false, }, latest_pipeline = { endpoint = "/pipeline", key = "latest_pipeline", state = "PIPELINE", refresh = true, }, labels = { endpoint = "/mr/label", key = "labels", state = "LABELS", refresh = false, }, revisions = { endpoint = "/mr/revisions", key = "Revisions", state = "MR_REVISIONS", refresh = false, }, draft_notes = { endpoint = "/mr/draft_notes/", key = "draft_notes", state = "DRAFT_NOTES", refresh = false, }, project_members = { endpoint = "/project/members", key = "ProjectMembers", state = "PROJECT_MEMBERS", refresh = false, }, merge_requests = { endpoint = "/merge_requests", key = "merge_requests", state = "MERGE_REQUESTS", refresh = true, method = "POST", body = function(opts) if opts then opts.open_reviewer_field = nil end if opts and opts.notlabel then -- Legacy: Migrate use of notlabel to not[label], per API opts["not[label]"] = opts.notlabel opts.notlabel = nil end return opts or vim.empty_dict() end, }, merge_requests_by_username = { endpoint = "/merge_requests_by_username", key = "merge_requests", state = "MERGE_REQUESTS", refresh = true, method = "POST", body = function(opts) local members = List.new(M.PROJECT_MEMBERS) local user = members:find(function(usr) return usr.username == opts.username end) if user == nil then error("Invalid payload, user could not be found!") end opts.user_id = user.id return opts end, }, discussion_data = { endpoint = "/mr/discussions/list", state = "DISCUSSION_DATA", refresh = false, method = "POST", body = function() return { blacklist = M.settings.discussion_tree.blacklist, sort_by = M.settings.discussion_tree.sort_by, } end, }, } ---Load new state for a dependency and execute callback with the data it returns. ---@param dep string The dependency name to re-load ---@param on_success fun(data:SuccessResponse) The function to call with the dependency data ---@param on_error? fun(data:ErrorResponse?) The function to call when the request fails M.load_new_state = function(dep, on_success, on_error) local client = require("gitlab.client") local dependency = M.dependencies[dep] client.send_request( dependency.endpoint, dependency.method or "GET", dependency.body and dependency.body() or nil, function(data) if dependency.key then M[dependency.state] = u.ensure_table(data[dependency.key]) end on_success(data) -- To set data manually... end, on_error ) end ---Clear out all of the previously fetched data. ---Used to reset plugin state when the Go server is restarted. M.clear_data = function() M.INFO = nil -- FIXME: The following loop should use pairs instead of ipairs to actually clear the -- state. for _, dep in ipairs(M.dependencies) do M[dep.state] = nil end end return M

Back | FazBrowse Home | New Git URL