rhysd / git-messenger.vim

Vim and Neovim plugin to reveal the commit messages under the cursor
MIT License
1.34k stars 32 forks source link

[Idea] Open github pull request of commit #74

Closed jdsutherland closed 3 years ago

jdsutherland commented 3 years ago

Sometimes it's useful to view the pull request for a change to learn more about it.

The way I've found to do this is by using Fugitive's :GBrowse <SHA>, which opens the github commit in browser which can contain a link to the PR (described here).

I added a mapping for this:

function! s:blame__browse() dict abort
    exec ':GBrowse ' . self.state.commit
endfunction
let s:blame.browse = funcref('s:blame__browse')

It's probably possible to directly open the PR by getting the URL from the github api (see here). I briefly experimented with this, but sometimes the PR links would be to the fork or some other incorrect repo, so I'm not sure if this is a reliable method. Another issue with trying to directly open is that not all commits will have a PR, so it can always fail.

Anyway, I thought I'd share in case there is any interest.

Edit:

I looked at this a bit more and arrived at method of reliably opening the PR page using the github API. This depends on https://github.com/mattn/webapi-vim and gh github cli. The API is rate limited to 60 requests per hour without authentication.

function! s:blame__open_github_pr() dict abort
    let owner_repo = trim(system('gh repo view | head -1 | awk "{print \$2}"'))
    let [owner, repo] = split(owner_repo, '/')
    let request_url = 'api.github.com/repos/' . owner . '/' . repo . '/commits/' . self.state.commit . '/pulls'
    let response = webapi#http#get(request_url, '', {"Accept": "application/vnd.github.groot-preview+json"})
    let content = webapi#json#decode(response.content)
    if len(content) < 1 || empty(content[0]._links.html.href)
      echo "git-messenger: No associated pull request for commit"
      return
    endif
    call netrw#BrowseX(content[0]._links.html.href, 0)
endfunction
let s:blame.open_github_pr = funcref('s:blame__open_github_pr')
rhysd commented 3 years ago

Sounds useful, but this plugin is for Git, not GitHub. So supporting features dedicated to GitHub would make this plugin more complicated.

Instead, I want to suggest adding your own mapping at gitmessengerpopup filetype buffer (it means popup window of git-messenger.vim).

function! s:open_github_pr() abort
    " Extract commit hash from buffer content.
    " Hex string after "Commit:" header is commit hash
    let commit_hash = ...
    " Get repository from Git information like output from `git remote get-url`
    let repo = ...
    " Get pull request URL from GitHub API or gh command
    let pr_url = ...
    " Open the URL
    call netrw#BrowseX(pr_url, 0)
endfunction

function! s:setup_gitmessengerpopup() abort
    " <C-o> in the popup window shows its pull request page
    nmap <buffer><silent><C-o> :<C-u>call <SID>open_github_pr()<CR>
    " Or define buffer local command
    command! BrowsePR -buffer -nargs=0 call <SID>open_github_pr()
endfunction
autocmd FileType gitmessengerpopup call <SID>setup_gitmessengerpopup()

Does this meet your requirement?

jdsutherland commented 3 years ago

Thanks @rhysd. I understand this feature is beyond the scope of the plugin. Using ftplugin/gitmessengerpopup.vim is a nice way to extend and avoids syncing a fork.

The only issue I'm having is that the mapping doesn't work. In ftplugin/gitmessengerpopup.vim, I have:

...

function! s:setup_gitmessengerpopup() abort
  nmap <buffer><silent><C-o> :<C-u>call <SID>open_github_pr()<CR>
endfunction
autocmd FileType gitmessengerpopup call <SID>setup_gitmessengerpopup()

If I add command! X :call <sid>open_github_pr(), :X works. Any idea?

jdsutherland commented 3 years ago

The problem I had was resolved by changing nmap to nnoremap. There was also an issue with the command–the name needs to be at the end: command! -buffer -nargs=0 BrowsePR call <SID>open_github_pr().

I'm going to close this then. Thanks again.