From 2541c7fe38c0286c1e3269e139c6d0858fc94815 Mon Sep 17 00:00:00 2001
From: Willem Jan Noort <noortw01@heiway.net>
Date: Wed, 10 Jul 2024 09:38:13 +0200
Subject: [PATCH] fix: Improved more accurate diffing strategy

Previously source was rebased on target, then check diff to target;
this is not how ADO does things, and it leads to incorrect comment
positions.

Now we get the common ancestor commit, and do the diff to that commit.
No more rebasing is required.
---
 .github/workflows/linter.yml |  1 +
 .textlintignore              |  1 +
 lua/adopure/activate.lua     |  4 +--
 lua/adopure/git.lua          | 51 ++++++++++++++++++------------------
 lua/adopure/types.lua        |  6 +++++
 5 files changed, 36 insertions(+), 27 deletions(-)
 create mode 100644 .textlintignore

diff --git a/.github/workflows/linter.yml b/.github/workflows/linter.yml
index 989bc78..a8b63b3 100644
--- a/.github/workflows/linter.yml
+++ b/.github/workflows/linter.yml
@@ -22,3 +22,4 @@ jobs:
           LINTER_RULES_PATH: /
           VALIDATE_JSCPD: false
           VALIDATE_PYTHON_BLACK: false
+          VALIDATE_NATURAL_LANGUAGE: false
diff --git a/.textlintignore b/.textlintignore
new file mode 100644
index 0000000..1b763b1
--- /dev/null
+++ b/.textlintignore
@@ -0,0 +1 @@
+CHANGELOG.md
diff --git a/lua/adopure/activate.lua b/lua/adopure/activate.lua
index 91632af..7b2c1ef 100644
--- a/lua/adopure/activate.lua
+++ b/lua/adopure/activate.lua
@@ -6,8 +6,8 @@ local function confirm_open_in_diffview(pull_request)
         if not input then
             return
         end
-        local remote_target_name = "origin/" .. vim.split(pull_request.targetRefName, "refs/heads/")[2]
-        vim.cmd(":DiffviewOpen " .. remote_target_name)
+        local merge_base = require("adopure.git").get_merge_base(pull_request)
+        vim.cmd(":DiffviewOpen " .. merge_base)
     end)
 end
 
diff --git a/lua/adopure/git.lua b/lua/adopure/git.lua
index fa0703c..5c54877 100644
--- a/lua/adopure/git.lua
+++ b/lua/adopure/git.lua
@@ -67,6 +67,31 @@ function M.get_remote_config()
     return extract_git_details(elected_remote)
 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({
+        command = "git",
+        args = {
+            "merge-base",
+            pull_request.lastMergeSourceCommit.commitId,
+            pull_request.lastMergeTargetCommit.commitId,
+        },
+        cwd = ".",
+    })
+    get_merge_base:start()
+    local result = require("adopure.utils").await_result(get_merge_base)
+    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 merge base found;")
+    return result.stdout[1]
+end
+
 ---@param pull_request adopure.PullRequest
 ---@param open_callable function
 function M.confirm_checkout_and_open(pull_request, open_callable)
@@ -76,11 +101,10 @@ function M.confirm_checkout_and_open(pull_request, open_callable)
             open_callable()
             return
         end
-        local remote_source_name = "origin/" .. vim.split(pull_request.sourceRefName, "refs/heads/")[2]
 
         local git_checkout_remote_job = Job:new({
             command = "git",
-            args = { "checkout", remote_source_name },
+            args = { "checkout", pull_request.lastMergeSourceCommit.commitId },
             cwd = ".",
             on_exit = function(j, return_val)
                 if return_val ~= 0 then
@@ -89,29 +113,6 @@ function M.confirm_checkout_and_open(pull_request, open_callable)
             end,
         })
 
-        local remote_target_name = "origin/" .. vim.split(pull_request.targetRefName, "refs/heads/")[2]
-        local git_rebase_abort_job = Job:new({
-            command = "git",
-            args = { "rebase", "--abort" },
-            cwd = ".",
-            on_exit = function(j, return_val)
-                if return_val ~= 0 then
-                    error("Rebase abort failed: " .. vim.inspect(j:result()))
-                end
-            end,
-        })
-        local git_rebase_job = Job:new({
-            command = "git",
-            args = { "rebase", remote_target_name },
-            cwd = ".",
-            on_exit = function(j, return_val)
-                if return_val ~= 0 then
-                    git_rebase_abort_job:start()
-                    error("Rebase failed: " .. vim.inspect(j:result()))
-                end
-            end,
-        })
-        git_checkout_remote_job:and_then_on_success(git_rebase_job)
         git_checkout_remote_job:start()
         open_callable()
     end)
diff --git a/lua/adopure/types.lua b/lua/adopure/types.lua
index 53279e7..2c07697 100644
--- a/lua/adopure/types.lua
+++ b/lua/adopure/types.lua
@@ -15,8 +15,14 @@
 ---@field createdBy adopure.User
 ---@field creationDate string
 ---@field mergeStatus string
+---@field lastMergeCommit MergeCommit
+---@field lastMergeSourceCommit MergeCommit
+---@field lastMergeTargetCommit MergeCommit
 ---@field reviewers adopure.Reviewer[]
 
+---@class MergeCommit
+---@field commitId string
+
 ---@class adopure.User
 ---@field displayName string
 ---@field id string