pre-upload: show all possible fixup commands while running

This allows people to quickly run fixup commands themselves if they
want.  This is helpful as we only offer to run the command if there
is one fixup in the latest commit.

Show these as a summary at the end so hopefully it's a little easier
for users to access if they want to copy & paste the command.

Bug: 274529930
Test: unittests
Change-Id: I75b9c196a5369874fac94e822ec87e72f804cb9a
diff --git a/pre-upload.py b/pre-upload.py
index c539dfd..bdb5b36 100755
--- a/pre-upload.py
+++ b/pre-upload.py
@@ -64,6 +64,7 @@
     PASSED = COLOR.color(COLOR.GREEN, 'PASSED')
     FAILED = COLOR.color(COLOR.RED, 'FAILED')
     WARNING = COLOR.color(COLOR.YELLOW, 'WARNING')
+    FIXUP = COLOR.color(COLOR.MAGENTA, 'FIXUP')
 
     # How long a hook is allowed to run before we warn that it is "too slow".
     _SLOW_HOOK_DURATION = datetime.timedelta(seconds=30)
@@ -175,6 +176,21 @@
         print(error, file=sys.stderr)
         self.success = False
 
+    def hook_fixups(
+        self,
+        project_results: rh.results.ProjectResults,
+        hook_results: List[rh.results.HookResult],
+    ) -> None:
+        """Display summary of possible fixups for a single hook."""
+        for result in (x for x in hook_results if x.fixup_cmd):
+            cmd = result.fixup_cmd + list(result.files)
+            for line in (
+                f'[{self.FIXUP}] {result.hook} has automated fixups available',
+                f'  cd {rh.shell.quote(project_results.workdir)} && \\',
+                f'    {rh.shell.cmd_to_str(cmd)}',
+            ):
+                rh.terminal.print_status_line(line, print_newline=True)
+
     def finish(self):
         """Print summary for all the hooks."""
         header = self.PASSED if self.success else self.FAILED
@@ -391,6 +407,7 @@
                         output.hook_warning(hook, warning)
                     if error is not None:
                         output.hook_error(hook, error)
+                        output.hook_fixups(ret, hook_results)
                 output.hook_finish(hook, duration)
 
     _attempt_fixes(ret, commit_list)