Repository: sscpac/statick

Issue:
Support level flag
Right now a new profile file has to be created to specify the desired level to run Statick. We should add support for setting a `--level` flag that overrides the level specified in the profile file.

Discussion:

Patch:
diff --git a/statick_tool/plugins/tool/cccc_tool_plugin.py b/statick_tool/plugins/tool/cccc_tool_plugin.py
index 67b57aa..be3192e 100644
--- a/statick_tool/plugins/tool/cccc_tool_plugin.py
+++ b/statick_tool/plugins/tool/cccc_tool_plugin.py
@@ -193,7 +193,7 @@ class CCCCToolPlugin(ToolPlugin):
                     config[row[".ADA"]] = {
                         "warn": row["ada.95"],
                         "error": row[""],
-                        "name": row[None][3],  # type: ignore
+                        "name": row[None][3],
                         "key": row[".ADA"],
                     }
 
diff --git a/statick_tool/statick.py b/statick_tool/statick.py
index 14e31d6..dedf01e 100644
--- a/statick_tool/statick.py
+++ b/statick_tool/statick.py
@@ -151,6 +151,13 @@ class Statick:
         args.add_argument(
             "--config", dest="config", type=str, help="Name of config yaml file"
         )
+        args.add_argument(
+            "--level",
+            dest="level",
+            type=str,
+            help="Scan level to use from config file. \
+                  Overrides any levels specified by the profile.",
+        )
         args.add_argument(
             "--profile", dest="profile", type=str, help="Name of profile yaml file"
         )
@@ -219,6 +226,9 @@ class Statick:
         """Get level to scan package at."""
         path = os.path.abspath(path)
 
+        if args.level is not None:
+            return str(args.level)
+
         profile_filename = "profile.yaml"
         if args.profile is not None:
             profile_filename = args.profile


Test patch:
diff --git a/tests/statick/test_statick.py b/tests/statick/test_statick.py
index 178c359..9548e5c 100644
--- a/tests/statick/test_statick.py
+++ b/tests/statick/test_statick.py
@@ -92,6 +92,7 @@ def test_get_level(init_statick):
     args.parser.add_argument(
         "--profile", dest="profile", type=str, default="profile-test.yaml"
     )
+    args.parser.add_argument("--level", dest="level", type=str)
     level = init_statick.get_level("some_package", args.get_args([]))
     assert level == "default_value"
 
@@ -106,10 +107,30 @@ def test_get_level_non_default(init_statick):
     args.parser.add_argument(
         "--profile", dest="profile", type=str, default="profile-test.yaml"
     )
+    args.parser.add_argument("--level", dest="level", type=str)
     level = init_statick.get_level("package", args.get_args([]))
     assert level == "package_specific"
 
 
+def test_get_level_cli(init_statick):
+    """
+    Test searching for a level when a level was specified on the command line.
+
+    Expected result: Some level is returned
+    """
+    args = Args("Statick tool")
+    args.parser.add_argument(
+        "--profile", dest="profile", type=str, default="profile-test.yaml"
+    )
+    args.parser.add_argument(
+        "--level", dest="level", type=str, default="custom"
+    )
+    level = init_statick.get_level("package", args.get_args([]))
+    assert level == "custom"
+    level = init_statick.get_level("package_specific", args.get_args([]))
+    assert level == "custom"
+
+
 def test_get_level_nonexistent_file(init_statick):
     """
     Test searching for a level which doesn't have a corresponding file.
@@ -120,6 +141,7 @@ def test_get_level_nonexistent_file(init_statick):
     args.parser.add_argument(
         "--profile", dest="profile", type=str, default="nonexistent.yaml"
     )
+    args.parser.add_argument("--level", dest="level", type=str)
     level = init_statick.get_level("some_package", args.get_args([]))
     assert level is None
 
@@ -136,6 +158,20 @@ def test_get_level_ioerror(mocked_profile_constructor, init_statick):
     args.parser.add_argument(
         "--profile", dest="profile", type=str, default="profile-test.yaml"
     )
+    args.parser.add_argument("--level", dest="level", type=str)
+    level = init_statick.get_level("some_package", args.get_args([]))
+    assert level is None
+
+
+@mock.patch("statick_tool.statick.Profile")
+def test_get_level_valueerror(mocked_profile_constructor, init_statick):
+    """Test the behavior when Profile throws a ValueError."""
+    mocked_profile_constructor.side_effect = ValueError("error")
+    args = Args("Statick tool")
+    args.parser.add_argument(
+        "--profile", dest="profile", type=str, default="profile-test.yaml"
+    )
+    args.parser.add_argument("--level", dest="level", type=str)
     level = init_statick.get_level("some_package", args.get_args([]))
     assert level is None
 
@@ -180,18 +216,6 @@ def test_custom_config_file(init_statick):
     assert has_level
 
 
-@mock.patch("statick_tool.statick.Profile")
-def test_get_level_valueerror(mocked_profile_constructor, init_statick):
-    """Test the behavior when Profile throws a ValueError."""
-    mocked_profile_constructor.side_effect = ValueError("error")
-    args = Args("Statick tool")
-    args.parser.add_argument(
-        "--profile", dest="profile", type=str, default="profile-test.yaml"
-    )
-    level = init_statick.get_level("some_package", args.get_args([]))
-    assert level is None
-
-
 @mock.patch("statick_tool.statick.Config")
 def test_get_config_valueerror(mocked_config_constructor, init_statick):
     """Test the behavior when Config throws a ValueError."""