diff --git a/lua/octo/commands.lua b/lua/octo/commands.lua index c20c7f19..72afa1ca 100644 --- a/lua/octo/commands.lua +++ b/lua/octo/commands.lua @@ -341,7 +341,7 @@ function M.octo(object, action, ...) end if not object then - if config.get_config().enable_builtin then + if config.values.enable_builtin then M.commands.actions() else utils.error "Missing arguments" @@ -759,7 +759,7 @@ end function M.create_pr(is_draft) is_draft = "draft" == is_draft and true or false - local conf = config.get_config() + local conf = config.values local select = conf.pull_requests.always_select_remote_on_create or false local repo diff --git a/lua/octo/config.lua b/lua/octo/config.lua index 262eecd4..deb94c76 100644 --- a/lua/octo/config.lua +++ b/lua/octo/config.lua @@ -1,211 +1,436 @@ local M = {} -M.defaults = { - picker = "telescope", - picker_config = { - use_emojis = false, - mappings = { - open_in_browser = { lhs = "", desc = "open issue in browser" }, - copy_url = { lhs = "", desc = "copy url to system clipboard" }, - checkout_pr = { lhs = "", desc = "checkout pull request" }, - merge_pr = { lhs = "", desc = "merge pull request" }, - }, - }, - default_remote = { "upstream", "origin" }, - ssh_aliases = {}, - reaction_viewer_hint_icon = " ", - user_icon = " ", - comment_icon = "▎", - outdated_icon = "󰅒 ", - resolved_icon = " ", - timeline_marker = " ", - timeline_indent = "2", - right_bubble_delimiter = "", - left_bubble_delimiter = "", - github_hostname = "", - use_local_fs = false, - enable_builtin = false, - snippet_context_lines = 4, - gh_env = {}, - timeout = 5000, - ui = { - use_signcolumn = true, - }, - issues = { - order_by = { - field = "CREATED_AT", - direction = "DESC", - }, - }, - pull_requests = { - order_by = { - field = "CREATED_AT", - direction = "DESC", +---@alias OctoMappingsWindow "issue" | "pull_request" | "review_thread" | "submit_win" | "review_diff" | "file_panel" | "repo" +---@alias OctoMappingsList { [string]: table} +---@alias OctoPickers "telescope" | "fzf-lua" + +---@class OctoPickerConfig +---@field use_emojis boolean +---@field mappings table + +---@class OctoConfigColors +---@field white string +---@field grey string +---@field black string +---@field red string +---@field dark_red string +---@field green string +---@field dark_green string +---@field yellow string +---@field dark_yellow string +---@field blue string +---@field dark_blue string +---@field purple string + +---@class OctoConfigFilePanel +---@field size number +---@field use_icons boolean + +---@class OctoConfigUi +---@field use_signcolumn boolean + +---@class OctoConfigIssues +---@field order_by OctoConfigOrderBy + +---@class OctoConfigPR +---@field order_by OctoConfigOrderBy +---@field always_select_remote_on_create boolean + +---@class OctoConfigOrderBy +---@field field string +---@field direction "ASC" | "DESC" + +---@class OctoConfig Octo configuration settings +---@field picker OctoPickers +---@field picker_config OctoPickerConfig +---@field default_remote table +---@field ssh_aliases {[string]:string} +---@field reaction_viewer_hint_icon string +---@field user_icon string +---@field comment_icon string +---@field outdated_icon string +---@field resolved_icon string +---@field timeline_marker string +---@field timeline_indent string +---@field right_bubble_delimiter string +---@field left_bubble_delimiter string +---@field github_hostname string +---@field use_local_fs boolean +---@field enable_builtin boolean +---@field snippet_context_lines number +---@field gh_env table +---@field timeout number +---@field ui OctoConfigUi +---@field issues OctoConfigIssues +---@field pull_requests OctoConfigPR +---@field file_panel OctoConfigFilePanel +---@field colors OctoConfigColors +---@field mappings { [OctoMappingsWindow]: OctoMappingsList} + +--- Returns the default octo config values +---@return OctoConfig +function M.get_default_values() + return { + picker = "telescope", + picker_config = { + use_emojis = false, + mappings = { + open_in_browser = { lhs = "", desc = "open issue in browser" }, + copy_url = { lhs = "", desc = "copy url to system clipboard" }, + checkout_pr = { lhs = "", desc = "checkout pull request" }, + merge_pr = { lhs = "", desc = "merge pull request" }, + }, }, - always_select_remote_on_create = false, - }, - file_panel = { - size = 10, - use_icons = true, - }, - colors = { - white = "#ffffff", - grey = "#2A354C", - black = "#000000", - red = "#fdb8c0", - dark_red = "#da3633", - green = "#acf2bd", - dark_green = "#238636", - yellow = "#d3c846", - dark_yellow = "#735c0f", - blue = "#58A6FF", - dark_blue = "#0366d6", - purple = "#6f42c1", - }, - mappings = { - issue = { - close_issue = { lhs = "ic", desc = "close issue" }, - reopen_issue = { lhs = "io", desc = "reopen issue" }, - list_issues = { lhs = "il", desc = "list open issues on same repo" }, - reload = { lhs = "", desc = "reload issue" }, - open_in_browser = { lhs = "", desc = "open issue in browser" }, - copy_url = { lhs = "", desc = "copy url to system clipboard" }, - add_assignee = { lhs = "aa", desc = "add assignee" }, - remove_assignee = { lhs = "ad", desc = "remove assignee" }, - create_label = { lhs = "lc", desc = "create label" }, - add_label = { lhs = "la", desc = "add label" }, - remove_label = { lhs = "ld", desc = "remove label" }, - goto_issue = { lhs = "gi", desc = "navigate to a local repo issue" }, - add_comment = { lhs = "ca", desc = "add comment" }, - delete_comment = { lhs = "cd", desc = "delete comment" }, - next_comment = { lhs = "]c", desc = "go to next comment" }, - prev_comment = { lhs = "[c", desc = "go to previous comment" }, - react_hooray = { lhs = "rp", desc = "add/remove 🎉 reaction" }, - react_heart = { lhs = "rh", desc = "add/remove ❤️ reaction" }, - react_eyes = { lhs = "re", desc = "add/remove 👀 reaction" }, - react_thumbs_up = { lhs = "r+", desc = "add/remove 👍 reaction" }, - react_thumbs_down = { lhs = "r-", desc = "add/remove 👎 reaction" }, - react_rocket = { lhs = "rr", desc = "add/remove 🚀 reaction" }, - react_laugh = { lhs = "rl", desc = "add/remove 😄 reaction" }, - react_confused = { lhs = "rc", desc = "add/remove 😕 reaction" }, + default_remote = { "upstream", "origin" }, + ssh_aliases = {}, + reaction_viewer_hint_icon = " ", + user_icon = " ", + comment_icon = "▎", + outdated_icon = "󰅒 ", + resolved_icon = " ", + timeline_marker = " ", + timeline_indent = "2", + right_bubble_delimiter = "", + left_bubble_delimiter = "", + github_hostname = "", + use_local_fs = false, + enable_builtin = false, + snippet_context_lines = 4, + gh_env = {}, + timeout = 5000, + ui = { + use_signcolumn = true, }, - pull_request = { - checkout_pr = { lhs = "po", desc = "checkout PR" }, - merge_pr = { lhs = "pm", desc = "merge commit PR" }, - squash_and_merge_pr = { lhs = "psm", desc = "squash and merge PR" }, - list_commits = { lhs = "pc", desc = "list PR commits" }, - list_changed_files = { lhs = "pf", desc = "list PR changed files" }, - show_pr_diff = { lhs = "pd", desc = "show PR diff" }, - add_reviewer = { lhs = "va", desc = "add reviewer" }, - remove_reviewer = { lhs = "vd", desc = "remove reviewer request" }, - close_issue = { lhs = "ic", desc = "close PR" }, - reopen_issue = { lhs = "io", desc = "reopen PR" }, - list_issues = { lhs = "il", desc = "list open issues on same repo" }, - reload = { lhs = "", desc = "reload PR" }, - open_in_browser = { lhs = "", desc = "open PR in browser" }, - copy_url = { lhs = "", desc = "copy url to system clipboard" }, - goto_file = { lhs = "gf", desc = "go to file" }, - add_assignee = { lhs = "aa", desc = "add assignee" }, - remove_assignee = { lhs = "ad", desc = "remove assignee" }, - create_label = { lhs = "lc", desc = "create label" }, - add_label = { lhs = "la", desc = "add label" }, - remove_label = { lhs = "ld", desc = "remove label" }, - goto_issue = { lhs = "gi", desc = "navigate to a local repo issue" }, - add_comment = { lhs = "ca", desc = "add comment" }, - delete_comment = { lhs = "cd", desc = "delete comment" }, - next_comment = { lhs = "]c", desc = "go to next comment" }, - prev_comment = { lhs = "[c", desc = "go to previous comment" }, - react_hooray = { lhs = "rp", desc = "add/remove 🎉 reaction" }, - react_heart = { lhs = "rh", desc = "add/remove ❤️ reaction" }, - react_eyes = { lhs = "re", desc = "add/remove 👀 reaction" }, - react_thumbs_up = { lhs = "r+", desc = "add/remove 👍 reaction" }, - react_thumbs_down = { lhs = "r-", desc = "add/remove 👎 reaction" }, - react_rocket = { lhs = "rr", desc = "add/remove 🚀 reaction" }, - react_laugh = { lhs = "rl", desc = "add/remove 😄 reaction" }, - react_confused = { lhs = "rc", desc = "add/remove 😕 reaction" }, + issues = { + order_by = { + field = "CREATED_AT", + direction = "DESC", + }, }, - review_thread = { - goto_issue = { lhs = "gi", desc = "navigate to a local repo issue" }, - add_comment = { lhs = "ca", desc = "add comment" }, - add_suggestion = { lhs = "sa", desc = "add suggestion" }, - delete_comment = { lhs = "cd", desc = "delete comment" }, - next_comment = { lhs = "]c", desc = "go to next comment" }, - prev_comment = { lhs = "[c", desc = "go to previous comment" }, - select_next_entry = { lhs = "]q", desc = "move to previous changed file" }, - select_prev_entry = { lhs = "[q", desc = "move to next changed file" }, - select_first_entry = { lhs = "[Q", desc = "move to first changed file" }, - select_last_entry = { lhs = "]Q", desc = "move to last changed file" }, - close_review_tab = { lhs = "", desc = "close review tab" }, - react_hooray = { lhs = "rp", desc = "add/remove 🎉 reaction" }, - react_heart = { lhs = "rh", desc = "add/remove ❤️ reaction" }, - react_eyes = { lhs = "re", desc = "add/remove 👀 reaction" }, - react_thumbs_up = { lhs = "r+", desc = "add/remove 👍 reaction" }, - react_thumbs_down = { lhs = "r-", desc = "add/remove 👎 reaction" }, - react_rocket = { lhs = "rr", desc = "add/remove 🚀 reaction" }, - react_laugh = { lhs = "rl", desc = "add/remove 😄 reaction" }, - react_confused = { lhs = "rc", desc = "add/remove 😕 reaction" }, + pull_requests = { + order_by = { + field = "CREATED_AT", + direction = "DESC", + }, + always_select_remote_on_create = false, }, - submit_win = { - approve_review = { lhs = "", desc = "approve review" }, - comment_review = { lhs = "", desc = "comment review" }, - request_changes = { lhs = "", desc = "request changes review" }, - close_review_tab = { lhs = "", desc = "close review tab" }, + file_panel = { + size = 10, + use_icons = true, }, - review_diff = { - add_review_comment = { lhs = "ca", desc = "add a new review comment" }, - add_review_suggestion = { lhs = "sa", desc = "add a new review suggestion" }, - focus_files = { lhs = "e", desc = "move focus to changed file panel" }, - toggle_files = { lhs = "b", desc = "hide/show changed files panel" }, - next_thread = { lhs = "]t", desc = "move to next thread" }, - prev_thread = { lhs = "[t", desc = "move to previous thread" }, - select_next_entry = { lhs = "]q", desc = "move to previous changed file" }, - select_prev_entry = { lhs = "[q", desc = "move to next changed file" }, - select_first_entry = { lhs = "[Q", desc = "move to first changed file" }, - select_last_entry = { lhs = "]Q", desc = "move to last changed file" }, - close_review_tab = { lhs = "", desc = "close review tab" }, - toggle_viewed = { lhs = "", desc = "toggle viewer viewed state" }, - goto_file = { lhs = "gf", desc = "go to file" }, + colors = { + white = "#ffffff", + grey = "#2A354C", + black = "#000000", + red = "#fdb8c0", + dark_red = "#da3633", + green = "#acf2bd", + dark_green = "#238636", + yellow = "#d3c846", + dark_yellow = "#735c0f", + blue = "#58A6FF", + dark_blue = "#0366d6", + purple = "#6f42c1", }, - file_panel = { - next_entry = { lhs = "j", desc = "move to next changed file" }, - prev_entry = { lhs = "k", desc = "move to previous changed file" }, - select_entry = { lhs = "", desc = "show selected changed file diffs" }, - refresh_files = { lhs = "R", desc = "refresh changed files panel" }, - focus_files = { lhs = "e", desc = "move focus to changed file panel" }, - toggle_files = { lhs = "b", desc = "hide/show changed files panel" }, - select_next_entry = { lhs = "]q", desc = "move to previous changed file" }, - select_prev_entry = { lhs = "[q", desc = "move to next changed file" }, - select_first_entry = { lhs = "[Q", desc = "move to first changed file" }, - select_last_entry = { lhs = "]Q", desc = "move to last changed file" }, - close_review_tab = { lhs = "", desc = "close review tab" }, - toggle_viewed = { lhs = "", desc = "toggle viewer viewed state" }, + mappings = { + issue = { + close_issue = { lhs = "ic", desc = "close issue" }, + reopen_issue = { lhs = "io", desc = "reopen issue" }, + list_issues = { lhs = "il", desc = "list open issues on same repo" }, + reload = { lhs = "", desc = "reload issue" }, + open_in_browser = { lhs = "", desc = "open issue in browser" }, + copy_url = { lhs = "", desc = "copy url to system clipboard" }, + add_assignee = { lhs = "aa", desc = "add assignee" }, + remove_assignee = { lhs = "ad", desc = "remove assignee" }, + create_label = { lhs = "lc", desc = "create label" }, + add_label = { lhs = "la", desc = "add label" }, + remove_label = { lhs = "ld", desc = "remove label" }, + goto_issue = { lhs = "gi", desc = "navigate to a local repo issue" }, + add_comment = { lhs = "ca", desc = "add comment" }, + delete_comment = { lhs = "cd", desc = "delete comment" }, + next_comment = { lhs = "]c", desc = "go to next comment" }, + prev_comment = { lhs = "[c", desc = "go to previous comment" }, + react_hooray = { lhs = "rp", desc = "add/remove 🎉 reaction" }, + react_heart = { lhs = "rh", desc = "add/remove ❤️ reaction" }, + react_eyes = { lhs = "re", desc = "add/remove 👀 reaction" }, + react_thumbs_up = { lhs = "r+", desc = "add/remove 👍 reaction" }, + react_thumbs_down = { lhs = "r-", desc = "add/remove 👎 reaction" }, + react_rocket = { lhs = "rr", desc = "add/remove 🚀 reaction" }, + react_laugh = { lhs = "rl", desc = "add/remove 😄 reaction" }, + react_confused = { lhs = "rc", desc = "add/remove 😕 reaction" }, + }, + pull_request = { + checkout_pr = { lhs = "po", desc = "checkout PR" }, + merge_pr = { lhs = "pm", desc = "merge commit PR" }, + squash_and_merge_pr = { lhs = "psm", desc = "squash and merge PR" }, + list_commits = { lhs = "pc", desc = "list PR commits" }, + list_changed_files = { lhs = "pf", desc = "list PR changed files" }, + show_pr_diff = { lhs = "pd", desc = "show PR diff" }, + add_reviewer = { lhs = "va", desc = "add reviewer" }, + remove_reviewer = { lhs = "vd", desc = "remove reviewer request" }, + close_issue = { lhs = "ic", desc = "close PR" }, + reopen_issue = { lhs = "io", desc = "reopen PR" }, + list_issues = { lhs = "il", desc = "list open issues on same repo" }, + reload = { lhs = "", desc = "reload PR" }, + open_in_browser = { lhs = "", desc = "open PR in browser" }, + copy_url = { lhs = "", desc = "copy url to system clipboard" }, + goto_file = { lhs = "gf", desc = "go to file" }, + add_assignee = { lhs = "aa", desc = "add assignee" }, + remove_assignee = { lhs = "ad", desc = "remove assignee" }, + create_label = { lhs = "lc", desc = "create label" }, + add_label = { lhs = "la", desc = "add label" }, + remove_label = { lhs = "ld", desc = "remove label" }, + goto_issue = { lhs = "gi", desc = "navigate to a local repo issue" }, + add_comment = { lhs = "ca", desc = "add comment" }, + delete_comment = { lhs = "cd", desc = "delete comment" }, + next_comment = { lhs = "]c", desc = "go to next comment" }, + prev_comment = { lhs = "[c", desc = "go to previous comment" }, + react_hooray = { lhs = "rp", desc = "add/remove 🎉 reaction" }, + react_heart = { lhs = "rh", desc = "add/remove ❤️ reaction" }, + react_eyes = { lhs = "re", desc = "add/remove 👀 reaction" }, + react_thumbs_up = { lhs = "r+", desc = "add/remove 👍 reaction" }, + react_thumbs_down = { lhs = "r-", desc = "add/remove 👎 reaction" }, + react_rocket = { lhs = "rr", desc = "add/remove 🚀 reaction" }, + react_laugh = { lhs = "rl", desc = "add/remove 😄 reaction" }, + react_confused = { lhs = "rc", desc = "add/remove 😕 reaction" }, + }, + review_thread = { + goto_issue = { lhs = "gi", desc = "navigate to a local repo issue" }, + add_comment = { lhs = "ca", desc = "add comment" }, + add_suggestion = { lhs = "sa", desc = "add suggestion" }, + delete_comment = { lhs = "cd", desc = "delete comment" }, + next_comment = { lhs = "]c", desc = "go to next comment" }, + prev_comment = { lhs = "[c", desc = "go to previous comment" }, + select_next_entry = { lhs = "]q", desc = "move to previous changed file" }, + select_prev_entry = { lhs = "[q", desc = "move to next changed file" }, + select_first_entry = { lhs = "[Q", desc = "move to first changed file" }, + select_last_entry = { lhs = "]Q", desc = "move to last changed file" }, + close_review_tab = { lhs = "", desc = "close review tab" }, + react_hooray = { lhs = "rp", desc = "add/remove 🎉 reaction" }, + react_heart = { lhs = "rh", desc = "add/remove ❤️ reaction" }, + react_eyes = { lhs = "re", desc = "add/remove 👀 reaction" }, + react_thumbs_up = { lhs = "r+", desc = "add/remove 👍 reaction" }, + react_thumbs_down = { lhs = "r-", desc = "add/remove 👎 reaction" }, + react_rocket = { lhs = "rr", desc = "add/remove 🚀 reaction" }, + react_laugh = { lhs = "rl", desc = "add/remove 😄 reaction" }, + react_confused = { lhs = "rc", desc = "add/remove 😕 reaction" }, + }, + submit_win = { + approve_review = { lhs = "", desc = "approve review" }, + comment_review = { lhs = "", desc = "comment review" }, + request_changes = { lhs = "", desc = "request changes review" }, + close_review_tab = { lhs = "", desc = "close review tab" }, + }, + review_diff = { + add_review_comment = { lhs = "ca", desc = "add a new review comment" }, + add_review_suggestion = { lhs = "sa", desc = "add a new review suggestion" }, + focus_files = { lhs = "e", desc = "move focus to changed file panel" }, + toggle_files = { lhs = "b", desc = "hide/show changed files panel" }, + next_thread = { lhs = "]t", desc = "move to next thread" }, + prev_thread = { lhs = "[t", desc = "move to previous thread" }, + select_next_entry = { lhs = "]q", desc = "move to previous changed file" }, + select_prev_entry = { lhs = "[q", desc = "move to next changed file" }, + select_first_entry = { lhs = "[Q", desc = "move to first changed file" }, + select_last_entry = { lhs = "]Q", desc = "move to last changed file" }, + close_review_tab = { lhs = "", desc = "close review tab" }, + toggle_viewed = { lhs = "", desc = "toggle viewer viewed state" }, + goto_file = { lhs = "gf", desc = "go to file" }, + }, + file_panel = { + next_entry = { lhs = "j", desc = "move to next changed file" }, + prev_entry = { lhs = "k", desc = "move to previous changed file" }, + select_entry = { lhs = "", desc = "show selected changed file diffs" }, + refresh_files = { lhs = "R", desc = "refresh changed files panel" }, + focus_files = { lhs = "e", desc = "move focus to changed file panel" }, + toggle_files = { lhs = "b", desc = "hide/show changed files panel" }, + select_next_entry = { lhs = "]q", desc = "move to previous changed file" }, + select_prev_entry = { lhs = "[q", desc = "move to next changed file" }, + select_first_entry = { lhs = "[Q", desc = "move to first changed file" }, + select_last_entry = { lhs = "]Q", desc = "move to last changed file" }, + close_review_tab = { lhs = "", desc = "close review tab" }, + toggle_viewed = { lhs = "", desc = "toggle viewer viewed state" }, + }, + repo = {}, }, - repo = {}, - }, -} + } +end + +M.values = M.get_default_values() -local config = {} +---Validates the config +---@return { [string]: string } all error messages emitted during validation +function M.validate_config() + local config = M.values + + ---@type { [string]: string } + local errors = {} + local function err(value, msg) + errors[value] = msg + end -function M.get_config() - return config or M.defaults + ---Checks if a variable is the correct, type if not it calls err with an error string + ---@param value any + ---@param name string + ---@param expected_types type | type[] + local function validate_type(value, name, expected_types) + if type(expected_types) == "table" then + if not vim.tbl_contains(expected_types, type(value)) then + err( + name, + string.format( + "Expected `%s` to be one of types '%s', got '%s'", + name, + table.concat(expected_types, ", "), + type(value) + ) + ) + return false + end + return true + end + + if type(value) ~= expected_types then + err(name, string.format("Expected `%s` to be of type '%s', got '%s'", name, expected_types, type(value))) + return false + end + return true + end + + local function validate_pickers() + local valid_pickers = { "telescope", "fzf-lua" } + if not validate_type(config.picker, "picker", "string") then + return + end + if not vim.tbl_contains(valid_pickers, config.picker) then + err( + "picker." .. config.picker, + string.format( + "Expected a valid picker, received '%s', which is not a supported picker! Valid pickers: ", + config.picker, + table.concat(valid_pickers, ", ") + ) + ) + end + if not validate_type(config.picker_config, "picker_config", "table") then + return + end + + validate_type(config.picker_config.use_emojis, "picker_config.use_emojis", "boolean") + validate_type(config.picker_config.mappings, "picker_config.mappings", "table") + end + + local function validate_aliases() + if not validate_type(config.ssh_aliases, "ssh_aliases", "table") then + return + end + for name, alias in pairs(config.ssh_aliases) do + validate_type(alias, string.format("ssh_aliases.%s", name), "string") + end + end + + local function validate_issues() + if not validate_type(config.issues, "issues", "table") then + return + end + if validate_type(config.issues.order_by, "issues.order_by", "table") then + validate_type(config.issues.order_by.field, "issues.order_by.field", "string") + validate_type(config.issues.order_by.direction, "issues.order_by.direction", "string") + end + end + + local function validate_pull_requests() + if not validate_type(config.pull_requests, "pull_requests", "table") then + return + end + if validate_type(config.pull_requests.order_by, "pull_requests.order_by", "table") then + validate_type(config.pull_requests.order_by.field, "pull_requests.order_by.field", "string") + validate_type(config.pull_requests.order_by.direction, "pull_requests.order_by.direction", "string") + end + validate_type(config.pull_requests.always_select_remote_on_create, "always_select_remote_on_create", "boolean") + end + + local function validate_mappings() + -- TODO(jarviliam): Validate each keymap + if not validate_type(config.mappings, "mappings", "table") then + return + end + end + + if validate_type(config, "base config", "table") then + validate_type(config.use_local_fs, "use_local_fs", "boolean") + validate_type(config.enable_builtin, "enable_builtin", "boolean") + validate_type(config.snippet_context_lines, "snippet_context_lines", "number") + validate_type(config.timeout, "timeout", "number") + validate_type(config.gh_env, "gh_env", "table") + validate_type(config.reaction_viewer_hint_icon, "reaction_viewer_hint_icon", "string") + validate_type(config.user_icon, "user_icon", "string") + validate_type(config.comment_icon, "comment_icon", "string") + validate_type(config.outdated_icon, "outdated_icon", "string") + validate_type(config.resolved_icon, "resolved_icon", "string") + validate_type(config.timeline_marker, "timeline_marker", "string") + validate_type(config.timeline_indent, "timeline_indent", "string") + validate_type(config.right_bubble_delimiter, "right_bubble_delimiter", "string") + validate_type(config.left_bubble_delimiter, "left_bubble_delimiter", "string") + validate_type(config.github_hostname, "github_hostname", "string") + if validate_type(config.default_remote, "default_remote", "table") then + for _, v in ipairs(config.default_remote) do + validate_type(v, "remote", "string") + end + end + if validate_type(config.ui, "ui", "table") then + validate_type(config.ui.use_signcolumn, "ui.use_signcolumn", "boolean") + end + if validate_type(config.colors, "colors", "table") then + for k, v in pairs(config.colors) do + validate_type(v, string.format("colors.%s", k), "string") + end + end + + validate_issues() + validate_pull_requests() + if validate_type(config.file_panel, "file_panel", "table") then + validate_type(config.file_panel.size, "file_panel.size", "number") + validate_type(config.file_panel.use_icons, "file_panel.use_icons", "boolean") + end + validate_aliases() + validate_pickers() + validate_mappings() + end + + return errors end -function M.setup(user_config) - user_config = user_config or {} - config = vim.tbl_deep_extend("force", M.defaults, user_config) - - -- If the user provides key bindings: use only the user bindings. - if user_config.mappings then - config.mappings.issue = (user_config.mappings.issue or M.defaults.mappings.issue) - config.mappings.pull_request = (user_config.mappings.pull_request or M.defaults.mappings.pull_request) - config.mappings.review_thread = (user_config.mappings.review_thread or M.defaults.mappings.review_thread) - config.mappings.review = (user_config.mappings.review or M.defaults.mappings.review) - config.mappings.file_panel = (user_config.mappings.file_panel or M.defaults.mappings.file_panel) - config.mappings.submit_win = (user_config.mappings.submit_win or M.defaults.mappings.submit_win) - config.mappings.repo = (user_config.mappings.repo or M.defaults.mappings.repo) +function M.setup(opts) + if opts ~= nil then + M.values = vim.tbl_deep_extend("force", M.values, opts) end + local config_errs = M.validate_config() + if vim.tbl_count(config_errs) > 0 then + local header = "====Octo Configuration Errors====" + local header_message = { + "You have a misconfiguration in your octo setup!", + 'Validate that your configuration passed to `require("octo").setup()` is valid!', + } + local header_sep = "" + for _ = 0, string.len(header), 1 do + header_sep = header_sep .. "-" + end - return config + local config_errs_message = {} + for config_key, err in pairs(config_errs) do + table.insert(config_errs_message, string.format("Config value: `%s` had error -> %s", config_key, err)) + end + error( + string.format( + "\n%s\n%s\n%s\n%s", + header, + table.concat(header_message, "\n"), + header_sep, + table.concat(config_errs_message, "\n") + ), + vim.log.levels.ERROR + ) + end end return M diff --git a/lua/octo/gh/init.lua b/lua/octo/gh/init.lua index 8835177e..8027495c 100644 --- a/lua/octo/gh/init.lua +++ b/lua/octo/gh/init.lua @@ -28,7 +28,7 @@ local env_vars = { local function get_env() local env = env_vars - local gh_env = config.get_config().gh_env + local gh_env = config.values.gh_env if type(gh_env) == "function" then local computed_env = gh_env() if type(computed_env) == "table" then @@ -83,7 +83,7 @@ function M.run(opts) end opts = opts or {} - local conf = config.get_config() + local conf = config.values local mode = opts.mode or "async" local hostname = "" if opts.args[1] == "api" then diff --git a/lua/octo/model/octo-buffer.lua b/lua/octo/model/octo-buffer.lua index 9a76a2c9..3da856c7 100644 --- a/lua/octo/model/octo-buffer.lua +++ b/lua/octo/model/octo-buffer.lua @@ -237,7 +237,7 @@ end function OctoBuffer:configure() -- configure buffer vim.api.nvim_buf_call(self.bufnr, function() - local use_signcolumn = config.get_config().ui.use_signcolumn + local use_signcolumn = config.values.ui.use_signcolumn vim.cmd [[setlocal filetype=octo]] vim.cmd [[setlocal buftype=acwrite]] vim.cmd [[setlocal omnifunc=v:lua.octo_omnifunc]] @@ -799,7 +799,7 @@ end ---Renders the signcolumn function OctoBuffer:render_signcolumn() - local use_signcolumn = config.get_config().ui.use_signcolumn + local use_signcolumn = config.values.ui.use_signcolumn if not use_signcolumn or not self.ready then return end diff --git a/lua/octo/picker.lua b/lua/octo/picker.lua index 73abe6c6..91cefd42 100644 --- a/lua/octo/picker.lua +++ b/lua/octo/picker.lua @@ -4,7 +4,7 @@ local utils = require "octo.utils" local M = {} function M.setup() - local provider_name = config.get_config().picker + local provider_name = config.values.picker if utils.is_blank(provider_name) then provider_name = "telescope" end diff --git a/lua/octo/pickers/fzf-lua/pickers/fzf_actions.lua b/lua/octo/pickers/fzf-lua/pickers/fzf_actions.lua index d05ef845..05c8d2d8 100644 --- a/lua/octo/pickers/fzf-lua/pickers/fzf_actions.lua +++ b/lua/octo/pickers/fzf-lua/pickers/fzf_actions.lua @@ -21,7 +21,7 @@ M.common_buffer_actions = function(formatted_items) end M.common_open_actions = function(formatted_items) - local cfg = octo_config.get_config() + local cfg = octo_config.values return vim.tbl_extend("force", M.common_buffer_actions(formatted_items), { [utils.convert_vim_mapping_to_fzf(cfg.picker_config.mappings.open_in_browser.lhs)] = function(selected) picker_utils.open_in_browser(formatted_items[selected[1]]) diff --git a/lua/octo/pickers/fzf-lua/pickers/issues.lua b/lua/octo/pickers/fzf-lua/pickers/issues.lua index 5410f5cc..e95f2143 100644 --- a/lua/octo/pickers/fzf-lua/pickers/issues.lua +++ b/lua/octo/pickers/fzf-lua/pickers/issues.lua @@ -23,7 +23,7 @@ return function(opts) end local owner, name = utils.split_repo(opts.repo) - local cfg = octo_config.get_config() + local cfg = octo_config.values local order_by = cfg.issues.order_by local query = graphql("issues_query", owner, name, filter, order_by.field, order_by.direction, { escape = false }) diff --git a/lua/octo/pickers/fzf-lua/pickers/prs.lua b/lua/octo/pickers/fzf-lua/pickers/prs.lua index ad925340..380455b7 100644 --- a/lua/octo/pickers/fzf-lua/pickers/prs.lua +++ b/lua/octo/pickers/fzf-lua/pickers/prs.lua @@ -27,7 +27,7 @@ return function(opts) end local owner, name = utils.split_repo(opts.repo) - local cfg = octo_config.get_config() + local cfg = octo_config.values local order_by = cfg.pull_requests.order_by local query = diff --git a/lua/octo/pickers/fzf-lua/previewers.lua b/lua/octo/pickers/fzf-lua/previewers.lua index 91166cdc..062d7a42 100644 --- a/lua/octo/pickers/fzf-lua/previewers.lua +++ b/lua/octo/pickers/fzf-lua/previewers.lua @@ -324,7 +324,7 @@ M.repo = function(formatted_repos) self:set_preview_buf(tmpbuf) local stargazer, fork - if config.get_config().picker_config.use_emojis then + if config.values.picker_config.use_emojis then stargazer = string.format("💫: %s", entry.repo.stargazerCount) fork = string.format("🔱: %s", entry.repo.forkCount) else diff --git a/lua/octo/pickers/telescope/provider.lua b/lua/octo/pickers/telescope/provider.lua index 4f3830ca..a4afc37f 100644 --- a/lua/octo/pickers/telescope/provider.lua +++ b/lua/octo/pickers/telescope/provider.lua @@ -132,7 +132,7 @@ function M.issues(opts) end local owner, name = utils.split_repo(opts.repo) - local cfg = octo_config.get_config() + local cfg = octo_config.values local order_by = cfg.issues.order_by local query = graphql("issues_query", owner, name, filter, order_by.field, order_by.direction, { escape = false }) utils.info "Fetching issues (this may take a while) ..." @@ -277,7 +277,7 @@ function M.pull_requests(opts) end local owner, name = utils.split_repo(opts.repo) - local cfg = octo_config.get_config() + local cfg = octo_config.values local order_by = cfg.pull_requests.order_by local query = graphql("pull_requests_query", owner, name, filter, order_by.field, order_by.direction, { escape = false }) @@ -479,7 +479,7 @@ end --- function M.search(opts) opts = opts or {} - local cfg = octo_config.get_config() + local cfg = octo_config.values local requester = function() return function(prompt) if not opts.prompt and utils.is_blank(prompt) then @@ -924,7 +924,7 @@ end -- function M.repos(opts) opts = opts or {} - local cfg = octo_config.get_config() + local cfg = octo_config.values if not opts.login then if vim.g.octo_viewer then opts.login = vim.g.octo_viewer diff --git a/lua/octo/reviews/file-entry.lua b/lua/octo/reviews/file-entry.lua index d35562e6..75a12559 100644 --- a/lua/octo/reviews/file-entry.lua +++ b/lua/octo/reviews/file-entry.lua @@ -176,7 +176,7 @@ function FileEntry:fetch() local left_sha = current_review.layout.left.commit local right_abbrev = current_review.layout.right:abbrev() local left_abbrev = current_review.layout.left:abbrev() - local conf = config.get_config() + local conf = config.values -- handle renamed files if self.status == "R" and self.previous_path then @@ -236,7 +236,7 @@ function FileEntry:load_buffers(left_winid, right_winid) -- configure diff buffers for _, split in ipairs(splits) do if not split.bufid or not vim.api.nvim_buf_is_loaded(split.bufid) then - local conf = config.get_config() + local conf = config.values local use_local = conf.use_local_fs and split.pos == "right" and utils.in_pr_branch(self.pull_request.bufnr) -- create buffer @@ -469,7 +469,7 @@ end function M._configure_buffer(bufid) utils.apply_mappings("review_diff", bufid) - -- local conf = config.get_config() + -- local conf = config.values -- vim.cmd(string.format("nnoremap %s :OctoAddReviewComment", conf.mappings.review_thread.add_comment)) -- vim.cmd(string.format("vnoremap %s :OctoAddReviewComment", conf.mappings.review_thread.add_comment)) -- vim.cmd(string.format("nnoremap %s :OctoAddReviewSuggestion", conf.mappings.review_thread.add_suggestion)) @@ -477,7 +477,7 @@ function M._configure_buffer(bufid) end function M._detach_buffer(bufid) - local conf = config.get_config() + local conf = config.values for _, lhs in pairs(conf.mappings.review_diff) do pcall(vim.keymap.del, "n", lhs, { buffer = bufid }) end diff --git a/lua/octo/reviews/file-panel.lua b/lua/octo/reviews/file-panel.lua index af859d99..4e3e002c 100644 --- a/lua/octo/reviews/file-panel.lua +++ b/lua/octo/reviews/file-panel.lua @@ -58,7 +58,7 @@ FilePanel.bufopts = { ---@param files FileEntry[] ---@return FilePanel function FilePanel:new(files) - local conf = config.get_config() + local conf = config.values local this = { files = files, size = conf.file_panel.size, @@ -96,7 +96,7 @@ function FilePanel:open() return end - local conf = config.get_config() + local conf = config.values self.size = conf.file_panel.size --vim.cmd("wincmd H") --vim.cmd("vsp") @@ -233,7 +233,7 @@ function FilePanel:render() end local current_review = require("octo.reviews").get_current_review() - local conf = config.get_config() + local conf = config.values local strlen = vim.fn.strlen local s = "Files changed" add_hl("OctoFilePanelTitle", line_idx, 0, #s) diff --git a/lua/octo/reviews/init.lua b/lua/octo/reviews/init.lua index 4d512107..e7950787 100644 --- a/lua/octo/reviews/init.lua +++ b/lua/octo/reviews/init.lua @@ -130,7 +130,7 @@ end function Review:initiate(opts) opts = opts or {} local pr = self.pull_request - local conf = config.get_config() + local conf = config.values if conf.use_local_fs and not utils.in_pr_branch(pr.bufnr) then local choice = vim.fn.confirm("Currently not in PR branch, would you like to checkout?", "&Yes\n&No", 2) if choice == 1 then @@ -224,7 +224,7 @@ function Review:collect_submit_info() return end - local conf = config.get_config() + local conf = config.values local winid, bufnr = window.create_centered_float { header = string.format( "Press %s to approve, %s to comment or %s to request changes", diff --git a/lua/octo/reviews/renderer.lua b/lua/octo/reviews/renderer.lua index 8432f885..bbb7d87f 100644 --- a/lua/octo/reviews/renderer.lua +++ b/lua/octo/reviews/renderer.lua @@ -84,7 +84,7 @@ function M.get_git_hl(status) end function M.get_file_icon(name, ext, render_data, line_idx, offset) - local use_icons = config.get_config().file_panel.use_icons + local use_icons = config.values.file_panel.use_icons if not use_icons then return " " end diff --git a/lua/octo/ui/bubbles.lua b/lua/octo/ui/bubbles.lua index 8169c1cc..d431dbcc 100644 --- a/lua/octo/ui/bubbles.lua +++ b/lua/octo/ui/bubbles.lua @@ -9,7 +9,7 @@ local colors = require "octo.ui.colors" local function make_bubble(content, highlight_group, opts) opts = opts or {} - local conf = config.get_config() + local conf = config.values local margin = string.rep(" ", opts.margin_width or 0) local right_margin = string.rep(" ", opts.right_margin_width or 0) local left_margin = string.rep(" ", opts.left_margin_width or 0) @@ -38,7 +38,7 @@ end local function make_user_bubble(name, is_viewer, opts) opts = opts or {} - local conf = config.get_config() + local conf = config.values local highlight = is_viewer and "OctoUserViewer" or "OctoUser" local icon_position = opts.icon_position or "left" local icon = conf.user_icon @@ -53,7 +53,7 @@ local function make_user_bubble(name, is_viewer, opts) end local function make_reaction_bubble(icon, includes_viewer, opts) - local conf = config.get_config() + local conf = config.values local highlight = includes_viewer and "OctoReactionViewer" or "OctoReaction" local hint_for_viewer = includes_viewer and conf.reaction_viewer_hint_icon or "" local content = icon .. hint_for_viewer diff --git a/lua/octo/ui/colors.lua b/lua/octo/ui/colors.lua index ffa3a017..b81fc714 100644 --- a/lua/octo/ui/colors.lua +++ b/lua/octo/ui/colors.lua @@ -22,7 +22,7 @@ local function get_fg(hl_group_name) end local function get_colors() - local conf = config.get_config() + local conf = config.values return conf.colors end diff --git a/lua/octo/ui/signs.lua b/lua/octo/ui/signs.lua index 1d9ead5c..8d89bfd8 100644 --- a/lua/octo/ui/signs.lua +++ b/lua/octo/ui/signs.lua @@ -3,7 +3,7 @@ local config = require "octo.config" local M = {} function M.setup() - local conf = config.get_config() + local conf = config.values vim.cmd(string.format("sign define octo_thread text=%s texthl=OctoBlue", conf.comment_icon)) vim.cmd(string.format("sign define octo_thread_resolved text=%s texthl=OctoGreen", conf.comment_icon)) diff --git a/lua/octo/ui/writers.lua b/lua/octo/ui/writers.lua index dc53974f..8c9f87e8 100644 --- a/lua/octo/ui/writers.lua +++ b/lua/octo/ui/writers.lua @@ -466,7 +466,7 @@ function M.write_comment(bufnr, comment, kind, line) ---- PullRequestComment (regular comment (not associated to any review) to a PR review comment) local buffer = octo_buffers[bufnr] - local conf = config.get_config() + local conf = config.values -- heading line = line or vim.api.nvim_buf_line_count(bufnr) + 1 @@ -598,7 +598,7 @@ function M.write_comment(bufnr, comment, kind, line) end local function find_snippet_range(diffhunk_lines) - local conf = config.get_config() + local conf = config.values local context_lines = conf.snippet_context_lines or 4 local snippet_start local count = 0 @@ -818,7 +818,7 @@ end function M.write_review_thread_header(bufnr, opts, line) line = line or vim.api.nvim_buf_line_count(bufnr) - 1 - local conf = config.get_config() + local conf = config.values -- clear virtual texts vim.api.nvim_buf_clear_namespace(bufnr, constants.OCTO_THREAD_HEADER_VT_NS, line, line + 2) @@ -1024,7 +1024,7 @@ end function M.write_issue_summary(bufnr, issue, opts) opts = opts or {} - local conf = config.get_config() + local conf = config.values local max_length = opts.max_length or 80 local chunks = {} @@ -1107,7 +1107,7 @@ function M.write_assigned_event(bufnr, item) -- item.actor.login == vim.g.octo_viewer -- ) local vt = {} - local conf = config.get_config() + local conf = config.values table.insert(vt, { conf.timeline_marker .. " ", "OctoTimelineMarker" }) table.insert(vt, { "EVENT: ", "OctoTimelineItemHeading" }) --vim.list_extend(vt, actor_bubble) @@ -1120,7 +1120,7 @@ end function M.write_commit_event(bufnr, item) local vt = {} - local conf = config.get_config() + local conf = config.values table.insert(vt, { conf.timeline_marker .. " ", "OctoTimelineMarker" }) table.insert(vt, { "EVENT: ", "OctoTimelineItemHeading" }) if item.commit.committer.user ~= vim.NIL then @@ -1148,7 +1148,7 @@ function M.write_merged_event(bufnr, item) -- item.actor.login == vim.g.octo_viewer -- ) local vt = {} - local conf = config.get_config() + local conf = config.values table.insert(vt, { conf.timeline_marker .. " ", "OctoTimelineMarker" }) table.insert(vt, { "EVENT: ", "OctoTimelineItemHeading" }) --vim.list_extend(vt, actor_bubble) @@ -1167,7 +1167,7 @@ function M.write_closed_event(bufnr, item) -- item.actor.login == vim.g.octo_viewer -- ) local vt = {} - local conf = config.get_config() + local conf = config.values table.insert(vt, { conf.timeline_marker .. " ", "OctoTimelineMarker" }) table.insert(vt, { "EVENT: ", "OctoTimelineItemHeading" }) --vim.list_extend(vt, actor_bubble) @@ -1192,7 +1192,7 @@ function M.write_labeled_events(bufnr, items, action) for _, actor in ipairs(vim.tbl_keys(labels_by_actor)) do local vt = {} - local conf = config.get_config() + local conf = config.values table.insert(vt, { conf.timeline_marker .. " ", "OctoTimelineMarker" }) table.insert(vt, { "EVENT: ", "OctoTimelineItemHeading" }) --vim.list_extend(vt, actor_bubble) @@ -1218,7 +1218,7 @@ function M.write_reopened_event(bufnr, item) -- item.actor.login == vim.g.octo_viewer -- ) local vt = {} - local conf = config.get_config() + local conf = config.values table.insert(vt, { conf.timeline_marker .. " ", "OctoTimelineMarker" }) table.insert(vt, { "EVENT: ", "OctoTimelineItemHeading" }) --vim.list_extend(vt, actor_bubble) @@ -1235,7 +1235,7 @@ function M.write_review_requested_event(bufnr, item) -- ) local vt = {} - local conf = config.get_config() + local conf = config.values table.insert(vt, { conf.timeline_marker .. " ", "OctoTimelineMarker" }) table.insert(vt, { "EVENT: ", "OctoTimelineItemHeading" }) --vim.list_extend(vt, actor_bubble) @@ -1256,7 +1256,7 @@ function M.write_review_request_removed_event(bufnr, item) -- item.actor.login == vim.g.octo_viewer -- ) local vt = {} - local conf = config.get_config() + local conf = config.values table.insert(vt, { conf.timeline_marker .. " ", "OctoTimelineMarker" }) table.insert(vt, { "EVENT: ", "OctoTimelineItemHeading" }) --vim.list_extend(vt, actor_bubble) @@ -1277,7 +1277,7 @@ function M.write_review_dismissed_event(bufnr, item) -- item.actor.login == vim.g.octo_viewer -- ) local vt = {} - local conf = config.get_config() + local conf = config.values table.insert(vt, { conf.timeline_marker .. " ", "OctoTimelineMarker" }) table.insert(vt, { "EVENT: ", "OctoTimelineItemHeading" }) --vim.list_extend(vt, actor_bubble) diff --git a/lua/octo/utils.lua b/lua/octo/utils.lua index 2b413757..17bfb2b6 100644 --- a/lua/octo/utils.lua +++ b/lua/octo/utils.lua @@ -170,7 +170,7 @@ function M.parse_remote_url(url, aliases) end function M.parse_git_remote() - local conf = config.get_config() + local conf = config.values local aliases = conf.ssh_aliases local job = Job:new { command = "git", args = { "remote", "-v" }, cwd = vim.fn.getcwd() } job:sync() @@ -192,7 +192,7 @@ function M.parse_git_remote() end function M.get_remote() - local conf = config.get_config() + local conf = config.values local remotes = M.parse_git_remote() for _, name in ipairs(conf.default_remote) do if remotes[name] then @@ -1271,7 +1271,7 @@ end --- Apply mappings to a buffer function M.apply_mappings(kind, bufnr) local mappings = require "octo.mappings" - local conf = config.get_config() + local conf = config.values for action, value in pairs(conf.mappings[kind]) do if not M.is_blank(value) diff --git a/lua/tests/octo/config_spec.lua b/lua/tests/octo/config_spec.lua new file mode 100644 index 00000000..b29f5d9b --- /dev/null +++ b/lua/tests/octo/config_spec.lua @@ -0,0 +1,146 @@ +local config = require "octo.config" + +describe("Octo config", function() + before_each(function() + config.values = config.get_default_values() + end) + describe("validation", function() + describe("for bad configs", function() + it("should return invalid when the base config isn't a table", function() + config.values = "INVALID" + assert.True(vim.tbl_count(require("octo.config").validate_config()) ~= 0) + end) + + it("should return invalid when picker isn't a string", function() + config.values.picker = false + assert.True(vim.tbl_count(require("octo.config").validate_config()) ~= 0) + end) + + it("should return invalid when picker isn't valid", function() + config.values.picker = "other" + assert.True(vim.tbl_count(require("octo.config").validate_config()) ~= 0) + end) + + it("should return invalid when picker_config isn't a table", function() + config.values.picker_config = "cfg" + assert.True(vim.tbl_count(require("octo.config").validate_config()) ~= 0) + end) + + it("should return invalid when picker_config.mappings isn't a table", function() + config.values.picker_config.mappings = "cfg" + assert.True(vim.tbl_count(require("octo.config").validate_config()) ~= 0) + end) + + it("should return invalid when user_icon isn't a string", function() + config.values.user_icon = false + assert.True(vim.tbl_count(require("octo.config").validate_config()) ~= 0) + end) + + it("should return invalid when comment_icon isn't a string", function() + config.values.comment_icon = false + assert.True(vim.tbl_count(require("octo.config").validate_config()) ~= 0) + end) + + it("should return invalid when reaction_viewer_hint_icon isn't a string", function() + config.values.reaction_viewer_hint_icon = false + assert.True(vim.tbl_count(require("octo.config").validate_config()) ~= 0) + end) + + it("should return invalid when outdated_icon isn't a string", function() + config.values.outdated_icon = false + assert.True(vim.tbl_count(require("octo.config").validate_config()) ~= 0) + end) + + it("should return invalid when resolved_icon isn't a string", function() + config.values.resolved_icon = false + assert.True(vim.tbl_count(require("octo.config").validate_config()) ~= 0) + end) + + it("should return invalid when timeline_marker isn't a string", function() + config.values.timeline_marker = false + assert.True(vim.tbl_count(require("octo.config").validate_config()) ~= 0) + end) + + it("should return invalid when timeline_indent isn't a string", function() + config.values.timeline_indent = false + assert.True(vim.tbl_count(require("octo.config").validate_config()) ~= 0) + end) + + it("should return invalid when right_bubble_delimiter isn't a string", function() + config.values.right_bubble_delimiter = false + assert.True(vim.tbl_count(require("octo.config").validate_config()) ~= 0) + end) + + it("should return invalid when left_bubble_delimiter isn't a string", function() + config.values.left_bubble_delimiter = false + assert.True(vim.tbl_count(require("octo.config").validate_config()) ~= 0) + end) + + it("should return invalid when github_hostname isn't a string", function() + config.values.github_hostname = false + assert.True(vim.tbl_count(require("octo.config").validate_config()) ~= 0) + end) + + it("should return invalid when use_local_fs isn't a boolean", function() + config.values.use_local_fs = "not a boolean" + assert.True(vim.tbl_count(require("octo.config").validate_config()) ~= 0) + end) + + it("should return invalid when enable_builtin isn't a boolean", function() + config.values.enable_builtin = "not a boolean" + assert.True(vim.tbl_count(require("octo.config").validate_config()) ~= 0) + end) + + it("should return invalid when snippet_context_lines isn't a number", function() + config.values.snippet_context_lines = "not a number" + assert.True(vim.tbl_count(require("octo.config").validate_config()) ~= 0) + end) + + it("should return invalid when gh_env isn't a table", function() + config.values.gh_env = "not a table" + assert.True(vim.tbl_count(require("octo.config").validate_config()) ~= 0) + end) + + it("should return invalid when timeout isn't a number", function() + config.values.timeout = "not a number" + assert.True(vim.tbl_count(require("octo.config").validate_config()) ~= 0) + end) + + it("should return invalid when ui isn't a table", function() + config.values.ui = "not a table" + assert.True(vim.tbl_count(require("octo.config").validate_config()) ~= 0) + end) + + it("should return invalid when issues isn't a table", function() + config.values.issues = "not a table" + assert.True(vim.tbl_count(require("octo.config").validate_config()) ~= 0) + end) + + it("should return invalid when pull_requests isn't a table", function() + config.values.pull_requests = "not a table" + assert.True(vim.tbl_count(require("octo.config").validate_config()) ~= 0) + end) + + it("should return invalid when file_panel isn't a table", function() + config.values.file_panel = "not a table" + assert.True(vim.tbl_count(require("octo.config").validate_config()) ~= 0) + end) + + it("should return invalid when colors isn't a table", function() + config.values.colors = "not a table" + assert.True(vim.tbl_count(require("octo.config").validate_config()) ~= 0) + end) + + it("should return invalid when mappings isn't a table", function() + config.values.mappings = "not a table" + assert.True(vim.tbl_count(require("octo.config").validate_config()) ~= 0) + end) + end) + + describe("for good configs", function() + it("should return valid for the default config", function() + assert.True(vim.tbl_count(require("octo.config").validate_config()) == 0) + end) + end) + end) +end) diff --git a/lua/tests/plenary/config_spec.lua b/lua/tests/plenary/config_spec.lua index 37370e2d..328bd3fa 100644 --- a/lua/tests/plenary/config_spec.lua +++ b/lua/tests/plenary/config_spec.lua @@ -20,7 +20,8 @@ local user_config = { }, }, } -local merged_config = this.setup(user_config) +this.setup(user_config) +local merged_config = this.values describe("Config module:", function() describe("setup", function() -------------------------------------------------- @@ -37,7 +38,6 @@ describe("Config module:", function() it("user defined mappings completely overrides defaults.", function() eq(merged_config.mappings.issue.close_issue.lhs, "") eq(merged_config.mappings.issue.close_issue.desc, "Close issue") - eq(merged_config.mappings.issue.reopen_issue, nil) eq(merged_config.mappings.pull_request.merge_pr.lhs, "pm") eq(merged_config.mappings.pull_request.merge_pr.desc, "merge commit PR") end)