Skip to content

Commit 93de113

Browse files
committed
Fix upstream watch issue naming
1 parent aa4ee39 commit 93de113

1 file changed

Lines changed: 75 additions & 3 deletions

File tree

scripts/upstream_watch.py

Lines changed: 75 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@
1818

1919

2020
USER_AGENT = "dotnet-skills-upstream-watch"
21+
ISSUE_TITLE_PREFIX = "Upstream update: "
22+
MAX_ISSUE_TITLE_LENGTH = 256
2123
MARKER_RE = re.compile(r"<!-- upstream-watch:id=(?P<watch_id>[^>]+) -->")
2224
VALUE_MARKER_RE = re.compile(r"<!-- upstream-watch:value=(?P<value>[^>]+) -->")
2325
ISSUE_KEY_MARKER_RE = re.compile(r"<!-- upstream-watch:issue-key=(?P<issue_key>[^>]+) -->")
@@ -223,6 +225,15 @@ def default_issue_name(skills: list[str]) -> str:
223225
return " + ".join(ordered)
224226

225227

228+
def condensed_issue_name(skills: list[str]) -> str | None:
229+
ordered = sorted(dict.fromkeys(skills))
230+
if not ordered:
231+
return None
232+
if len(ordered) <= 3:
233+
return " + ".join(ordered)
234+
return f"{ordered[0]} + {ordered[1]} + {ordered[2]} + {len(ordered) - 3} more"
235+
236+
226237
def validate_issue_group_fields(normalized: dict[str, Any], raw_watch: dict[str, Any]) -> None:
227238
issue_key = raw_watch.get("issue_key") or default_issue_key(normalized["skills"])
228239
issue_name = raw_watch.get("issue_name") or default_issue_name(normalized["skills"])
@@ -584,7 +595,55 @@ def parse_open_issue(
584595

585596

586597
def issue_title(issue_name: str) -> str:
587-
return f"Upstream update: {issue_name}"
598+
return f"{ISSUE_TITLE_PREFIX}{issue_name}"
599+
600+
601+
def parse_issue_name_from_title(title: str | None) -> str | None:
602+
if not isinstance(title, str):
603+
return None
604+
if not title.startswith(ISSUE_TITLE_PREFIX):
605+
return None
606+
issue_name = title[len(ISSUE_TITLE_PREFIX) :].strip()
607+
return issue_name or None
608+
609+
610+
def truncate_issue_name(issue_name: str) -> str:
611+
max_issue_name_length = MAX_ISSUE_TITLE_LENGTH - len(ISSUE_TITLE_PREFIX)
612+
if max_issue_name_length <= 0 or len(issue_name) <= max_issue_name_length:
613+
return issue_name
614+
if max_issue_name_length <= 3:
615+
return issue_name[:max_issue_name_length]
616+
return issue_name[: max_issue_name_length - 3].rstrip() + "..."
617+
618+
619+
def resolve_issue_name(
620+
*,
621+
issue_key: str,
622+
skills: list[str],
623+
configured_issue_name: str | None = None,
624+
existing_issue_name: str | None = None,
625+
) -> str:
626+
candidates: list[str] = []
627+
for candidate in (
628+
configured_issue_name,
629+
existing_issue_name,
630+
default_issue_name(skills) if skills else None,
631+
condensed_issue_name(skills),
632+
issue_key,
633+
):
634+
if not isinstance(candidate, str):
635+
continue
636+
cleaned = candidate.strip()
637+
if not cleaned or cleaned in candidates:
638+
continue
639+
candidates.append(cleaned)
640+
641+
for candidate in candidates:
642+
if len(issue_title(candidate)) <= MAX_ISSUE_TITLE_LENGTH:
643+
return candidate
644+
645+
fallback = candidates[-1] if candidates else issue_key.strip() or "upstream-watch"
646+
return truncate_issue_name(fallback)
588647

589648

590649
def issue_body(
@@ -757,10 +816,14 @@ def load_open_issue_groups(
757816
"issues": [],
758817
"pending_watches": {},
759818
"skills": [],
819+
"issue_name": None,
760820
"fresh": False,
761821
},
762822
)
763823
group["issues"].append(issue)
824+
issue_name = parse_issue_name_from_title(issue.get("title"))
825+
if issue_name and not group.get("issue_name"):
826+
group["issue_name"] = issue_name
764827

765828
for skill in skills:
766829
if skill not in group["skills"]:
@@ -842,7 +905,11 @@ def reconcile_open_issues(
842905
canonical_issue = choose_canonical_issue(group["issues"])
843906
pending_watches = group["pending_watches"]
844907
skills = collect_group_skills(pending_watches, watch_index, fallback_skills=group.get("skills"))
845-
issue_name = default_issue_name(skills) if skills else issue_key
908+
issue_name = resolve_issue_name(
909+
issue_key=issue_key,
910+
skills=skills,
911+
existing_issue_name=group.get("issue_name"),
912+
)
846913
title = issue_title(issue_name)
847914
body = issue_body(
848915
issue_key=issue_key,
@@ -911,7 +978,12 @@ def rotate_issue(
911978
existing_watch_snapshot = pending_watches.get(watch["id"])
912979
pending_watches[watch["id"]] = minimal_snapshot(new_snapshot)
913980
skills = collect_group_skills(pending_watches, watch_index, fallback_skills=watch.get("skills"))
914-
issue_name = default_issue_name(skills) if skills else watch.get("issue_name", issue_key)
981+
issue_name = resolve_issue_name(
982+
issue_key=issue_key,
983+
skills=skills,
984+
configured_issue_name=watch.get("issue_name"),
985+
existing_issue_name=existing_group.get("issue_name") if existing_group else None,
986+
)
915987
title = issue_title(issue_name)
916988
body = issue_body(
917989
issue_key=issue_key,

0 commit comments

Comments
 (0)