-
-
Notifications
You must be signed in to change notification settings - Fork 193
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add GitHub integration #839
base: main
Are you sure you want to change the base?
Changes from all commits
c3deefe
ac03a80
b20d616
8f4dbab
5fb7d79
ea8ccb1
b15d197
3c596fe
1998b16
0423002
014ad51
c58b9e6
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -46,6 +46,7 @@ end | |
--- @field delay integer | ||
--- @field ignore_whitespace boolean | ||
--- @field virt_text_priority integer | ||
--- @field github_blame boolean | ||
|
||
--- @class Gitsigns.Config | ||
--- @field debug_mode boolean | ||
|
@@ -70,6 +71,7 @@ end | |
--- @field current_line_blame_formatter_opts { relative_time: boolean } | ||
--- @field current_line_blame_formatter string|Gitsigns.CurrentLineBlameFmtFun | ||
--- @field current_line_blame_formatter_nc string|Gitsigns.CurrentLineBlameFmtFun | ||
--- @field current_line_blame_formatter_gh string|Gitsigns.CurrentLineBlameFmtFun | ||
--- @field current_line_blame_opts Gitsigns.CurrentLineBlameOpts | ||
--- @field preview_config table<string,any> | ||
--- @field attach_to_untracked boolean | ||
|
@@ -430,15 +432,15 @@ M.schema = { | |
count_chars = { | ||
type = 'table', | ||
default = { | ||
[1] = '1', -- '₁', | ||
[2] = '2', -- '₂', | ||
[3] = '3', -- '₃', | ||
[4] = '4', -- '₄', | ||
[5] = '5', -- '₅', | ||
[6] = '6', -- '₆', | ||
[7] = '7', -- '₇', | ||
[8] = '8', -- '₈', | ||
[9] = '9', -- '₉', | ||
[1] = '1', -- '₁', | ||
[2] = '2', -- '₂', | ||
[3] = '3', -- '₃', | ||
[4] = '4', -- '₄', | ||
[5] = '5', -- '₅', | ||
[6] = '6', -- '₆', | ||
[7] = '7', -- '₇', | ||
[8] = '8', -- '₈', | ||
[9] = '9', -- '₉', | ||
['+'] = '>', -- '₊', | ||
}, | ||
description = [[ | ||
|
@@ -669,6 +671,26 @@ M.schema = { | |
]], | ||
}, | ||
|
||
current_line_blame_formatter_gh = { | ||
type = { 'string', 'function' }, | ||
default = ' <author>, <mergedAt>, PR: #<number> • <title>', | ||
description = [[ | ||
String or function used to format the virtual text of | ||
|gitsigns-config-current_line_blame| when github is used. | ||
|
||
Note: |gitsigns-config-current_line_blame_opts-github_blame| must be active. | ||
|
||
When a string, accepts the following format specifiers in addition to the defaults: | ||
|
||
• `<number>` | ||
• `<author>` | ||
• `<mergedAt>` or `<mergedAt:FORMAT>` | ||
• `<title>` | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. As an improvement, we could expand this to the full list of fields that |
||
|
||
See |gitsigns-config-current_line_blame_formatter| for more information. | ||
]], | ||
}, | ||
|
||
trouble = { | ||
type = 'boolean', | ||
default = function() | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -5,6 +5,7 @@ local scheduler = a.scheduler | |
|
||
local cache = require('gitsigns.cache').cache | ||
local config = require('gitsigns.config').config | ||
local gh = require('gitsigns.gh') | ||
local util = require('gitsigns.util') | ||
local uv = vim.loop | ||
|
||
|
@@ -63,7 +64,7 @@ BlameCache.contents = {} | |
|
||
--- @param bufnr integer | ||
--- @param lnum integer | ||
--- @param x? Gitsigns.BlameInfo | ||
--- @param x? Gitsigns.BlameInfo|GitHub.PrInfo | ||
function BlameCache:add(bufnr, lnum, x) | ||
if not x then | ||
return | ||
|
@@ -80,7 +81,7 @@ end | |
|
||
--- @param bufnr integer | ||
--- @param lnum integer | ||
--- @return Gitsigns.BlameInfo? | ||
--- @return Gitsigns.BlameInfo|GitHub.PrInfo|nil | ||
function BlameCache:get(bufnr, lnum) | ||
if not config._blame_cache then | ||
return | ||
|
@@ -121,7 +122,7 @@ local running = false | |
--- @param bufnr integer | ||
--- @param lnum integer | ||
--- @param opts Gitsigns.CurrentLineBlameOpts | ||
--- @return Gitsigns.BlameInfo? | ||
--- @return Gitsigns.BlameInfo|GitHub.PrInfo|nil | ||
local function run_blame(bufnr, lnum, opts) | ||
local result = BlameCache:get(bufnr, lnum) | ||
if result then | ||
|
@@ -136,6 +137,18 @@ local function run_blame(bufnr, lnum, opts) | |
local buftext = util.buf_lines(bufnr) | ||
local bcache = cache[bufnr] | ||
result = bcache.git_obj:run_blame(buftext, lnum, opts.ignore_whitespace) | ||
|
||
if result and opts.github_blame then | ||
local last_pr = gh.get_last_associated_pr(result.sha); | ||
|
||
if last_pr then | ||
result = last_pr; | ||
-- the parser does not support accessing keys like <author.name> | ||
result.author = last_pr.author.name | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
result.is_github = true; | ||
end | ||
end | ||
|
||
BlameCache:add(bufnr, lnum, result) | ||
running = false | ||
|
||
|
@@ -149,9 +162,17 @@ end | |
local function handle_blame_info(bufnr, lnum, blame_info, opts) | ||
local bcache = cache[bufnr] | ||
local virt_text ---@type {[1]: string, [2]: string}[] | ||
local clb_formatter = blame_info.author == 'Not Committed Yet' | ||
and config.current_line_blame_formatter_nc | ||
or config.current_line_blame_formatter | ||
local code_committed = blame_info.author ~= 'Not Committed Yet' | ||
local use_github = opts.github_blame and blame_info.is_github; | ||
|
||
local clb_formatter = code_committed | ||
and config.current_line_blame_formatter | ||
or config.current_line_blame_formatter_nc | ||
|
||
if code_committed and use_github then | ||
clb_formatter = config.current_line_blame_formatter_gh | ||
end | ||
|
||
if type(clb_formatter) == 'string' then | ||
virt_text = { | ||
{ | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,76 @@ | ||
local async = require('gitsigns.async') | ||
local log = require('gitsigns.debug.log') | ||
local subprocess = require('gitsigns.subprocess') | ||
|
||
--- @class GitHub.PrInfo | ||
--- @field url string | ||
--- @field author {login: string, name: string} | ||
--- @field mergedAt string | ||
--- @field number string | ||
--- @field title string | ||
--- @field is_github? boolean | ||
|
||
local M = {} | ||
|
||
local GH_NOT_FOUND_ERROR = "Could not find 'gh' command. Is the gh-cli package installed?"; | ||
|
||
|
||
local gh_command = function(args) | ||
if vim.fn.executable('gh') then | ||
return async.wait(2, subprocess.run_job, { command = 'gh', args = args }); | ||
end | ||
|
||
return {}; | ||
end | ||
|
||
--- Requests a list of GitHub PRs associated with the given commit SHA | ||
--- | ||
--- @param sha string The commit SHA | ||
--- | ||
--- @return GitHub.PrInfo[]? : Array of PR object | ||
M.associated_prs = function(sha) | ||
local _, _, stdout, stderr = gh_command({ | ||
'pr', 'list', | ||
'--search', sha, | ||
'--state', 'merged', | ||
'--json', 'url,author,title,number,mergedAt', | ||
}) | ||
|
||
if stderr then | ||
log.eprintf("Received stderr when running 'gh pr list' command:\n%s", stderr) | ||
end | ||
|
||
local empty_set_len = 2; | ||
|
||
if type(stdout) == string and #stdout > empty_set_len then | ||
return vim.json.decode(stdout); | ||
end | ||
|
||
return nil; | ||
end | ||
|
||
--- Returns the last PR associated with the commit | ||
--- | ||
--- @param sha string The commit SHA | ||
--- | ||
--- @return GitHub.PrInfo? : The latest PR associated with the commit or nil | ||
M.get_last_associated_pr = function(sha) | ||
local prs = M.associated_prs(sha); | ||
--- @type GitHub.PrInfo? | ||
local last_pr = nil; | ||
|
||
if prs then | ||
for _, pr in ipairs(prs) do | ||
local pr_number = tonumber(pr.number); | ||
local last_pr_number = last_pr and tonumber(last_pr.number) or 0; | ||
|
||
if pr_number > last_pr_number then | ||
last_pr = pr | ||
end | ||
end | ||
end | ||
|
||
return last_pr; | ||
end | ||
|
||
return M |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@lewis6991 should this be called something like
use_github
or something like that instead?