Repository: rrrene/credo (elixir)

Issue:
Proposal - Filter out checks to run by priority too
### Environment

* Credo version (`mix credo -v`): 0.9.1
* Erlang/Elixir version (`elixir -v`): OTP20 / 1.6.4
* Operating system: Ubuntu

### What were you trying to do?

I was trying to run checks based on priorities only. 

### Expected outcome

Be able to filter out the checks to run based on the priorities

### Actual outcome

Can not filter out the checks based on the priorities

### Use Case

While the `--only warning,refactor` does work to filter out the checks based on the type, sometimes it is convenient to be able to run only the checks that have priority higher than certain value such as >= `high`. For example, I want to fail on `PipeChainStart` but not on other readability issues in my CI environment but I still want to gradually fix other pipelines so I can not really disable other checks under readability category.

Something like below:

`mix credo --priority high` -> can run `high` or `higher` checks

Alternatively, we could do:
`mix credo --priority high,higher`

I could not find any relevant docs but I am sorry if I am overlooking certain things

Pull request description:
Add string options for the `--min-priority` switch
Fixes #532

This does 2 things:

1.  It documents the `--min-priority` switch
1.  It adds 5 new possible values to the `--min-priority` (`high`, `medium`, `normal`, `low`, `lower`)

There's one caveat with this PR. It piggies back on the unknown flags handling feature of credo. If the `--min-priority` switch is given a string it can't parse (not one of the values above nor an integer) it'll report that the `--min-priority` switch is unknown. 

This is not great for users but it's consistent with the current behavior of credo. I didn't want to improve the error reporting for non-parsed flags in this PR since it seemed complicated and beyond the scope of the original issue. At least it's not worse than it was before.

Error output from master:

```sh
$ mix credo --min-priority what
Unknown switch: --min-priority
```

Error output from this PR:

```sh
$ mix credo --min-priority what
Unknown switch: --min-priority
```

Patch:
diff --git a/lib/credo/cli/command/list/list_output.ex b/lib/credo/cli/command/list/list_output.ex
index 55fea40b..ec2f084d 100644
--- a/lib/credo/cli/command/list/list_output.ex
+++ b/lib/credo/cli/command/list/list_output.ex
@@ -29,6 +29,7 @@ defmodule Credo.CLI.Command.List.ListOutput do
     List options:
       -a, --all             Show all issues
       -A, --all-priorities  Show all issues including low priority ones
+          --min-priority    Minimum priority to show issues (high,medium,normal,low,lower or number)
       -c, --checks          Only include checks that match the given strings
       -C, --config-name     Use the given config instead of "default"
       -i, --ignore-checks   Ignore checks that match the given strings
diff --git a/lib/credo/cli/command/suggest/suggest_output.ex b/lib/credo/cli/command/suggest/suggest_output.ex
index ad761057..d271cb52 100644
--- a/lib/credo/cli/command/suggest/suggest_output.ex
+++ b/lib/credo/cli/command/suggest/suggest_output.ex
@@ -29,6 +29,7 @@ defmodule Credo.CLI.Command.Suggest.SuggestOutput do
     Suggest options:
       -a, --all             Show all issues
       -A, --all-priorities  Show all issues including low priority ones
+          --min-priority    Minimum priority to show issues (high,medium,normal,low,lower or number)
       -c, --checks          Only include checks that match the given strings
       -C, --config-name     Use the given config instead of "default"
       -i, --ignore-checks   Ignore checks that match the given strings
diff --git a/lib/credo/cli/options.ex b/lib/credo/cli/options.ex
index 4126fad2..a2e25278 100644
--- a/lib/credo/cli/options.ex
+++ b/lib/credo/cli/options.ex
@@ -19,7 +19,7 @@ defmodule Credo.CLI.Options do
     help: :boolean,
     ignore_checks: :string,
     ignore: :string,
-    min_priority: :integer,
+    min_priority: :string,
     only: :string,
     read_from_stdin: :boolean,
     strict: :boolean,
@@ -52,15 +52,38 @@ defmodule Credo.CLI.Options do
     args = Enum.reject(args, &Enum.member?(ignored_args, &1))
     {command, path, unknown_args} = split_args(args, current_dir, command_names)
 
+    {switches_keywords, extra_unknown_switches} = patch_switches(switches_keywords)
+
     %__MODULE__{
       command: command,
       path: path,
       args: unknown_args,
       switches: Enum.into(switches_keywords, %{}),
-      unknown_switches: unknown_switches_keywords
+      unknown_switches: unknown_switches_keywords ++ extra_unknown_switches
     }
   end
 
+  defp patch_switches(switches_keywords) do
+    {switches, unknowns} = Enum.map_reduce(switches_keywords, [], &patch_switch/2)
+    switches = Enum.reject(switches, &(&1 == nil))
+    {switches, unknowns}
+  end
+
+  defp patch_switch({:min_priority, "high"}, unknowns), do: {{:min_priority, 20}, unknowns}
+  defp patch_switch({:min_priority, "medium"}, unknowns), do: {{:min_priority, 10}, unknowns}
+  defp patch_switch({:min_priority, "normal"}, unknowns), do: {{:min_priority, 0}, unknowns}
+  defp patch_switch({:min_priority, "low"}, unknowns), do: {{:min_priority, -2}, unknowns}
+  defp patch_switch({:min_priority, "lower"}, unknowns), do: {{:min_priority, -999}, unknowns}
+
+  defp patch_switch({:min_priority, str}, unknowns) do
+    case Integer.parse(str) do
+      {int, ""} -> {{:min_priority, int}, unknowns}
+      _ -> {nil, [{"--min-priority", str} | unknowns]}
+    end
+  end
+
+  defp patch_switch(switch, unknowns), do: {switch, unknowns}
+
   defp split_args([], current_dir, _) do
     {path, unknown_args} = extract_path([], current_dir)
 


Test patch:
diff --git a/test/credo/cli/options_test.exs b/test/credo/cli/options_test.exs
index 2e191322..d8b0edd1 100644
--- a/test/credo/cli/options_test.exs
+++ b/test/credo/cli/options_test.exs
@@ -38,6 +38,48 @@ defmodule Credo.CLI.OptionsTest do
     assert expected == switches(args)
   end
 
+  test "switches: it should convert min_priority high to 20" do
+    args = String.split("--min-priority=high --version")
+    expected = %{version: true, min_priority: 20}
+    assert expected == switches(args)
+  end
+
+  test "switches: it should convert min_priority medium to 10" do
+    args = String.split("--min-priority=medium --version")
+    expected = %{version: true, min_priority: 10}
+    assert expected == switches(args)
+  end
+
+  test "switches: it should convert min_priority normal to 0" do
+    args = String.split("--min-priority=normal --version")
+    expected = %{version: true, min_priority: 0}
+    assert expected == switches(args)
+  end
+
+  test "switches: it should convert min_priority low to -2" do
+    args = String.split("--min-priority=low --version")
+    expected = %{version: true, min_priority: -2}
+    assert expected == switches(args)
+  end
+
+  test "switches: it should convert min_priority lower to -999" do
+    args = String.split("--min-priority=lower --version")
+    expected = %{version: true, min_priority: -999}
+    assert expected == switches(args)
+  end
+
+  test "switches: it should convert min_priority to integer" do
+    args = String.split("--min-priority=-1234 --version")
+    expected = %{version: true, min_priority: -1234}
+    assert expected == switches(args)
+  end
+
+  test "switches: it should reject float min_priority" do
+    args = String.split("--min-priority=-1234.12 --version")
+    expected = %{version: true}
+    assert expected == switches(args)
+  end
+
   test "command: it should work w/o command" do
     args = String.split("--strict --version")
     options = parse(args)