defmodule Gogs do
@moduledoc """
Documentation for `Gogs`.
This package is an `Elixir` interface to our `Gogs` Server.
It contains all functions we need to create repositories,
clone, add data to files, commit, push and diff.
Some of these functions use `Git` and others use the `REST API`.
We would _obviously_ prefer if everything was one or the other,
but sadly, some things cannot be done via `Git` or `REST`
so we have adopted a "hybrid" approach.
The functions in this file are defined in the order that we
are _using_ them. So they tell a story.
If you are reading this and prefer to order them alphabetically
or some other way, please share by opening an issue:
github.com/dwyl/gogs/issues
"""
@access_token Envar.get("GOGS_ACCESS_TOKEN")
@api_base_url GogsHelpers.api_base_url()
@httpoison (Application.compile_env(:gogs, :httpoison_mock) &&
Gogs.HTTPoisonMock) || HTTPoison
@doc """
`inject_poison/0` injects a TestDouble of HTTPoison in Test
so that we don't have duplicate mock in consuming apps.
see: github.com/dwyl/elixir-auth-google/issues/35
"""
def inject_poison, do: @httpoison
@doc """
make_url/2 constructs the URL based on the supplied git `url` and TCP `port`.
If the `port` is set it will be a custom Gogs instance.
## Examples
iex> Gogs.make_url("gogs-server.fly.dev", "10022")
"ssh://git@gogs-server.fly.dev:10022/"
iex> Gogs.make_url("github.com")
"git@github.com:"
"""
def make_url(git_url, port \\ 0) do
if port > 0 do
"ssh://git@#{git_url}:#{port}/"
else
"git@#{git_url}:"
end
end
@doc """
returns the remote url for cloning
"""
def remote_url(base_url, org, repo) do
"#{base_url}#{org}/#{repo}.git"
end
@doc """
`parse_body_response/1` parses the response returned by the Gogs Server
so your app can use the resulting JSON.
"""
@spec parse_body_response({atom, String.t()} | {:error, any}) :: {:ok, map} | {:error, any}
def parse_body_response({:error, err}), do: {:error, err}
def parse_body_response({:ok, response}) do
# IO.inspect(response)
body = Map.get(response, :body)
# make keys of map atoms for easier access in templates
if body == nil || byte_size(body) == 0 do
IO.inspect("response body is nil")
{:error, :no_body}
else
{:ok, str_key_map} = Jason.decode(body)
{:ok, Useful.atomize_map_keys(str_key_map)}
end
end
@doc """
`post/2` accepts two arguments: `url` and `params`.
"""
@spec post(String.t(), map) :: {:ok, map} | {:error, any}
def post(url, params \\ %{}) do
# IO.inspect(url, label: url)
body = Jason.encode!(params)
headers = [
{"Accept", "application/json"},
{"Authorization", "token #{@access_token}"},
{"Content-Type", "application/json"}
]
inject_poison().post(url, body, headers)
|> parse_body_response()
end
@doc """
`remote_repo_create/3` accepts two arguments: `org_name`, `repo_name` & `private`.
It creates a repo on the remote `Gogs` instance as defined
by the environment variable `GOGS_URL`.
For convenience it assumes that you only have _one_ `Gogs` instance.
If you have more or different requirements, please share!
"""
def remote_repo_create(org_name, repo_name, private \\ false) do
url = @api_base_url <> "org/#{org_name}/repos"
# IO.inspect(url, label: "remote_repo_create url")
params = %{
name: repo_name,
private: private,
description: repo_name
}
post(url, params)
end
@doc """
clone/1 clones a remote git repository based on `git_repo_url`
returns the path of the _local_ copy of the repository.
"""
def clone(git_repo_url) do
# IO.inspect("git clone #{git_repo_url}")
case Git.clone(git_repo_url) do
{:ok, %Git.Repository{path: path}} ->
# IO.inspect(path)
path
{:error, %Git.Error{message: _message}} ->
# IO.inspect("Attempted to clone #{git_repo_url}, got: #{message}")
get_repo_name_from_url(git_repo_url) |> local_repo_path()
end
end
# Feel free to refactor/simplify this function if you want.
def get_repo_name_from_url(url) do
String.split(url, "/") |> List.last() |> String.split(".git") |> List.first()
end
def local_repo_path(repo) do
temp_dir() <> "/" <> repo
end
# Made this a function in case we want to
defp temp_dir do
File.cwd!
end
# def commit do
# end
end