zf

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

first_run_hint.ex (5522B)


      1 defmodule Credo.CLI.Output.FirstRunHint do
      2   alias Credo.CLI.Output
      3   alias Credo.CLI.Output.UI
      4   alias Credo.Execution
      5 
      6   @lots_of_issue_threshold 30
      7   @command_padding 40
      8   @category_count 5
      9 
     10   def call(exec) do
     11     term_width = Output.term_columns()
     12     issues = Execution.get_issues(exec)
     13 
     14     headline = " 8< "
     15     bar = String.pad_leading("", div(term_width - String.length(headline), 2), "-")
     16 
     17     UI.puts()
     18     UI.puts()
     19     UI.puts([:magenta, :bright, "#{bar} 8< #{bar}"])
     20     UI.puts()
     21     UI.puts()
     22 
     23     issue_count = Enum.count(issues)
     24 
     25     readability_issue_count =
     26       issues
     27       |> Enum.filter(&(&1.category == :readability))
     28       |> Enum.count()
     29 
     30     relative_issue_count_per_category = div(issue_count, @category_count)
     31 
     32     mostly_readability_issues =
     33       readability_issue_count >= div(@lots_of_issue_threshold, 2) &&
     34         readability_issue_count > relative_issue_count_per_category * 2
     35 
     36     readability_hint =
     37       if mostly_readability_issues do
     38         [
     39           """
     40 
     41           While not recommended, you could simply start ignoring issues for the time being:
     42 
     43           """,
     44           :cyan,
     45           String.pad_trailing("    mix credo --ignore readability", @command_padding),
     46           :faint,
     47           "# exclude checks matching a given phrase",
     48           "\n",
     49           :reset
     50         ]
     51       else
     52         []
     53       end
     54 
     55     if issue_count >= @lots_of_issue_threshold do
     56       UI.puts([
     57         :reset,
     58         :orange,
     59         """
     60         # Where to start?
     61         """,
     62         :reset,
     63         """
     64 
     65         That's a lot of issues to deal with at once.
     66         """,
     67         readability_hint
     68       ])
     69     else
     70       UI.puts([
     71         :reset,
     72         :orange,
     73         """
     74         # How to introduce Credo
     75         """,
     76         :reset,
     77         """
     78 
     79         This is looking pretty already! You can probably just fix the issues above in one go.
     80 
     81         """,
     82         readability_hint
     83       ])
     84     end
     85 
     86     print_lots_of_issues(exec)
     87 
     88     UI.puts([
     89       :reset,
     90       :orange,
     91       """
     92 
     93       ## Every project is different
     94       """,
     95       :reset,
     96       """
     97 
     98       Introducing code analysis to an existing codebase should not be about following any
     99       "best practice" in particular, it should be about helping you to get to know the ropes
    100       and make the changes you want.
    101 
    102       Try the options outlined above to see which one is working for this project!
    103       """
    104     ])
    105   end
    106 
    107   defp print_lots_of_issues(exec) do
    108     working_dir = Execution.working_dir(exec)
    109     now = now()
    110     default_branch = default_branch(working_dir)
    111     latest_commit_on_default_branch = latest_commit_on_default_branch(working_dir)
    112     latest_tag = latest_tag(working_dir)
    113 
    114     current_branch = current_branch(working_dir)
    115 
    116     if current_branch != default_branch do
    117       UI.puts([
    118         :reset,
    119         """
    120         You can use `diff` to only show the issues that were introduced on this branch:
    121         """,
    122         :cyan,
    123         """
    124 
    125             mix credo diff #{default_branch}
    126 
    127         """
    128       ])
    129     end
    130 
    131     UI.puts([
    132       :reset,
    133       :orange,
    134       """
    135       ## Compare to a point in history
    136       """,
    137       :reset,
    138       """
    139 
    140       Alternatively, you can use `diff` to only show the issues that were introduced after a certain tag or commit:
    141       """
    142     ])
    143 
    144     if latest_tag do
    145       UI.puts([
    146         :cyan,
    147         String.pad_trailing("    mix credo diff #{latest_tag} ", @command_padding),
    148         :faint,
    149         "# use the latest tag",
    150         "\n"
    151       ])
    152     end
    153 
    154     UI.puts([
    155       :reset,
    156       :cyan,
    157       String.pad_trailing(
    158         "    mix credo diff #{latest_commit_on_default_branch}",
    159         @command_padding
    160       ),
    161       :faint,
    162       "# use the current HEAD of #{default_branch}",
    163       "\n\n",
    164       :reset,
    165       """
    166       Lastly, you can compare your working dir against this point in time:
    167 
    168       """,
    169       :cyan,
    170       String.pad_trailing("    mix credo diff --since #{now}", @command_padding),
    171       :faint,
    172       "# use the current date",
    173       "\n"
    174     ])
    175   end
    176 
    177   defp latest_tag(working_dir) do
    178     case System.cmd("git", ~w"rev-list --tags --max-count=1", cd: working_dir) do
    179       {"", 0} ->
    180         nil
    181 
    182       {latest_tag_sha1, 0} ->
    183         case System.cmd("git", ~w"describe --tags #{latest_tag_sha1}", cd: working_dir) do
    184           {tagname, 0} -> String.trim(tagname)
    185           _ -> nil
    186         end
    187 
    188       _ ->
    189         nil
    190     end
    191   end
    192 
    193   defp current_branch(working_dir) do
    194     case System.cmd("git", ~w"rev-parse --abbrev-ref HEAD", cd: working_dir) do
    195       {output, 0} -> String.trim(output)
    196       _ -> nil
    197     end
    198   end
    199 
    200   defp default_branch(working_dir) do
    201     remote_name = default_remote_name(working_dir)
    202 
    203     case System.cmd("git", ~w"symbolic-ref refs/remotes/#{remote_name}/HEAD", cd: working_dir) do
    204       {output, 0} -> ~r"refs/remotes/#{remote_name}/(.+)$" |> Regex.run(output) |> Enum.at(1)
    205       _ -> nil
    206     end
    207   end
    208 
    209   defp default_remote_name(_working_dir) do
    210     "origin"
    211   end
    212 
    213   defp latest_commit_on_default_branch(working_dir) do
    214     case System.cmd(
    215            "git",
    216            ~w"rev-parse --short #{default_remote_name(working_dir)}/#{default_branch(working_dir)}",
    217            cd: working_dir
    218          ) do
    219       {output, 0} -> String.trim(output)
    220       _ -> nil
    221     end
    222   end
    223 
    224   defp now do
    225     %{year: year, month: month, day: day} = DateTime.utc_now()
    226 
    227     "#{year}-#{pad(month)}-#{pad(day)}"
    228   end
    229 
    230   defp pad(number) when number < 10, do: "0#{number}"
    231   defp pad(number), do: to_string(number)
    232 end