Skip to content

Commit

Permalink
feat!: big project refactor
Browse files Browse the repository at this point in the history
New features:
- support for using the plugin with any working directory (as long as it
  is in the repo)
- edit comments
- delete comments
  • Loading branch information
noortw01 committed Jan 6, 2025
1 parent b61fe1f commit de0d03d
Show file tree
Hide file tree
Showing 21 changed files with 787 additions and 534 deletions.
3 changes: 2 additions & 1 deletion .github/workflows/lemmy-help.yml
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,8 @@ jobs:
./lemmy-help \
lua/adopure.lua \
lua/adopure/config/meta.lua \
lua/adopure/state.lua \
lua/adopure/types/ado_state.lua \
lua/adopure/types/state_manager.lua \
lua/adopure/thread.lua \
lua/adopure/quickfix.lua \
lua/adopure/pickers/thread.lua \
Expand Down
31 changes: 22 additions & 9 deletions lua/adopure.lua
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@

---@toc adopure.contents

---@mod adopure
Expand Down Expand Up @@ -38,7 +37,7 @@
--- *existing_thread*: Opens a window with an existing comment thread.
---
--->vim
--- :AdoPure [ submit ] [ comment | vote | thread_status ] [ opts ]
--- :AdoPure [ submit ] [ comment | vote | thread_status | delete_comment | edit_comment ] [ opts ]
---<
---Submits specified argument to Azure DevOps.
---
Expand All @@ -48,6 +47,10 @@
---
--- *thread_status*: Submit a thread_status change; must be in existing_thread window.
---
--- *delete_comment*: Delete one of your own comments; must be in existing_thread window.
---
--- *edit_comment*: Edit one of your own comments; must be in existing_thread window.
---
--->vim
--- :AdoPure [ unload ]
---<
Expand Down Expand Up @@ -120,17 +123,27 @@ local subcommand_tbl = {
end,
},
submit = {
complete_args = { "comment", "vote", "thread_status" },
complete_args = { "comment", "vote", "thread_status", "delete_comment", "edit_comment" },
impl = function(args)
---@param target adopure.UpdateThreadTarget
local function update_thread(target)
adopure.get_loaded_state():update_thread({ target = target })
end
local sub_impl = {
comment = function(opts)
require("adopure.thread").submit_comment(adopure.get_loaded_state(), opts)
adopure.get_loaded_state():submit_comment(opts)
end,
vote = function(opts)
require("adopure.review").submit_vote(adopure.get_loaded_state(), opts)
end,
thread_status = function(opts)
require("adopure.thread").update_thread_status(adopure.get_loaded_state(), opts)
thread_status = function(_)
update_thread("update_status")
end,
delete_comment = function(_)
update_thread("delete_comment")
end,
edit_comment = function(_)
update_thread("edit_comment")
end,
}
execute_or_prompt(sub_impl, args, "submit")
Expand All @@ -141,7 +154,7 @@ local subcommand_tbl = {
impl = function(args)
local sub_impl = {
quickfix = function(opts)
require("adopure.quickfix").render_quickfix(adopure.get_loaded_state().pull_request_threads, opts)
require("adopure.quickfix").render_quickfix(adopure.get_loaded_state(), opts)
end,
thread_picker = function(opts)
require("adopure.pickers.thread").choose_thread(adopure.get_loaded_state(), opts)
Expand Down Expand Up @@ -193,8 +206,8 @@ end
---@usage ]]
function adopure.load_state_manager()
if not state_manager then
local context = require("adopure.state").AdoContext:new()
state_manager = require("adopure.state").StateManager:new(context)
local context = require("adopure.types.state_manager").AdoContext:new()
state_manager = require("adopure.types.state_manager").StateManager:new(context)
end
assert(state_manager, "StateManager should not be nil after loading;")
return state_manager
Expand Down
3 changes: 2 additions & 1 deletion lua/adopure/activate.lua
Original file line number Diff line number Diff line change
Expand Up @@ -11,14 +11,15 @@ local function confirm_open_in_diffview(pull_request)
end)
end

---@param state adopure.AdoState
local function buffer_marker_autocmd(state)
local augroup = vim.api.nvim_create_augroup("adopure.nvim", { clear = true })
vim.api.nvim_create_autocmd({ "BufEnter" }, {
group = augroup,
callback = function(args)
if state.pull_request_threads and args.file ~= "" then
require("adopure.marker").clear_removed_comment_marks(args.buf, state.pull_request_threads)
require("adopure.marker").create_new_comment_marks(args.buf, state.pull_request_threads, args.file)
require("adopure.marker").create_new_comment_marks(args.buf, state, args.file)
end
end,
})
Expand Down
39 changes: 32 additions & 7 deletions lua/adopure/api.lua
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ local M = {}
local curl = require("plenary.curl")
local config = require("adopure.config.internal")

local GIT_API_VERSION = "api-version=7.1-preview.1"
local GIT_API_VERSION = "api-version=7.1"

local access_token = config:access_token()
local organization_url = ""
Expand All @@ -26,7 +26,7 @@ local function get_azure_devops(url, request_type)
if not ok or not response or response.status ~= 200 then
local details = ""
if response then
details = response.body or tostring(response)
details = (response.body ~= "" and response.body) or vim.inspect(response)
end
return nil, "Failed to retrieve " .. request_type .. "; " .. details
end
Expand Down Expand Up @@ -60,6 +60,17 @@ function M.get_repository(context)
end
end

---Get connection data from Azure DevOps
---@return adopure.ConnectionData|nil connection_data, string|nil err
function M.get_connection_data()
---@type adopure.ConnectionData
local result, err = get_azure_devops(organization_url .. "/_apis/connectionData", "connectionData")
if err then
return nil, err
end
return result, err
end

---Get pull requests from Azure DevOps
---@param repository adopure.Repository
---@return adopure.PullRequest[] pull_requests, string|nil err
Expand Down Expand Up @@ -216,21 +227,35 @@ function M.delete_pull_request_comment(pull_request, thread, comment_id)
local result, err = submit_azure_devops(
table.concat({ pull_request.url, "/threads/", thread.id, "/comments/", comment_id, "?", GIT_API_VERSION }),
"DELETE",
"pull request thread update",
"pull request thread comment delete",
nil
)
return result, err
end

---Update pull request comment
---@param pull_request adopure.PullRequest
---@param thread adopure.Thread
---@param comment adopure.Comment
---@return adopure.Thread|nil thread, string|nil err
function M.update_pull_request_comment(pull_request, thread, comment)
---@type adopure.Thread|nil
local result, err = submit_azure_devops(
table.concat({ pull_request.url, "/threads/", thread.id, "/comments/", comment.id, "?", GIT_API_VERSION }),
"PATCH",
"pull request thread comment update",
comment
)
return result, err
end

---Create new pull request vote
---@param pull_request adopure.PullRequest
---@param vote PullRequestVote
---@return adopure.Reviewer|nil reviewer, string|nil err
function M.submit_vote(pull_request, vote)
---@type adopure.ConnectionData
local connection_result, connection_err =
get_azure_devops(organization_url .. "/_apis/connectionData", "connectionData")
if connection_err then
local connection_result, connection_err = M.get_connection_data()
if connection_err or not connection_result then
return nil, connection_err
end

Expand Down
46 changes: 31 additions & 15 deletions lua/adopure/git.lua
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,12 @@ local function elect_remote(remote_stdout)
end

---@param remote_stdout string
---@param root_path string
---@return string organization_url
---@return string project_name
---@return string repository_name
local function extract_git_details(remote_stdout)
---@return string root_path
local function extract_git_details(remote_stdout, root_path)
local host, project_name, repository_name, organization_name
local url_with_type = vim.split(remote_stdout, "\t")[2]
local url = vim.split(url_with_type, " ")[1]
Expand All @@ -41,37 +43,51 @@ local function extract_git_details(remote_stdout)
host = user_at_host_parts[#user_at_host_parts]
end
local organization_url = table.concat({ "https://", host, "/", organization_name, "/" })
return organization_url, project_name, repository_name
return organization_url, project_name, repository_name, root_path
end

---Get config from git remote
---@return string organization_url
---@return string project_name
---@return string repository_name
---@return string root_path
function M.get_remote_config()
local get_remotes = require("plenary.job"):new({
local get_remotes = require("plenary.job"):new({ ---@diagnostic disable-line: missing-fields
command = "git",
args = { "remote", "-v" },
cwd = ".",
})
local get_root = require("plenary.job"):new({ ---@diagnostic disable-line: missing-fields
command = "git",
args = { "rev-parse", "--show-toplevel" },
cwd = ".",
})

get_remotes:start()
local result = require("adopure.utils").await_result(get_remotes)
if result.stderr[1] then
if not result.stdout[1] then
error(result.stderr[1])
end
vim.notify(result.stderr[1], 3)
end
assert(result.stdout[1], "No remote found to extract details;")
local elected_remote = elect_remote(result.stdout)
return extract_git_details(elected_remote)
get_root:start()
local remote_result = require("adopure.utils").await_result(get_remotes)
local root_result = require("adopure.utils").await_result(get_root)
vim.iter({ remote_result, root_result })
:filter(function(result) ---@param result adopure.JobResult
return not not result.stderr[1]
end)
:each(function(result) ---@param result adopure.JobResult
if not result.stdout[1] then
error(result.stderr[1])
end
vim.notify(result.stderr[1], 3)
end)
assert(remote_result.stdout[1], "No remote found to extract details;")
assert(root_result.stdout[1], "No root location found in repo;")
local elected_remote = elect_remote(remote_result.stdout)
return extract_git_details(elected_remote, root_result.stdout[1])
end

---Get merge base commit
---@param pull_request adopure.PullRequest
---@return string merge_base
function M.get_merge_base(pull_request)
local get_merge_base = require("plenary.job"):new({
local get_merge_base = require("plenary.job"):new({ ---@diagnostic disable-line: missing-fields
command = "git",
args = {
"merge-base",
Expand Down Expand Up @@ -102,7 +118,7 @@ function M.confirm_checkout_and_open(pull_request, open_callable)
return
end

local git_checkout_remote_job = Job:new({
local git_checkout_remote_job = Job:new({ ---@diagnostic disable-line: missing-fields
command = "git",
args = { "checkout", pull_request.lastMergeSourceCommit.commitId },
cwd = ".",
Expand Down
4 changes: 2 additions & 2 deletions lua/adopure/health.lua
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ local function check_pat_token()
end
local function check_context()
local context_ok, context = pcall(function()
return require("adopure.state").AdoContext:new()
return require("adopure.types.state_manager").AdoContext:new()
end)
if not context_ok then
vim.health.error(tostring(context))
Expand All @@ -31,7 +31,7 @@ local function check_context()
return true
end
local function check_token_in_context()
local context = require("adopure.state").AdoContext:new()
local context = require("adopure.types.state_manager").AdoContext:new()
local ok, repository = pcall(require("adopure.api").get_repository, context)
if not ok or not repository then
vim.health.error(tostring(repository or "No repository found with pat_token in this context;"))
Expand Down
78 changes: 24 additions & 54 deletions lua/adopure/marker.lua
Original file line number Diff line number Diff line change
Expand Up @@ -73,74 +73,44 @@ local function create_extmark(bufnr, pull_request_thread, context)
end

---@param bufnr number
---@param pull_request_threads adopure.Thread[]
---@param pull_request_threads adopure.AdoThread[]
function M.clear_removed_comment_marks(bufnr, pull_request_threads)
---@param extmark table<number, number, number, table>
local function clear_extmark(extmark)
vim.api.nvim_buf_del_extmark(bufnr, namespace, extmark[1])
end

---@param extmark table<number, number, number, table>
local function mark_not_in_pull_request_threads(extmark)
---@param pull_request_thread adopure.Thread
local function mark_match_thread(pull_request_thread)
return extmark[1] == pull_request_thread.id
end

return not vim.iter(pull_request_threads):any(mark_match_thread)
end

---@type table<number, number, number, table>[]
local existing_marks = vim.api.nvim_buf_get_extmarks(bufnr, namespace, 0, -1, { details = true })

vim.iter(existing_marks):filter(mark_not_in_pull_request_threads):each(clear_extmark)
vim.iter(existing_marks)
:filter(function(extmark) ---@param extmark vim.api.keyset.get_extmark_item
---@type adopure.AdoThread|nil
local thread = vim.iter(pull_request_threads)
:find(function(pull_request_thread) ---@param pull_request_thread adopure.AdoThread
return pull_request_thread:match_mark(extmark)
end)
return not (thread and thread:is_active_thread())
end)
:each(function(extmark) ---@param extmark vim.api.keyset.get_extmark_item
vim.api.nvim_buf_del_extmark(bufnr, namespace, extmark[1])
end)
end

---Create
---@param bufnr number
---@param pull_request_threads adopure.Thread[]
---@param state adopure.AdoState
---@param file_path string
function M.create_new_comment_marks(bufnr, pull_request_threads, file_path)
local focused_file_path = tostring(Path:new(file_path):make_relative())

---@type table<number, number, number, table>[]
function M.create_new_comment_marks(bufnr, state, file_path)
local focused_file_path = tostring(Path:new(file_path):make_relative(state.root_path))
local existing_marks = vim.api.nvim_buf_get_extmarks(bufnr, namespace, 0, -1, { details = true })
---@param thread adopure.Thread
---@return boolean
local function should_render_thread(thread)
---@param extmark table<number, number, number, table>
local function mark_match_thread(extmark)
return extmark[1] == thread.id
end
if thread.threadContext == vim.NIL or vim.iter(existing_marks):any(mark_match_thread) then
return false
end

local path_reference = thread.threadContext.filePath
if
focused_file_path ~= tostring(Path:new(string.sub(path_reference, 2)))
or thread.isDeleted
or thread.threadContext.rightFileStart == vim.NIL
then
return false
end

return true
end
---@param thread adopure.Thread
local function _create_extmark(thread)
create_extmark(bufnr, thread, thread.threadContext)
end

vim.iter(pull_request_threads):filter(should_render_thread):each(_create_extmark)
vim.iter(state.pull_request_threads)
:filter(function(thread) ---@param thread adopure.AdoThread
return thread:should_render_extmark(existing_marks, focused_file_path)
end)
:each(function(thread) ---@param thread adopure.AdoThread
create_extmark(bufnr, thread, thread.threadContext)
end)
end

---Get extmarks at the cursor position
---@return table<number, number, number>[]: extmark_id, row, col
function M.get_extmarks_at_position()
local line = vim.api.nvim_win_get_cursor(0)[1] - 1
local buffer_marks = vim.api.nvim_buf_get_extmarks(0, namespace, { line, 0 }, { line + 1, 0 }, {})
return buffer_marks
return vim.api.nvim_buf_get_extmarks(0, namespace, { line, 0 }, { line + 1, 0 }, {})
end

return M
Loading

0 comments on commit de0d03d

Please sign in to comment.