auto_abandon_cls: include internal CLs

BUG=b:335019675
TEST=Ran with --dry-run

Change-Id: I2e78f31e8b22f8ae318e55037c7a680b059ac869
Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/third_party/toolchain-utils/+/5458261
Tested-by: George Burgess <gbiv@chromium.org>
Reviewed-by: Jordan Abrahams-Whitehead <ajordanr@google.com>
Commit-Queue: George Burgess <gbiv@chromium.org>
diff --git a/auto_abandon_cls.py b/auto_abandon_cls.py
index d210c08..ae78bfa 100755
--- a/auto_abandon_cls.py
+++ b/auto_abandon_cls.py
@@ -16,10 +16,18 @@
 from typing import List
 
 
-def enumerate_old_cls(old_days: int) -> List[int]:
+def gerrit_cmd(internal: bool) -> List[str]:
+    cmd = ["gerrit"]
+    if internal:
+        cmd.append("--internal")
+    return cmd
+
+
+def enumerate_old_cls(old_days: int, internal: bool) -> List[int]:
     """Returns CL numbers that haven't been updated in `old_days` days."""
     stdout = subprocess.run(
-        ["gerrit", "--raw", "search", f"owner:me status:open age:{old_days}d"],
+        gerrit_cmd(internal)
+        + ["--raw", "search", f"owner:me status:open age:{old_days}d"],
         check=True,
         stdin=subprocess.DEVNULL,
         stdout=subprocess.PIPE,
@@ -27,17 +35,42 @@
     ).stdout
     # Sort for prettier output; it's unclear if Gerrit always sorts, and it's
     # cheap.
-    return sorted(int(x) for x in stdout.splitlines())
+    lines = stdout.splitlines()
+    if internal:
+        # These are printed as `chrome-internal:NNNN`, rather than `NNNN`.
+        chrome_internal_prefix = "chrome-internal:"
+        assert all(x.startswith(chrome_internal_prefix) for x in lines), lines
+        lines = [x[len(chrome_internal_prefix) :] for x in lines]
+    return sorted(int(x) for x in lines)
 
 
-def abandon_cls(cls: List[int]) -> None:
+def abandon_cls(cls: List[int], internal: bool) -> None:
     subprocess.run(
-        ["gerrit", "abandon"] + [str(x) for x in cls],
+        gerrit_cmd(internal) + ["abandon"] + [str(x) for x in cls],
         check=True,
         stdin=subprocess.DEVNULL,
     )
 
 
+def detect_and_abandon_cls(
+    old_days: int, dry_run: bool, internal: bool
+) -> None:
+    old_cls = enumerate_old_cls(old_days, internal)
+    if not old_cls:
+        logging.info("No CLs less than %d days old found; quit", old_days)
+        return
+
+    cl_namespace = "i" if internal else "c"
+    logging.info(
+        "Abandoning CLs: %s", [f"crrev.com/{cl_namespace}/{x}" for x in old_cls]
+    )
+    if dry_run:
+        logging.info("--dry-run specified; skip the actual abandon part")
+        return
+
+    abandon_cls(old_cls, internal)
+
+
 def main(argv: List[str]) -> None:
     logging.basicConfig(
         format=">> %(asctime)s: %(levelname)s: %(filename)s:%(lineno)d: "
@@ -65,17 +98,18 @@
     )
     opts = parser.parse_args(argv)
 
-    old_cls = enumerate_old_cls(opts.old_days)
-    if not old_cls:
-        logging.info("No CLs less than %d days old found; quit", opts.old_days)
-        return
-
-    logging.info("Abandoning CLs: %s", [f"crrev.com/c/{x}" for x in old_cls])
-    if opts.dry_run:
-        logging.info("--dry-run specified; skip the actual abandon part")
-        return
-
-    abandon_cls(old_cls)
+    logging.info("Checking for external CLs...")
+    detect_and_abandon_cls(
+        old_days=opts.old_days,
+        dry_run=opts.dry_run,
+        internal=False,
+    )
+    logging.info("Checking for internal CLs...")
+    detect_and_abandon_cls(
+        old_days=opts.old_days,
+        dry_run=opts.dry_run,
+        internal=True,
+    )
 
 
 if __name__ == "__main__":