hooks: alint: add fixup_cmd when alint exits with codes (5, 6)

Bug: 494210418
Change-Id: I348d65f25841364c28f7879e9d28f63a6c2b046c
Reviewed-on: https://gerrit-review.googlesource.com/c/git-repohooks/+/564464
Reviewed-by: Alibek Manabayev <minmax@google.com>
Reviewed-by: Lauren Minchin <lminchin@google.com>
Tested-by: Marty Heavey <mheavey@google.com>
Reviewed-by: Mike Frysinger <vapier@google.com>
Commit-Queue: Marty Heavey <mheavey@google.com>
diff --git a/rh/hooks.py b/rh/hooks.py
index 538d6b0..b41c3ca 100644
--- a/rh/hooks.py
+++ b/rh/hooks.py
@@ -1300,7 +1300,20 @@
 
     cmd = [alint_path] + options.args((), diff) + ["--commit", commit]
 
-    return _check_cmd("alint", project, commit, cmd)
+    result = _run(cmd)
+
+    # alint returns exit code 5 or 6 if there are findings with fixes available.
+    fixup_cmd = (
+        [alint_path, "fix", "--no_amend"]
+        if result.returncode in (5, 6)
+        else None
+    )
+
+    return [
+        rh.results.HookCommandResult(
+            "alint", project, commit, result, fixup_cmd=fixup_cmd
+        )
+    ]
 
 
 # Hooks that projects can opt into.
diff --git a/rh/hooks_unittest.py b/rh/hooks_unittest.py
index 8f982f5..bbc8f95 100755
--- a/rh/hooks_unittest.py
+++ b/rh/hooks_unittest.py
@@ -364,6 +364,12 @@
     def setUp(self):
         self.project = rh.Project(name="project-name", dir="/.../repo/dir")
         self.options = rh.hooks.HookOptions("hook name", [], {})
+        mock.patch.object(
+            rh.git, "find_repo_root", side_effect=mock_find_repo_root
+        ).start()
+
+    def tearDown(self):
+        mock.patch.stopall()
 
     def _test_commit_messages(self, func, accept, msgs, files=None):
         """Helper for testing commit message hooks.
@@ -1183,10 +1189,44 @@
         Test: ...
         Flag: ..."""
         diff = [rh.git.RawDiffEntry(file="file.txt", status="A")]
+
+        # Test success.
+        mock_run.return_value = rh.utils.CompletedProcess(returncode=0)
         ret = rh.hooks.check_alint(
             self.project, commit, "desc", diff, options=self.options
         )
         self.assertIsNotNone(ret)
+        self.assertIsNone(ret[0].fixup_cmd)
+
+        # Test error with fix.
+        mock_run.return_value = rh.utils.CompletedProcess(returncode=5)
+        ret = rh.hooks.check_alint(
+            self.project, commit, "desc", diff, options=self.options
+        )
+        self.assertIsNotNone(ret)
+        self.assertEqual(ret[0].fixup_cmd, ["alint", "fix", "--no_amend"])
+        self.assertFalse(ret[0].is_warning())
+        self.assertEqual(ret[0].result.returncode, 5)
+
+        # Test warning with fix.
+        mock_run.return_value = rh.utils.CompletedProcess(returncode=6)
+        ret = rh.hooks.check_alint(
+            self.project, commit, "desc", diff, options=self.options
+        )
+        self.assertIsNotNone(ret)
+        self.assertEqual(ret[0].fixup_cmd, ["alint", "fix", "--no_amend"])
+        self.assertFalse(ret[0].is_warning())
+        self.assertEqual(ret[0].result.returncode, 6)
+
+        # Test warning without fix.
+        mock_run.return_value = rh.utils.CompletedProcess(returncode=77)
+        ret = rh.hooks.check_alint(
+            self.project, commit, "desc", diff, options=self.options
+        )
+        self.assertIsNotNone(ret)
+        self.assertIsNone(ret[0].fixup_cmd)
+        self.assertTrue(ret[0].is_warning())
+        self.assertEqual(ret[0].result.returncode, 77)
 
 
 if __name__ == "__main__":