Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 19 additions & 8 deletions lib/hex/cooldown.ex
Original file line number Diff line number Diff line change
Expand Up @@ -187,30 +187,41 @@ defmodule Hex.Cooldown do
nil

entries ->
today = Date.utc_today()

lines =
entries
|> Enum.group_by(fn {repo, pkg, _vsn, _} -> {repo, pkg} end)
|> Enum.sort()
|> Enum.flat_map(fn {_key, entries} -> package_lines(entries, cutoff, today) end)
|> Enum.flat_map(fn {_key, entries} -> package_lines(entries, cutoff) end)

"\nVersions filtered by cooldown:\n" <> Enum.join(lines, "\n") <> "\n"
iodata = ["\nVersions filtered by cooldown:\n", Enum.intersperse(lines, "\n"), "\n"]
IO.chardata_to_string(Hex.Shell.format(iodata))
end
end

defp package_lines(entries, cutoff, today) do
defp package_lines(entries, cutoff) do
{listed, rest} =
entries
|> Enum.sort_by(fn {_repo, _pkg, vsn, _} -> Version.parse!(vsn) end, {:desc, Version})
|> Enum.split(@versions_listed_per_package)

lines =
Enum.map(listed, fn {_repo, pkg, vsn, published_at} ->
published_date = published_at |> DateTime.from_unix!() |> DateTime.to_date()
days_ago = Date.diff(today, published_date)
eligible_date = eligible_on(published_at, cutoff)
" #{pkg} #{vsn} — published #{days_ago} days ago, eligible #{eligible_date}"

[
" ",
:bright,
pkg,
:reset,
" ",
:yellow,
vsn,
:reset,
" — eligible ",
:cyan,
to_string(eligible_date),
:reset
]
end)

case rest do
Expand Down
10 changes: 10 additions & 0 deletions lib/hex/policy/diagnostics.ex
Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,16 @@ defmodule Hex.Policy.Diagnostics do

def format_reason(other), do: inspect(other)

@doc """
Maps a blocker reason to an ANSI color used to highlight it in output.
"""
@spec reason_color(term()) :: atom()
def reason_color({:advisory, _}), do: :red
def reason_color({:retirement, _}), do: :yellow
def reason_color({:cooldown, _, _}), do: :cyan
def reason_color(:override_deny), do: :red
def reason_color(_other), do: :reset

defp count(1, noun), do: "1 #{noun}"
defp count(n, noun), do: "#{n} #{noun}s"
end
67 changes: 39 additions & 28 deletions lib/mix/tasks/hex.policy.ex
Original file line number Diff line number Diff line change
Expand Up @@ -93,9 +93,13 @@ defmodule Mix.Tasks.Hex.Policy do
end

defp render_show(policy) do
Hex.Shell.info(
"Active policy: #{policy.repository}/#{policy.name} [#{visibility_label(policy.visibility)}]\n"
)
Hex.Shell.info([
"Active policy: ",
[:cyan, "#{policy.repository}/#{policy.name}"],
" ",
visibility_tag(policy.visibility),
"\n"
])

render_repositories(policy)
Hex.Shell.info("")
Expand All @@ -107,7 +111,11 @@ defmodule Mix.Tasks.Hex.Policy do
:ok

{source, duration} ->
Hex.Shell.info("Effective cooldown: #{duration} (#{cooldown_source(source)})")
Hex.Shell.info([
"Effective cooldown: ",
[:cyan, duration],
" (#{cooldown_source(source)})"
])
end
end

Expand All @@ -125,11 +133,11 @@ defmodule Mix.Tasks.Hex.Policy do
restriction = Map.get(rp, :restriction)
overrides = Map.get(rp, :overrides, [])

Hex.Shell.info(" #{rp.repository}:")
Hex.Shell.info(" Cooldown: #{cooldown_label(restriction)}")
Hex.Shell.info(" Advisory rule: #{advisory_label(restriction)}")
Hex.Shell.info(" Retirement rule: #{retirement_label(restriction)}")
Hex.Shell.info(" Overrides: #{length(overrides)}")
Hex.Shell.info([" ", [:bright, "#{rp.repository}:"]])
Hex.Shell.info([" Cooldown: ", cooldown_label(restriction)])
Hex.Shell.info([" Advisory rule: ", advisory_label(restriction)])
Hex.Shell.info([" Retirement rule: ", retirement_label(restriction)])
Hex.Shell.info([" Overrides: ", to_string(length(overrides))])
end

defp why(arg) do
Expand Down Expand Up @@ -177,16 +185,16 @@ defmodule Mix.Tasks.Hex.Policy do

case Filter.classify(policy, candidate) do
:allowed ->
[version, "ALLOWED", ""]
[version, [:green, "ALLOWED"], ""]

{:blocked, reasons} ->
reason_text =
reason_cell =
reasons
|> Enum.map(&Diagnostics.format_reason/1)
|> Enum.uniq()
|> Enum.join(", ")
|> Enum.map(&[Diagnostics.reason_color(&1), Diagnostics.format_reason(&1)])
|> Enum.intersperse(", ")

[version, "BLOCKED", reason_text]
[version, [:red, "BLOCKED"], reason_cell]
end
end)

Expand All @@ -196,27 +204,30 @@ defmodule Mix.Tasks.Hex.Policy do
defp cooldown_source(:local), do: "local"
defp cooldown_source({repo, name}), do: "#{repo}/#{name}"

defp visibility_label(:VISIBILITY_PUBLIC), do: "public"
defp visibility_label(:VISIBILITY_PRIVATE), do: "private"
defp visibility_label(other), do: to_string(other)
defp visibility_tag(:VISIBILITY_PUBLIC), do: [:green, "[public]"]
defp visibility_tag(:VISIBILITY_PRIVATE), do: [:yellow, "[private]"]
defp visibility_tag(other), do: ["[", to_string(other), "]"]

defp cooldown_label(%{cooldown: duration}) when is_binary(duration), do: duration
defp cooldown_label(_restriction), do: "(none)"
defp cooldown_label(%{cooldown: duration}) when is_binary(duration), do: [:cyan, duration]
defp cooldown_label(_restriction), do: [:faint, "(none)"]

defp advisory_label(%{advisory_min_severity: :SEVERITY_NONE}), do: "block any advisory"
defp advisory_label(%{advisory_min_severity: :SEVERITY_NONE}), do: [:red, "block any advisory"]

defp advisory_label(%{advisory_min_severity: severity}) when not is_nil(severity),
do: "block ≥ #{Hex.Utils.advisory_severity(severity)}"
do: [:red, "block ≥ #{Hex.Utils.advisory_severity(severity)}"]

defp advisory_label(_restriction), do: "(disabled)"
defp advisory_label(_restriction), do: [:faint, "(disabled)"]

defp retirement_label(%{retirement_reasons: reasons}) when is_list(reasons) and reasons != [] do
reasons
|> Enum.map(fn r ->
r |> Hex.Utils.package_retirement_reason() |> String.upcase()
end)
|> Enum.join(", ")
text =
reasons
|> Enum.map(fn r ->
r |> Hex.Utils.package_retirement_reason() |> String.upcase()
end)
|> Enum.join(", ")

[:yellow, text]
end

defp retirement_label(_restriction), do: "(disabled)"
defp retirement_label(_restriction), do: [:faint, "(disabled)"]
end
1 change: 0 additions & 1 deletion test/hex/cooldown_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -298,7 +298,6 @@ defmodule Hex.CooldownTest do

assert summary =~ "Versions filtered by cooldown:"
assert summary =~ "castore 1.0.19"
assert summary =~ "3 days ago"
assert summary =~ "eligible #{Cooldown.eligible_on(published_at, cutoff)}"
end

Expand Down
Loading