Packages
github_issues
0.4.39
0.4.71
0.4.70
0.4.69
0.4.68
0.4.66
0.4.65
0.4.64
0.4.63
0.4.62
0.4.61
0.4.60
0.4.59
0.4.58
0.4.56
0.4.55
0.4.54
0.4.53
0.4.52
0.4.51
0.4.50
0.4.48
0.4.47
0.4.46
0.4.45
0.4.44
0.4.43
0.4.42
0.4.41
0.4.40
0.4.39
0.4.38
0.4.37
0.4.36
0.4.35
0.4.34
0.4.33
0.4.32
0.4.31
0.4.30
0.4.29
0.4.28
0.4.27
0.4.26
0.4.25
0.4.24
0.4.23
0.4.22
0.4.21
0.4.20
0.4.19
0.4.18
0.4.17
0.4.16
0.4.15
0.4.14
0.4.13
0.4.12
0.4.11
0.4.10
0.4.9
0.4.7
0.4.6
0.4.5
0.4.4
0.4.3
0.4.2
0.4.1
0.4.0
0.3.24
0.3.23
0.3.22
0.3.21
0.3.20
0.3.19
0.3.18
0.3.17
0.3.16
0.3.15
0.3.14
0.3.13
0.3.12
0.3.11
0.3.10
0.3.9
0.3.8
0.3.7
0.3.6
0.3.5
0.3.4
0.3.3
0.3.2
0.3.0
0.2.5
0.2.3
0.2.2
0.2.0
0.1.10
0.1.9
0.1.8
0.1.7
0.1.6
0.1.4
0.1.2
0.1.1
0.1.0
Writes GitHub Issues to "stdio" in a table with borders and colors.
Current section
Files
Jump to
Current section
Files
lib/github/issues/cli.ex
# ┌───────────────────────────────────────────────────────────┐
# │ Inspired by the book "Programming Elixir" by Dave Thomas. │
# └───────────────────────────────────────────────────────────┘
defmodule GitHub.Issues.CLI do
@moduledoc """
Parses the command line and prints a table of the first or last _n_ issues
of a GitHub project.
##### Inspired by the book [Programming Elixir](https://pragprog.com/book/elixir16/programming-elixir-1-6) by Dave Thomas.
"""
use PersistConfig
alias GitHub.Issues
alias GitHub.Issues.{Help, Log}
alias IO.ANSI.Table
alias IO.ANSI.Table.Style
@aliases get_env(:aliases)
@count get_env(:default_count)
@strict get_env(:strict)
@switches get_env(:default_switches)
@table_spec get_env(:table_spec)
@type bell :: boolean
@type count :: pos_integer
@type parsed :: {user, project, count, bell, Style.t()} | :help
@type project :: String.t()
@type user :: String.t()
@doc """
Parses the command line and prints a table of the first or last _n_ issues
of a GitHub `project`.
`argv` can be "-h" or "--help", which prints info on the command's
usage and syntax. Otherwise it contains a `user`, a `project`, and
optionally the number of issues to format (the first _n_ ones).
To format the last _n_ issues, specify switch `--last`.
To ring the bell, specify switch `--bell`.
To choose a table style, specify switch `--table-style`.
## Parameters
- `argv` - command line arguments (list)
## Switches
- `-h` or `--help` - for help
- `-l` or `--last` - to format the last _n_ issues
- `-b` or `--bell` - to ring the bell
- `-t` or `--table-style` - to choose a table style
## Table styles
#{Style.texts("\s\s- `&arg`&filler - ¬e\n")}
"""
@spec main(OptionParser.argv()) :: :ok | no_return
def main(argv) do
case parse(argv) do
{user, project, count, bell, style} ->
case Issues.fetch(user, project) do
{:ok, issues} ->
:ok = printing(user, project) |> IO.ANSI.format() |> IO.puts()
:ok = Log.info(:printing, {user, project, __ENV__})
options = [count: count, bell: bell, style: style]
:ok = Table.write(issues, @table_spec, options)
{:error, text} ->
:ok = error(user, project, text) |> IO.ANSI.format() |> IO.puts()
:ok = Log.error(:fetching, {text, user, project})
System.stop(1)
end
:help ->
:ok = Help.show_help()
System.stop(0)
end
end
## Private functions
@spec printing(user, project) :: IO.ANSI.ansilist()
defp printing(user, project) do
[
@table_spec.left_margin,
[:light_green, "Printing issues from GitHub "],
[:italic, "#{user}/#{project}..."]
]
end
@spec error(user, project, String.t()) :: IO.ANSI.ansilist()
defp error(user, project, text) do
[
[:light_green, "Error fetching issues from GitHub "],
[:italic, "#{user}/#{project}...\n"],
[:light_yellow, text]
]
end
# @doc """
# Parses `argv` (command line arguments). Returns either
# a tuple of `{user, project, count, bell, table_style}` or `:help`.
# ## Examples
# iex> alias GitHub.Issues.CLI
# iex> CLI.parse(["-h"])
# :help
# iex> alias GitHub.Issues.CLI
# iex> CLI.parse(["user", "project", "99"])
# {"user", "project", 99, false, :medium}
# iex> alias GitHub.Issues.CLI
# iex> CLI.parse(["user", "project", "88", "--last", "--bell"])
# {"user", "project", -88, true, :medium}
# iex> alias GitHub.Issues.CLI
# iex> CLI.parse(["user", "project", "6", "--table-style", "dark"])
# {"user", "project", 6, false, :dark}
# iex> alias GitHub.Issues.CLI
# iex> CLI.parse(["user", "project", "6", "-blt", "dark-alt"])
# {"user", "project", -6, true, :dark_alt}
# iex> alias GitHub.Issues.CLI
# iex> CLI.parse(["user", "project", "0", "--table-style", "dark"])
# :help
# """
@spec parse(OptionParser.argv()) :: parsed
defp parse(argv) do
argv
|> OptionParser.parse(strict: @strict, aliases: @aliases)
|> to_parsed()
end
# @doc """
# Converts the output of `OptionParser.parse/2` into `parsed`.
# ## Examples
# iex> alias GitHub.Issues.CLI
# iex> CLI.to_parsed({[help: true], [], []})
# :help
# iex> alias GitHub.Issues.CLI
# iex> CLI.to_parsed({[help: true], ["anything"], []})
# :help
# iex> alias GitHub.Issues.CLI
# iex> CLI.to_parsed({[], ["user", "project", "13"], []})
# {"user", "project", 13, false, :medium}
# iex> alias GitHub.Issues.CLI
# iex> CLI.to_parsed({[], ["user", "project"], []})
# {"user", "project", 9, false, :medium}
# iex> alias GitHub.Issues.CLI
# iex> CLI.to_parsed({
# ...> [last: true, bell: true, table_style: "dark-alt"],
# ...> ["user", "project", "13"],
# ...> []
# ...> })
# {"user", "project", -13, true, :dark_alt}
# """
@spec to_parsed(
{OptionParser.parsed(), OptionParser.argv(), OptionParser.errors()}
) :: parsed
defp to_parsed({switches, args, []}) do
with {user, project, count} <- to_tuple(args),
%{help: false, last: last, bell: bell, table_style: table_style} <-
Map.merge(Map.new(@switches), Map.new(switches)),
{:ok, style} <- Style.from_switch_arg(table_style),
do: {user, project, (last && -count) || count, bell, style},
else: (_ -> :help)
end
defp to_parsed(_), do: :help
# @doc """
# Converts `args` into a tuple or `:error`.
# ## Examples
# iex> alias GitHub.Issues.CLI
# iex> CLI.to_tuple(["user", "project", "7"])
# {"user", "project", 7}
# iex> alias GitHub.Issues.CLI
# iex> CLI.to_tuple(["user", "project", "0"])
# :error
# iex> alias GitHub.Issues.CLI
# iex> CLI.to_tuple([])
# :error
# iex> alias GitHub.Issues.CLI
# iex> CLI.to_tuple(["user", "project"])
# {"user", "project", 9}
# """
@spec to_tuple(OptionParser.argv()) :: {user, project, pos_integer} | :error
defp to_tuple([user, project, count] = _args) do
with {int, ""} when int > 0 <- Integer.parse(count),
do: {user, project, int},
else: (_ -> :error)
end
defp to_tuple([user, project] = _args), do: {user, project, @count}
defp to_tuple(_), do: :error
end