Current section
Files
Jump to
Current section
Files
lib/duck_duck/effects.ex
defmodule DuckDuck.Effects do
@moduledoc false
alias Mix.Project
@no_api_token_msg """
Couldn't find the API token! Please add a valid GitHub API token either
- In the default location: `~/.goose_api_token`
- In a config file like so
```
# config/config.exs
config :duckduck,
owner: "the-mikedavis",
repo: "duck_duck",
token_file: "~/.duck_duck_token_file" # OR
api_token: "MY_API_TOKEN"
```
"""
defmodule Behaviour do
@moduledoc false
@callback get_tag() :: String.t()
@callback release_files(atom(), String.t(), Path.t()) :: [Path.t()]
@callback build_path() :: Path.t()
@callback read_api_token() :: String.t() | no_return()
@callback start_http_client() :: :ok
@callback post_file!(String.t(), Path.t(), [{String.t(), String.t()}]) ::
%HTTPoison.Response{}
@callback post!(String.t(), binary(), [{String.t(), String.t()}]) ::
%HTTPoison.Response{}
@callback get!(String.t(), [{String.t(), String.t()}]) ::
%HTTPoison.Response{}
@callback get(String.t(), [{String.t(), String.t()}]) ::
{:ok, %HTTPoison.Response{}} | {:error, any()}
end
@behaviour __MODULE__.Behaviour
# side effects like
# - http reqs
# - reading envs from the system
# - reading from git
# - file operations
# read the tag from `git`
@impl true
def get_tag do
{tag_string, 0} = System.cmd("git", ["describe", "--tags"])
String.trim(tag_string)
end
# given an app name, get the name of the release artifact
@impl true
def release_files(app, tag, build_path) do
[build_path, "rel", "#{app}", "releases", "#{tag}*", "#{app}.tar.gz"]
|> Path.join()
|> Path.wildcard()
end
@impl true
def build_path, do: Project.build_path()
# read the api token either from System.get_env or from the token file
@impl true
def read_api_token do
token_file =
:duckduck
|> Application.get_env(:token_file, "~/.goose_api_token")
|> Path.expand()
with :error <- Application.fetch_env(:duckduck, :api_token),
false <- File.exists?(token_file) do
DuckDuck.puts_failure(@no_api_token_msg)
System.halt(1)
else
{:ok, api_token} ->
api_token
true ->
token_file
|> File.read!()
|> String.trim()
end
end
@impl true
def start_http_client do
{:ok, _all} = Application.ensure_all_started(:httpoison)
:ok
end
@impl true
def post_file!(url, path, headers) do
HTTPoison.post!(url, {:file, path}, headers,
timeout: :infinity,
recv_timeout: :infinity
)
end
@impl true
def post!(url, body, headers), do: HTTPoison.post!(url, body, headers)
@impl true
def get!(url, headers), do: HTTPoison.get!(url, headers)
@impl true
def get(url, headers), do: HTTPoison.get(url, headers)
end