2.3 KiB · text History 6280797
defmodule GitGud.Imports.ImportItem do
@moduledoc """
One remote repository inside an import batch. Rows are created during
discovery (`status: "pending"`) and then walked by
`GitGud.Imports.Workers.CloneRepo`, one Oban job per item, so a single
bad repo can't sink the batch.
"""
use Ecto.Schema
import Ecto.Changeset
alias GitGud.Imports.Import
alias GitGud.Repositories.Repository
@statuses ~w(pending cloning imported skipped failed)
schema "repository_import_items" do
field :remote_name, :string
field :remote_full_name, :string
field :clone_url, :string
field :remote_description, :string
field :remote_default_branch, :string
field :remote_private, :boolean, default: false
field :remote_fork, :boolean, default: false
field :remote_archived, :boolean, default: false
field :target_name, :string
field :status, :string, default: "pending"
field :error, :string
belongs_to :import, Import, foreign_key: :repository_import_id
belongs_to :repository, Repository
timestamps(type: :utc_datetime)
end
def statuses, do: @statuses
def done?(%__MODULE__{status: s}), do: s in ~w(imported skipped failed)
def changeset(item, attrs) do
item
|> cast(attrs, [
:remote_name,
:remote_full_name,
:clone_url,
:remote_description,
:remote_default_branch,
:remote_private,
:remote_fork,
:remote_archived,
:target_name,
:status
])
|> validate_required([:remote_name, :remote_full_name, :clone_url, :target_name])
|> validate_inclusion(:status, @statuses)
|> validate_clone_url()
end
def status_changeset(item, attrs) do
item
|> cast(attrs, [:status, :error, :repository_id])
|> validate_inclusion(:status, @statuses)
|> validate_length(:error, max: 2000)
end
# Only ever hand `git clone` an http(s) URL we produced from a provider
# API response. Guards against a hostile/compromised API handing back
# `ext::sh -c ...` or a local path.
defp validate_clone_url(changeset) do
validate_change(changeset, :clone_url, fn :clone_url, url ->
case URI.new(url) do
{:ok, %URI{scheme: s, host: h}}
when s in ["http", "https"] and is_binary(h) and h != "" ->
[]
_ ->
[clone_url: "must be an http(s) clone URL"]
end
end)
end
end