Packages

A Mix Task to upload Distillery releases to GitHub.

Current section

Files

Jump to
duckduck lib duck_duck.ex
Raw

lib/duck_duck.ex

defmodule DuckDuck do
use Private
@moduledoc false
# Helper functions for finding release artifacts and uploading them.
alias __MODULE__.{DeadDuckError, Effects}
@effects Application.get_env(:duckduck, :effects_client, Effects)
# print in green
def puts_success(str) do
[:green, str]
|> IO.ANSI.format()
|> IO.puts()
end
# print in red
def puts_failure(str) do
[:red, str]
|> IO.ANSI.format()
|> IO.puts()
end
def fail(str), do: raise(DeadDuckError, message: str)
@spec valid_token?(String.t(), String.t(), String.t()) :: boolean()
def valid_token?(api_token, owner, repo) do
headers = auth_header(api_token)
owner
|> build_token_check_url(repo)
|> @effects.get(headers)
|> valid?()
end
@spec find_upload_url(String.t(), String.t(), String.t(), String.t()) ::
String.t()
def find_upload_url(api_token, owner, repo, tag) do
headers = auth_header(api_token)
owner
|> build_tags_url(repo, tag)
|> @effects.get!(headers)
|> Map.get(:body)
|> Jason.decode!()
|> validate_upload_url()
|> case do
{:error, :not_found} ->
create_release_from_tag(api_token, owner, repo, tag)
{:ok, url} ->
url
end
|> String.replace(~r/\{.*\}/, "")
end
@spec create_release_from_tag(String.t(), String.t(), String.t(), String.t()) ::
String.t()
def create_release_from_tag(api_token, owner, repo, tag) do
headers = auth_header(api_token)
body = Jason.encode!(%{"tag_name" => tag})
owner
|> build_release_creation_url(repo)
|> @effects.post!(body, headers)
|> Map.get(:body)
|> Jason.decode!()
|> Map.get("upload_url")
end
def upload(path, api_token, upload_url) do
headers = auth_header(api_token)
puts_success("Please wait. Uploading #{path}...")
upload_url
|> build_upload_asset_url(path)
|> @effects.post_file!(path, headers)
|> Map.get(:body)
|> Jason.decode!()
|> good_upload?()
end
private do
@spec auth_header(String.t()) :: [{String.t(), String.t()}]
defp auth_header(token), do: [{"Authorization", "token #{token}"}]
@spec build_token_check_url(String.t(), String.t()) :: String.t()
defp build_token_check_url(owner, repo) do
"https://api.github.com/repos/#{owner}/#{repo}"
end
@spec build_tags_url(String.t(), String.t(), String.t()) :: String.t()
defp build_tags_url(owner, repo, tag) do
build_token_check_url(owner, repo) <> "/releases/tags/#{tag}"
end
@spec build_upload_asset_url(String.t(), String.t()) :: String.t()
defp build_upload_asset_url(upload_url, asset_path) do
upload_url <> "?name=" <> Path.basename(asset_path)
end
@spec build_release_creation_url(String.t(), String.t()) :: String.t()
defp build_release_creation_url(owner, repo) do
build_token_check_url(owner, repo) <> "/releases"
end
defp valid?({:ok, %HTTPoison.Response{}}), do: true
defp valid?(_), do: false
defp validate_upload_url(%{"message" => "Not Found"}),
do: {:error, :not_found}
defp validate_upload_url(%{"upload_url" => url}), do: {:ok, url}
defp good_upload?(%{"errors" => [%{"code" => "already_exists"}]}) do
puts_failure("""
GitHub said that there's already a release artifact with this name for
this tag! Make a new tag and trying again.
""")
end
defp good_upload?(%{"message" => "Not Found"}) do
puts_failure("""
I could not write to this tag! Check your token and try again.
""")
end
# denotes that a release was successfully uploaded
defp good_upload?(%{"content_type" => "application/octet-stream"}) do
puts_success("Release successfully uploaded")
end
end
end