Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion docs/docs/en/release.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ The main feature of this release is the **Try It Out** feature for your **Async

Now you can test your developing application directly from the web, just like Swagger for HTTP. It supports in-memory publication to test a subscriber and real broker publication to verify behavior in real scenarios.

<img width="1467" height="640" alt="Снимок экрана 2026-03-01 в 11 16 10" src="[#>](https://github.com/user-attachments/assets/4320e674-24d5-4ead-9820-4bb979e340e7" />){.external-link target="_blank"}
<img width="1467" height="640" alt="" src="https://github.com/user-attachments/assets/4320e674-24d5-4ead-9820-4bb979e340e7">

* feat: Add Try It Out feature for AsyncAPI documentation by [@vvlrff](https://github.com/vvlrff){.external-link target="_blank"} in [#2777](https://github.com/ag2ai/faststream/pull/2777){.external-link target="_blank"}

Expand Down
44 changes: 42 additions & 2 deletions docs/update_releases.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,9 +35,38 @@ def get_github_releases() -> Sequence[Tuple[str, str]]:
raise Exception(f"Error getting GitHub releases: {e}, {row_data}") from e


def convert_links_and_usernames(text):
def normalize_img_tag(match: re.Match) -> str:
"""Extract img attributes and return a normalized <img> tag (plain src URL, empty alt)."""
attrs = match.group(1)
width = re.search(r'width=["\']?(\d+)', attrs)
height = re.search(r'height=["\']?(\d+)', attrs)
src = re.search(r'src=["\']([^"\']+)["\']', attrs)
if not src:
return match.group(0)
parts = []
if width:
parts.append(f'width="{width.group(1)}"')
if height:
parts.append(f'height="{height.group(1)}"')
parts.append('alt=""')
# Use only the URL, no markdown/link wrapping
parts.append(f'src="{src.group(1)}"')
return "<img " + " ".join(parts) + ">"


def convert_links_and_usernames(text: str) -> str:
# Replace <img ...> tags with placeholders so their URLs are not wrapped as links
img_pattern = re.compile(r"<img\s+([^>]+)>")
img_placeholders: List[str] = []

def stash_img(match: re.Match) -> str:
img_placeholders.append(normalize_img_tag(match))
return f"\x00IMG_PLACEHOLDER_{len(img_placeholders) - 1}\x00"

text = img_pattern.sub(stash_img, text)

if "](" not in text:
# Convert HTTP/HTTPS links
# Convert HTTP/HTTPS links (img tags already stashed, so their URLs are not matched)
text = re.sub(
r"(https?://.*\/(.*))",
r'[#\2](\1){.external-link target="_blank"}',
Expand All @@ -51,6 +80,10 @@ def convert_links_and_usernames(text):
text,
)

# Restore normalized img tags
for i, img in enumerate(img_placeholders):
text = text.replace(f"\x00IMG_PLACEHOLDER_{i}\x00", img)

return text


Expand All @@ -71,6 +104,7 @@ def update_release_notes(release_notes_path: Path):

old_versions = collect_already_published_versions(changelog)

added_versions: List[str] = []
for version, body in filter(
lambda v: v[0] not in old_versions,
get_github_releases(),
Expand All @@ -79,6 +113,12 @@ def update_release_notes(release_notes_path: Path):
body = convert_links_and_usernames(body)
version_changelog = f"## {version}\n\n{body}\n\n"
changelog = version_changelog + changelog
added_versions.append(version)

if added_versions:
print(f"Added release versions: {', '.join(added_versions)}")
else:
print("No new versions to add")

# Update the RELEASE.md file with the latest version and changelog
release_notes_path.write_text(
Expand Down