zf

zenflows testing
git clone https://s.sonu.ch/~srfsh/zf.git
Log | Files | Refs | Submodules | README | LICENSE

summary.ex (4694B)


      1 defmodule Credo.CLI.Output.Summary do
      2   @moduledoc false
      3 
      4   # This module is responsible for printing the summary at the end of the analysis.
      5 
      6   @category_wording [
      7     {:consistency, "consistency issue", "consistency issues"},
      8     {:warning, "warning", "warnings"},
      9     {:refactor, "refactoring opportunity", "refactoring opportunities"},
     10     {:readability, "code readability issue", "code readability issues"},
     11     {:design, "software design suggestion", "software design suggestions"}
     12   ]
     13   @cry_for_help "Please report incorrect results: https://github.com/rrrene/credo/issues"
     14 
     15   alias Credo.CLI.Output
     16   alias Credo.CLI.Output.FirstRunHint
     17   alias Credo.CLI.Output.UI
     18   alias Credo.Execution
     19   alias Credo.SourceFile
     20 
     21   def print(
     22         _source_files,
     23         %Execution{format: "flycheck"},
     24         _time_load,
     25         _time_run
     26       ) do
     27     nil
     28   end
     29 
     30   def print(_source_files, %Execution{format: "oneline"}, _time_load, _time_run) do
     31     nil
     32   end
     33 
     34   def print(source_files, exec, time_load, time_run) do
     35     issues = Execution.get_issues(exec)
     36     source_file_count = exec |> Execution.get_source_files() |> Enum.count()
     37     checks_count = count_checks(exec)
     38 
     39     UI.puts()
     40     UI.puts([:faint, @cry_for_help])
     41     UI.puts()
     42     UI.puts([:faint, format_time_spent(checks_count, source_file_count, time_load, time_run)])
     43 
     44     UI.puts(summary_parts(source_files, issues))
     45     UI.puts()
     46 
     47     print_priority_hint(exec)
     48     print_first_run_hint(exec)
     49   end
     50 
     51   defp print_first_run_hint(%Execution{cli_options: %{switches: %{first_run: true}}} = exec) do
     52     FirstRunHint.call(exec)
     53   end
     54 
     55   defp print_first_run_hint(exec), do: exec
     56 
     57   defp count_checks(exec) do
     58     {result, _only_matching, _ignore_matching} = Execution.checks(exec)
     59 
     60     Enum.count(result)
     61   end
     62 
     63   defp print_priority_hint(%Execution{min_priority: min_priority})
     64        when min_priority >= 0 do
     65     UI.puts([
     66       :faint,
     67       "Showing priority issues: ↑ ↗ →  (use `mix credo explain` to explain issues, `mix credo --help` for options)."
     68     ])
     69   end
     70 
     71   defp print_priority_hint(_) do
     72     UI.puts([
     73       :faint,
     74       "Use `mix credo explain` to explain issues, `mix credo --help` for options."
     75     ])
     76   end
     77 
     78   defp format_time_spent(check_count, source_file_count, time_load, time_run) do
     79     time_run = time_run |> div(10_000)
     80     time_load = time_load |> div(10_000)
     81 
     82     formatted_total = format_in_seconds(time_run + time_load)
     83 
     84     time_to_load = format_in_seconds(time_load)
     85     time_to_run = format_in_seconds(time_run)
     86 
     87     total_in_seconds =
     88       case formatted_total do
     89         "1.0" -> "1 second"
     90         value -> "#{value} seconds"
     91       end
     92 
     93     checks =
     94       if check_count == 1 do
     95         "1 check"
     96       else
     97         "#{check_count} checks"
     98       end
     99 
    100     source_files =
    101       if source_file_count == 1 do
    102         "1 file"
    103       else
    104         "#{source_file_count} files"
    105       end
    106 
    107     breakdown = "#{time_to_load}s to load, #{time_to_run}s running #{checks} on #{source_files}"
    108 
    109     "Analysis took #{total_in_seconds} (#{breakdown})"
    110   end
    111 
    112   defp format_in_seconds(t) do
    113     if t < 10 do
    114       "0.0#{t}"
    115     else
    116       t = div(t, 10)
    117       "#{div(t, 10)}.#{rem(t, 10)}"
    118     end
    119   end
    120 
    121   defp category_count(issues, category) do
    122     issues
    123     |> Enum.filter(&(&1.category == category))
    124     |> Enum.count()
    125   end
    126 
    127   defp summary_parts(source_files, issues) do
    128     parts =
    129       @category_wording
    130       |> Enum.flat_map(&summary_part(&1, issues))
    131 
    132     parts =
    133       parts
    134       |> List.update_at(Enum.count(parts) - 1, fn last_part ->
    135         String.replace(last_part, ", ", "")
    136       end)
    137 
    138     parts =
    139       if Enum.empty?(parts) do
    140         "no issues"
    141       else
    142         parts
    143       end
    144 
    145     [
    146       :green,
    147       "#{scope_count(source_files)} mods/funs, ",
    148       :reset,
    149       "found ",
    150       parts,
    151       "."
    152     ]
    153   end
    154 
    155   defp summary_part({category, singular, plural}, issues) do
    156     color = Output.check_color(category)
    157 
    158     case category_count(issues, category) do
    159       0 -> []
    160       1 -> [color, "1 #{singular}, "]
    161       x -> [color, "#{x} #{plural}, "]
    162     end
    163   end
    164 
    165   defp scope_count(%SourceFile{} = source_file) do
    166     Credo.Code.prewalk(source_file, &scope_count_traverse/2, 0)
    167   end
    168 
    169   defp scope_count([]), do: 0
    170 
    171   defp scope_count(source_files) when is_list(source_files) do
    172     source_files
    173     |> Enum.map(&Task.async(fn -> scope_count(&1) end))
    174     |> Enum.map(&Task.await/1)
    175     |> Enum.reduce(&(&1 + &2))
    176   end
    177 
    178   @def_ops [:defmodule, :def, :defp, :defmacro]
    179   for op <- @def_ops do
    180     defp scope_count_traverse({unquote(op), _, _} = ast, count) do
    181       {ast, count + 1}
    182     end
    183   end
    184 
    185   defp scope_count_traverse(ast, count) do
    186     {ast, count}
    187   end
    188 end