mirror of
https://github.com/rennf93/roboco.git
synced 2026-08-03 07:23:24 +02:00
fix(x): release caption uses curated CHANGELOG headlines, not commit subjects (#607)
draft_release_post was fed highlights=list(report.change_summary) — raw
per-commit subjects — so the announcement model parroted the top commit
('RoboCo API v0.26.0 is out: docs: curate the full Unreleased body #601').
New pure changelog_highlights() extracts the bold feature leads from the
curated release entry (report.drafted_changelog), stripping PR refs and
trailing periods; approve() prefers those and falls back to change_summary
only when the changelog yields nothing. The video captions were already
good because the authoring dev read the changelog — same source now.
Co-authored-by: Renn F <rennf93@users.noreply.github.com>
This commit is contained in:
@@ -283,11 +283,17 @@ class ReleaseProposalService(BaseService):
|
||||
publish). Off/no-creds is itself a no-op inside the engine. The
|
||||
proposal task's project scopes the draft to the released project."""
|
||||
try:
|
||||
from roboco.services.x_engine import get_x_engine
|
||||
from roboco.services.x_engine import changelog_highlights, get_x_engine
|
||||
|
||||
# Prefer the curated CHANGELOG's feature headlines over raw
|
||||
# per-commit subjects — the latter made the announcement caption
|
||||
# parrot the top commit ("docs: curate the Unreleased body…").
|
||||
highlights = changelog_highlights(report.drafted_changelog) or list(
|
||||
report.change_summary
|
||||
)
|
||||
await get_x_engine(self.session).draft_release_post(
|
||||
version=report.proposed_version,
|
||||
highlights=list(report.change_summary),
|
||||
highlights=highlights,
|
||||
project_id=project_id,
|
||||
)
|
||||
except Exception as exc:
|
||||
|
||||
@@ -103,6 +103,31 @@ def _fallback_release_body(
|
||||
return f"{product_name} v{version} is out: {lead}"
|
||||
|
||||
|
||||
# Bold feature leads in a Keep-a-Changelog release body: "- **Headline (#N).**"
|
||||
_CHANGELOG_LEAD_RE = re.compile(r"^- \*\*(?P<lead>.+?)\*\*", re.MULTILINE)
|
||||
_CHANGELOG_PR_REF_RE = re.compile(r"\s*\(#\d+(?:,\s*#\d+)*\)")
|
||||
|
||||
|
||||
def changelog_highlights(entry: str, *, limit: int = 8) -> list[str]:
|
||||
"""Human-readable feature headlines from a curated CHANGELOG release body.
|
||||
|
||||
The release drafter's ``change_summary`` is raw per-commit subjects
|
||||
("docs: curate the full 0.26.0 Unreleased body (#601)") — feeding those to
|
||||
the announcement model produces a lame parroted caption. The curated
|
||||
changelog's bold leads ARE the feature story ("Telegram Mini App V5 — brand
|
||||
voice…"), so use those instead. Pure + best-effort: a body with no bold
|
||||
leads yields an empty list and the caller falls back to change_summary.
|
||||
"""
|
||||
out: list[str] = []
|
||||
for m in _CHANGELOG_LEAD_RE.finditer(entry):
|
||||
lead = _CHANGELOG_PR_REF_RE.sub("", m.group("lead")).strip().rstrip(".").strip()
|
||||
if lead:
|
||||
out.append(lead)
|
||||
if len(out) >= limit:
|
||||
break
|
||||
return out
|
||||
|
||||
|
||||
def _release_prompt(
|
||||
version: str, highlights: list[str], voice: str, product_name: str
|
||||
) -> str:
|
||||
|
||||
@@ -1398,3 +1398,27 @@ async def test_draft_release_post_uses_project_name_when_set(
|
||||
assert body is not None
|
||||
assert "Acme Robotics" in body
|
||||
assert "RoboCo" not in body
|
||||
|
||||
|
||||
def test_changelog_highlights_extracts_feature_headlines() -> None:
|
||||
entry = (
|
||||
"## [0.26.0] - 2026-07-20\n\n"
|
||||
"### Security\n\n"
|
||||
"- **Orchestrator API is off the public internet (GHSA-4f7g).** Both "
|
||||
"composes published :8000 on 0.0.0.0.\n\n"
|
||||
"### Added\n\n"
|
||||
"- **Telegram Mini App V5 — brand voice and an operations ring (#583).** "
|
||||
"Share Tech Mono becomes the display face.\n"
|
||||
"- **Forge program: GitHub, Gitea, and GitLab (#575, #581).** One API.\n"
|
||||
)
|
||||
hl = x_engine_module.changelog_highlights(entry)
|
||||
assert hl[0] == "Orchestrator API is off the public internet (GHSA-4f7g)"
|
||||
assert hl[1] == "Telegram Mini App V5 — brand voice and an operations ring"
|
||||
assert hl[2] == "Forge program: GitHub, Gitea, and GitLab"
|
||||
# No raw commit-subject noise, no trailing PR refs or periods.
|
||||
assert all("#" not in h.split("(GHSA")[0] for h in hl)
|
||||
|
||||
|
||||
def test_changelog_highlights_empty_on_no_leads() -> None:
|
||||
body = "## [0.26.0]\n\nplain prose, no bold leads\n"
|
||||
assert x_engine_module.changelog_highlights(body) == []
|
||||
|
||||
Reference in New Issue
Block a user