a8f76e3fe849a2d1cde06b7f19bd9f4d8fbb81fb braney Tue Aug 11 09:50:19 2026 -0700 redmineCli: watch the code reviewer on build-patch tickets, refs #37281 build-patch added the QA Team and the build meister as watchers, but not the person named in Suggested Code Reviewer. That reviewer has to set Code Review Status to Approved before QA can test, so they are the first person the ticket waits on, and they were the one person not told it existed. The reviewer name is now part of the default watcher list. Dedup is by user ID, so nothing changes when the reviewer is also the build meister, and --no-default-watchers still suppresses all three. Co-Authored-By: Claude Opus 5 (1M context) diff --git src/utils/redmineCli src/utils/redmineCli index fc83f38e107..503b370aa7b 100755 --- src/utils/redmineCli +++ src/utils/redmineCli @@ -662,31 +662,32 @@ print(f"Created #{ticket_id}: {make_url(args.base_url, ticket_id)}") # --------------------------------------------------------------------------- # Subcommand: build-patch # --------------------------------------------------------------------------- def cmd_build_patch(args): """Create a Build Patch ticket with every field the process requires. Encodes the team's Build Patch process so the required fields cannot be forgotten: GB project, Build Patch tracker, Urgent priority, New status, no assignee (QA claims it), and the five required custom fields (Commit ID, Files Changed, CGIs to retest, Test Case, Suggested Code Reviewer). Relates the ticket to the bug it fixes and, unless --no-default-watchers is given, - adds the QA Team and build meister as watchers. + adds the QA Team, the build meister, and the suggested code reviewer as + watchers. """ description = read_text_input(args.description, args.description_file) if not description: sys.exit("Error: --description or --description-file is required") description = strip_emoji(prepend_attribution(description)) custom_fields = [ {"id": CF_DEVELOPER, "value": str(resolve_user(args.developer))}, {"id": CF_COMMIT_ID, "value": args.commit_id}, {"id": CF_FILES_CHANGED, "value": args.files}, {"id": CF_CGIS_RETEST, "value": args.cgis}, {"id": CF_TEST_CASE, "value": args.test_case}, {"id": CF_CODE_REVIEWER, "value": str(resolve_user(args.reviewer))}, ] if args.post_mortem: @@ -711,33 +712,35 @@ print(f"Created Build Patch #{ticket_id}: {make_url(args.base_url, ticket_id)}") # Relate to the bug(s) this patch fixes. for bug_id in (args.relates or []): data = {"relation": {"issue_to_id": int(bug_id), "relation_type": "relates"}} try: api_post(args.base_url, f"/issues/{ticket_id}/relations.json", args.api_key, data) print(f" Related #{ticket_id} <-> #{bug_id}") except SystemExit as e: if "422" in str(e): print(f" Already related: #{ticket_id} <-> #{bug_id}") else: raise - # Watchers: QA Team + build meister by default, plus any extras. The - # process requires QA Team on every Build Patch from the start. - watchers = [] if args.no_default_watchers else ["qa", "build"] + # Watchers: QA Team + build meister + the suggested code reviewer by + # default, plus any extras. The process requires QA Team on every Build + # Patch from the start, and the reviewer has to set Code Review Status + # before QA can test, so they need the notification too. + watchers = [] if args.no_default_watchers else ["qa", "build", args.reviewer] watchers += (args.watch or []) seen = set() for name in watchers: uid = resolve_user(name) if uid in seen: continue seen.add(uid) try: api_post(args.base_url, f"/issues/{ticket_id}/watchers.json", args.api_key, {"user_id": uid}) print(f" Added watcher {name} (user {uid}) to #{ticket_id}") except SystemExit as e: if "422" in str(e): print(f" {name} is already watching #{ticket_id}") else: @@ -1142,42 +1145,42 @@ p_bp.add_argument("--subject", required=True, help="Ticket subject") p_bp.add_argument("--description", help="What is broken and why it needs a patch") p_bp.add_argument("--description-file", dest="description_file", help="Read description from file (- for stdin)") p_bp.add_argument("--developer", required=True, help="Developer who caused the bug (name or user ID)") p_bp.add_argument("--commit-id", dest="commit_id", required=True, help="Fix commit hash; list all hashes if several commits fix it") p_bp.add_argument("--files", required=True, help="Full paths of the source files changed") p_bp.add_argument("--cgis", required=True, help="CGIs that could be affected and need retesting") p_bp.add_argument("--test-case", dest="test_case", required=True, help="Step-by-step to reproduce both the failure and the fix") p_bp.add_argument("--reviewer", required=True, - help="Suggested code reviewer (name or user ID)") + help="Suggested code reviewer (name or user ID); also added as a watcher") p_bp.add_argument("--target-version", dest="target_version", required=True, help="Release number being built (e.g. 500)") p_bp.add_argument("--post-mortem", dest="post_mortem", help="Optional plain-language what-happened / how-to-prevent note") p_bp.add_argument("--relates", nargs="+", metavar="BUG_ID", help="Bug ticket(s) this patch fixes; related on creation") p_bp.add_argument("--watch", nargs="+", metavar="NAME", - help="Extra watchers beyond the QA Team + build meister defaults") + help="Extra watchers beyond the QA Team + build meister + reviewer defaults") p_bp.add_argument("--no-default-watchers", dest="no_default_watchers", action="store_true", - help="Do not auto-add the QA Team and build meister as watchers") + help="Do not auto-add the QA Team, build meister, and reviewer as watchers") p_bp.add_argument("--project", default=PROJECT_GB, help="Project (default: %(default)s)") # comment p_comment = sub.add_parser("comment", help="Add a comment to a ticket") p_comment.add_argument("ticket_id", help="Ticket ID number") p_comment.add_argument("--message", help="Comment text") p_comment.add_argument("--message-file", dest="message_file", help="Read comment from file (- for stdin)") p_comment.add_argument("--private", action="store_true", help="Mark this comment as a private note " "(only visible to project members with permission)") # update p_update = sub.add_parser("update", help="Update ticket fields")