~tomleb/repo-url.nvim

ea15377e5e338b10dc6e1229849c5b353da07cb7 — Tom Lebreux 4 months ago 7c52fcd
Prefer tracked remote first, then fallback on preferred_upstream
1 files changed, 84 insertions(+), 29 deletions(-)

M lua/repo-url/init.lua
M lua/repo-url/init.lua => lua/repo-url/init.lua +84 -29
@@ 13,6 13,12 @@ local M = {}
--- @field history_url (fun(RepoUrl.UrlBuilderParams): string)?
--- @field raw_url (fun(RepoUrl.UrlBuilderParams): string)?
--- @field tree_url (fun(RepoUrl.UrlBuilderParams): string)?
--
--- @class RepoUrl.GitDir
--- @field path string
--- @field commit string
--- @field branch? string The current checked out branch if any
--- @field remote? string The tracked remote of the current branch if any

local fallback_gocache_dir = nil



@@ 317,18 323,77 @@ local function list_git_remotes(git_dir)
  return remotes
end

---@param git_dir string
---@param preferred_remotes string[]
---@return {commit: string, remote_url: string, hostname: string}
local function git_info(git_dir, preferred_remotes)
  local commit_command = { 'git', '-C', git_dir, 'rev-parse', 'HEAD' }
  local commit, commit_success = git_run(commit_command)
  if not commit_success then
    error('unable to get git commit: ' .. commit)
-- find_remote attempts to find the remote for the git repository at the given commit
-- It does this heuristically in the following order, until one succeeds:
--   1. Uses the tracked remote of the branch
--   2. Uses the preferred_remotes config
--   3. Fallbacks to any remote
--- @param git_dir RepoUrl.GitDir
local function find_remote(git_dir)
  -- Try to get the tracked remote first
  if git_dir.remote then
    return git_dir.remote
  end

  local remotes = list_git_remotes(git_dir.path)
  if not remotes then
    error 'no remote found'
  end
  -- Check preferred
  for _, it in ipairs(config.preferred_remotes) do
    if remotes[it] then
      return it
    end
  end

  -- Fallback to any remote
  for it, _ in ipairs(remotes) do
    return it
  end
end

--- @param path string
--- @return RepoUrl.GitDir
local function current_git_dir(path)
  local ok = false
  local git_dir = {
    path = path,
  }

  local cmd = { 'git', '-C', path, 'rev-parse', 'HEAD' }
  git_dir.commit, ok = git_run(cmd)
  if not ok then
    error('unable to get git commit: ' .. git_dir.commit)
  end

  local branch
  cmd = { 'git', '-C', path, 'rev-parse', '--abbrev-ref', 'HEAD' }
  branch, ok = git_run(cmd)
  if not ok then
    error('unable to get git branch: ' .. branch)
  end

  if branch and branch ~= 'HEAD' then
    git_dir.branch = branch

    local remote
    cmd = { 'git', '-C', path, 'config', '--get', 'branch.' .. branch .. '.remote' }
    remote, ok = git_run(cmd)
    if not ok then
      error('unable to get git remote: ' .. remote)
    end
    if remote and remote ~= '' then
      git_dir.remote = remote
    end
  end
  return git_dir
end

---@param path string
---@return {commit: string, remote_url: string, hostname: string}
local function git_info(path)
  local function get_remote_url(remote_name)
    local remote_command = { 'git', '-C', git_dir, 'remote', 'get-url', remote_name }
    local remote_command = { 'git', '-C', path, 'remote', 'get-url', remote_name }
    local remote_url, remote_success = git_run(remote_command)
    if not remote_success then
      error('unable to get git remote url: ' .. remote_url)


@@ 355,32 420,22 @@ local function git_info(git_dir, preferred_remotes)
    return remote_to_url(remote_url)
  end

  local remote_url = nil
  local remotes = list_git_remotes(git_dir)
  -- Check preferred
  for _, remote in ipairs(preferred_remotes) do
    if remotes[remote] then
      remote_url = get_remote_url(remote)
      break
    end
  end
  -- Fallback to the rest
  if remote_url == nil then
    for _, remote in ipairs(remotes) do
      if remotes[remote] then
        remote_url = get_remote_url(remote)
        break
      end
    end
  local git_dir = current_git_dir(path)

  local remote = find_remote(git_dir)
  if not remote then
    error 'unable to find remote'
  end

  local remote_url = get_remote_url(remote)
  if remote_url == nil then
    error 'unable to find remote'
    error 'unable to find remote url'
  end

  local hostname = remote_url:match '://([^/]+)/'

  return {
    commit = commit,
    commit = git_dir.commit,
    remote_url = remote_url,
    hostname = hostname,
  }


@@ 426,7 481,7 @@ local get_repo_info = function()
    error 'not a git repository'
  end

  local git = git_info(project_dir, config.preferred_remotes)
  local git = git_info(project_dir)
  local rel_filepath = string.sub(filename, #project_dir + 2)
  local info = {
    base_url = git.remote_url,