2.3 KiB · text History 6280797
defmodule GitGud.Imports.Providers.GitUrl do
@moduledoc """
One-off import of an arbitrary git repository by URL — no forge API
involved.
It implements the same `GitGud.Imports.Provider` contract as the
GitHub/GitLab adapters so a single-URL import gets the same batch
record, per-item progress, retries and upstream re-sync as a bulk one;
"discovery" here is just parsing the URL into a one-element list.
Only http(s) URLs are accepted. SSH remotes would need a key we don't
have (and `git` would sit at a host-key or passphrase prompt); use the
https URL with a token instead.
"""
@behaviour GitGud.Imports.Provider
@impl true
def label, do: "Git URL"
@impl true
def default_base_url, do: "https://"
@doc """
`owner` is the clone URL itself. Returns a single normalized repo,
naming it after the last path segment with any `.git` suffix trimmed.
"""
@impl true
def list_repositories(url, _opts) do
with {:ok, %URI{scheme: s, host: h, path: path, userinfo: userinfo}}
when s in ["http", "https"] <-
URI.new(url),
true <- is_binary(h) and h != "",
:ok <- reject_userinfo(userinfo),
name when is_binary(name) <- repo_name(path) do
{:ok,
[
%{
name: name,
full_name: String.trim_trailing(url, ".git"),
clone_url: url,
description: nil,
default_branch: nil,
# Assume private: the safe default when we can't ask anyone.
private: true,
fork: false,
archived: false
}
]}
else
{:error, :credentials_in_url} = err -> err
_ -> {:error, :invalid_clone_url}
end
end
# A URL like `https://user:token@host/repo.git` would put the secret in
# the import record, the repository's `upstream_url`, and the bare
# repo's git config. Refuse it and point at the token field instead.
defp reject_userinfo(nil), do: :ok
defp reject_userinfo(""), do: :ok
defp reject_userinfo(_), do: {:error, :credentials_in_url}
defp repo_name(nil), do: nil
defp repo_name(path) do
path
|> String.split("/", trim: true)
|> List.last()
|> case do
nil -> nil
seg -> seg |> String.trim_trailing(".git") |> nilify_blank()
end
end
defp nilify_blank(""), do: nil
defp nilify_blank(s), do: s
end