Current section

Files

Jump to
git_street lib git_street.ex
Raw

lib/git_street.ex

defmodule GitStreet do
@moduledoc """
Documentation for GitStreet.
"""
@doc """
Entrypoint for further working with existing git repository.
## Examples
iex> GitStreet.open
%GitStreet.Repo{path: "/current/directory/path/.git"}
iex> GitStreet.open("/user/repo/path")
%GitStreet.Repo{path: "/user/repo/path/.git"}
"""
@spec open(Path.t()) :: %GitStreet.Repo{} | {:error, binary}
def open, do: open(File.cwd!)
def open(path) when is_binary(path) do
if File.exists?("#{path}/.git"), do: %GitStreet.Repo{path: path}, else: {:error, "invalid path"}
end
def open(_path), do: {:error, "invalid argument"}
@doc """
Shows the commit logs.
You can set `limit` option and function returns limited output of commits.
## Examples
iex> GitStreet.log(%GitStreet.Repo{path: "/user/repo/path"})
[%{
author_name: "Author Name",
author_email: "author.name@gmail.com",
created_at: "Tue Feb 4 14:13:37 2020 +0200",
hash: "fa6ff4e6b12b90b035671d1eb44a7762191c175c",
message: "commit message"
},
%{
....
}]
iex> GitStreet.log(%GitStreet.Repo{path: "/user/repo/path"}, limit: 1)
[%{
author_name: "Author Name",
author_email: "author.name@gmail.com",
created_at: "Tue Feb 4 14:13:37 2020 +0200",
hash: "fa6ff4e6b12b90b035671d1eb44a7762191c175c",
message: "commit message"
}]
"""
@spec log(%GitStreet.Repo{}, keyword) :: list(map)
def log(repository, options \\ [])
def log(%GitStreet.Repo{path: path}, options) do
limit = Keyword.get(options, :limit, -1)
{string_of_commits, _} = System.cmd("git", ["log", "-n #{limit}", "--pretty=%H /-/ %an /-/ %ae /-/ %at /-/ %s"], cd: path)
string_of_commits
|> String.split("\n", trim: true)
|> Enum.map(fn commit ->
[hash, name, email, date, message] = String.split(commit, " /-/ ")
{microseconds, _} = Integer.parse(date)
%{hash: hash, author_name: name, author_email: email, created_at: DateTime.from_unix!(microseconds), message: message}
end)
end
def log(_path, _options), do: {:error, "invalid argument"}
@doc """
Clone a repository into a new directory.
You can set `path` option and set the name of a new directory to clone into.
## Examples
iex> GitStreet.clone("git@provider.com:repo_name.git")
%GitStreet.Repo{path: "/current/directory/path/repo_name/.git"}
iex> GitStreet.clone("git@provider.com:repo_name.git", path: "/users/directory/path")
%GitStreet.Repo{path: "/users/directory/path/repo_name/.git"}
"""
@spec clone(String.t, keyword) :: String.t
def clone(link, options \\ [])
def clone(link, options) when is_binary(link) do
path = Keyword.get(options, :path, File.cwd!)
project_name = Regex.run(~r/^(https|git)(:\/\/|@)([^\/:]+)[\/:]([^\/:]+)\/(.+).git$/, link) |> List.last
project_path = "#{path}/#{project_name}"
System.cmd("git", ["clone", link, project_path, "-q"])
%GitStreet.Repo{path: project_path}
end
def clone(_link, _options), do: {:error, "invalid argument"}
@doc """
List of branches
## Examples
iex> GitStreet.branch(%GitStreet.Repo{path: "/user/repo/path"})
["master", "release", "feature/123"]
"""
@spec branch(%GitStreet.Repo{}) :: list
def branch(%GitStreet.Repo{path: path}) do
System.cmd("git", ["remote", "set-head", "origin", "-d"], cd: path)
{string_of_branches, _} = System.cmd("git", ["branch", "-rl"], cd: path)
string_of_branches
|> String.split("\n", trim: true)
|> Enum.map(fn branch ->
[_, branch_name] = Regex.run(~r/origin\/(.*)/, branch)
branch_name
end)
end
def branch(_path), do: {:error, "invalid argument"}
@doc """
Switch branches or restore working tree files
## Examples
iex> GitStreet.checkout(%GitStreet.Repo{path: "/user/repo/path"}, "my_branch")
{:ok, "Switched to branch my_branch"}
iex> GitStreet.checkout(%GitStreet.Repo{path: "/user/repo/path"}, "nonexistent_branch")
{:ok, "Couldn`t switch to nonexistent_branch"}
"""
@spec checkout(%GitStreet.Repo{}, String.t) :: tuple
def checkout(%GitStreet.Repo{path: path}, branch_name) when is_binary(branch_name) do
{result, _} = System.cmd("git", ["checkout", branch_name], stderr_to_stdout: true, cd: path)
case String.match?(result, ~r/^error/) do
true -> {:error, "Couldn`t switch to #{branch_name}"}
false -> {:ok, "Switched to branch #{branch_name}"}
end
end
def checkout(_path, _branch_name), do: {:error, "invalid argument"}
end