ec013b7cd85204640ee339dd860b6c819c912bf0
lrnassar
  Mon Mar 16 09:31:08 2026 -0700
More feedback from CR.

diff --git src/utils/redmineCli src/utils/redmineCli
index 986f4d5ff5a..fd724fc43ab 100755
--- src/utils/redmineCli
+++ src/utils/redmineCli
@@ -217,44 +217,44 @@
 
 # ---------------------------------------------------------------------------
 # Subcommand: show
 # ---------------------------------------------------------------------------
 
 def cmd_show(args):
     """Display a single ticket in Markdown."""
     data = api_get(args.base_url,
                    f"/issues/{args.ticket_id}.json?include=journals,attachments",
                    args.api_key)
     issue = data["issue"]
 
     attachments = {a["id"]: a for a in issue.get("attachments", [])}
     attach_by_name = {a["filename"]: a for a in issue.get("attachments", [])}
 
-    img_dir = None
-    if args.images:
-        img_dir = tempfile.mkdtemp(prefix=f"redmine_{args.ticket_id}_")
-        print(f"<!-- Images downloaded to: {img_dir} -->", file=sys.stderr)
+    dl_dir = None
+    if args.images or args.download_all:
+        dl_dir = tempfile.mkdtemp(prefix=f"redmine_{args.ticket_id}_")
+        print(f"<!-- Attachments downloaded to: {dl_dir} -->", file=sys.stderr)
 
     def resolve_images(text):
         if not text:
             return text
         def replace_img(m):
             fname = m.group(1)
             if fname in attach_by_name:
                 a = attach_by_name[fname]
-                if img_dir:
-                    local = os.path.join(img_dir, fname)
+                if dl_dir:
+                    local = os.path.join(dl_dir, fname)
                     if not os.path.exists(local):
                         download_file(a["content_url"], local, args.api_key)
                         print(f"  Downloaded: {local}", file=sys.stderr)
                     return f"![image]({local})"
                 else:
                     return f"![image]({a['content_url']})"
             return m.group(0)
         return re.sub(r'!\[image\]\(([^)]+\.(png|jpg|jpeg|gif))\)',
                        replace_img, text, flags=re.IGNORECASE)
 
     out = []
     out.append(f"# #{issue['id']}: {issue['subject']}")
     out.append("")
     out.append(f"- **Project:** {issue['project']['name']}")
     out.append(f"- **Tracker:** {issue['tracker']['name']}")
@@ -307,34 +307,35 @@
         out.append(f"### {user} — {date}")
         out.append("")
         if details:
             detail_text = format_details(details)
             if detail_text:
                 out.append(detail_text)
                 out.append("")
         if notes:
             md_notes = redmine_textile_to_md(notes)
             md_notes = resolve_images(md_notes)
             out.append(md_notes)
             out.append("")
         out.append("---")
         out.append("")
 
-    if img_dir:
+    if dl_dir:
         for a in issue["attachments"]:
-            if a.get("content_type", "").startswith("image/"):
-                local = os.path.join(img_dir, a["filename"])
+            is_image = a.get("content_type", "").startswith("image/")
+            if args.download_all or is_image:
+                local = os.path.join(dl_dir, a["filename"])
                 if not os.path.exists(local):
                     download_file(a["content_url"], local, args.api_key)
                     print(f"  Downloaded: {local}", file=sys.stderr)
 
     print("\n".join(out))
 
 
 def download_file(url, dest_path, api_key):
     """Download a file with API key auth."""
     req = urllib.request.Request(url)
     req.add_header("X-Redmine-API-Key", api_key)
     with urllib.request.urlopen(req, timeout=30) as resp:
         with open(dest_path, "wb") as f:
             f.write(resp.read())
 
@@ -533,34 +534,36 @@
 # Argument parsing
 # ---------------------------------------------------------------------------
 
 def build_parser():
     parser = argparse.ArgumentParser(
         prog="redmineCli",
         description="Redmine CLI for the UCSC Genome Browser team")
     parser.add_argument("--redmine", default=DEFAULT_REDMINE,
                         help="Redmine base URL (default: %(default)s)")
     parser.add_argument("--conf", default="~/.hg.conf",
                         help="Config file with redmine.apiKey (default: %(default)s)")
 
     sub = parser.add_subparsers(dest="command", required=True)
 
     # show
-    p_show = sub.add_parser("show", help="Display a ticket in Markdown")
+    p_show = sub.add_parser("show", help="Display a ticket in Markdown, optionally download attachments")
     p_show.add_argument("ticket_id", help="Ticket ID number")
     p_show.add_argument("--images", action="store_true",
                         help="Download images to a temp directory")
+    p_show.add_argument("--download-all", dest="download_all", action="store_true",
+                        help="Download all attachments to a temp directory")
 
     # list
     p_list = sub.add_parser("list", help="List/search tickets")
     p_list.add_argument("--project", default=DEFAULT_PROJECT,
                         help="Project identifier (default: %(default)s)")
     p_list.add_argument("--status", default="open",
                         help="Status filter: open, closed, * (default: %(default)s)")
     p_list.add_argument("--assigned-to", dest="assigned_to",
                         help="Assignee name or 'me'")
     p_list.add_argument("--tracker",
                         help="Tracker name or ID")
     p_list.add_argument("--search",
                         help="Search in subject")
     p_list.add_argument("--limit", type=int, default=25,
                         help="Max results (default: %(default)s)")