From ea14f1a3893cdb4d337f333e95a204fac235fd08 Mon Sep 17 00:00:00 2001 From: lucaronin Date: Sun, 19 Apr 2026 20:53:39 +0200 Subject: [PATCH] fix: use rendered release note html --- .github/workflows/release-stable.yml | 2 +- .github/workflows/release.yml | 2 +- src/utils/releaseHistoryPage.test.ts | 16 ++++++++++++++++ src/utils/releaseHistoryPage.ts | 28 ++++++++++++++++++---------- 4 files changed, 36 insertions(+), 12 deletions(-) diff --git a/.github/workflows/release-stable.yml b/.github/workflows/release-stable.yml index 0157cda3..c882e284 100644 --- a/.github/workflows/release-stable.yml +++ b/.github/workflows/release-stable.yml @@ -265,7 +265,7 @@ jobs: GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} run: | mkdir -p _site/alpha _site/stable - gh api repos/${{ github.repository }}/releases --paginate > _site/releases.json + gh api -H "Accept: application/vnd.github.html+json" repos/${{ github.repository }}/releases --paginate > _site/releases.json PAGES_URL="https://refactoringhq.github.io/${GITHUB_REPOSITORY#*/}" curl -fsSL "${PAGES_URL}/alpha/latest.json" -o _site/alpha/latest.json || echo '{}' > _site/alpha/latest.json diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 9fe39057..a0a8ed58 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -301,7 +301,7 @@ jobs: GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} run: | mkdir -p _site/alpha _site/stable - gh api repos/${{ github.repository }}/releases --paginate > _site/releases.json + gh api -H "Accept: application/vnd.github.html+json" repos/${{ github.repository }}/releases --paginate > _site/releases.json PAGES_URL="https://refactoringhq.github.io/${GITHUB_REPOSITORY#*/}" gh release download --repo ${{ github.repository }} "${{ needs.version.outputs.tag }}" --pattern "alpha-latest.json" --output _site/alpha/latest.json || echo '{}' > _site/alpha/latest.json diff --git a/src/utils/releaseHistoryPage.test.ts b/src/utils/releaseHistoryPage.test.ts index b876bbf6..61d0ca7e 100644 --- a/src/utils/releaseHistoryPage.test.ts +++ b/src/utils/releaseHistoryPage.test.ts @@ -11,6 +11,7 @@ describe('buildReleaseHistoryPage', () => { }, ], body: '## Highlights\n\n- Faster startup\n- Better release notes', + body_html: '

Highlights

', html_url: 'https://github.com/refactoringhq/tolaria/releases/tag/stable-v2026.4.19', name: 'Tolaria Stable 2026.4.19', prerelease: false, @@ -25,6 +26,7 @@ describe('buildReleaseHistoryPage', () => { }, ], body: '**Alpha** notes with [details](https://example.com/details).', + body_html: '

Alpha notes with details.

', html_url: 'https://github.com/refactoringhq/tolaria/releases/tag/2026.4.19-alpha.1', name: 'Alpha 2026.4.19.1', prerelease: true, @@ -44,6 +46,20 @@ describe('buildReleaseHistoryPage', () => { expect(html).toContain('View on GitHub') }) + it('falls back to escaped paragraph markup when rendered html is unavailable', () => { + const html = buildReleaseHistoryPage([ + { + body: 'First paragraph\nwith a line break.\n\nSecond paragraph', + name: 'Fallback release', + prerelease: false, + published_at: '2026-04-19T11:00:00Z', + tag_name: 'stable-v2026.4.19', + }, + ]) + + expect(html).toContain('

First paragraph
with a line break.

Second paragraph

') + }) + it('filters draft releases and shows an empty state for channels without published builds', () => { const html = buildReleaseHistoryPage([ { diff --git a/src/utils/releaseHistoryPage.ts b/src/utils/releaseHistoryPage.ts index 0498be43..4f126748 100644 --- a/src/utils/releaseHistoryPage.ts +++ b/src/utils/releaseHistoryPage.ts @@ -1,8 +1,3 @@ -import { createElement } from 'react' -import Markdown from 'react-markdown' -import { renderToStaticMarkup } from 'react-dom/server' -import remarkGfm from 'remark-gfm' - type ReleaseAssetPayload = { browser_download_url?: unknown name?: unknown @@ -11,6 +6,7 @@ type ReleaseAssetPayload = { type GitHubReleasePayload = { assets?: ReleaseAssetPayload[] body?: unknown + body_html?: unknown draft?: unknown html_url?: unknown name?: unknown @@ -376,7 +372,6 @@ const RELEASE_HISTORY_PAGE_SCRIPT = ` })(); ` -const MARKDOWN_REMARK_PLUGINS = [remarkGfm] const RELEASE_CHANNEL_LABELS: Record = { alpha: 'Alpha', stable: 'Stable', @@ -446,8 +441,22 @@ function normalizeDownloads(assets: ReleaseAssetPayload[] | undefined): ReleaseD return downloads } -function renderReleaseNotes(markdown: string): string { - return renderToStaticMarkup(createElement(Markdown, { remarkPlugins: MARKDOWN_REMARK_PLUGINS }, markdown)) +function buildFallbackReleaseNotesHtml(markdownFallback: string): string { + const paragraphs = markdownFallback + .split(/\n{2,}/) + .map(part => part.trim()) + .filter(part => part.length > 0) + .map(part => `

${escapeHtml(part).replaceAll('\n', '
')}

`) + + return paragraphs.join('') +} + +function resolveReleaseNotesHtml(renderedHtml: unknown, markdownFallback: unknown): string { + const bodyHtml = normalizeText(renderedHtml) + if (bodyHtml !== null) return bodyHtml + + const fallback = normalizeText(markdownFallback) ?? 'No release notes provided.' + return buildFallbackReleaseNotesHtml(fallback) } function normalizeReleaseEntry(release: GitHubReleasePayload): [ReleaseChannel, ReleaseEntry] | null { @@ -455,13 +464,12 @@ function normalizeReleaseEntry(release: GitHubReleasePayload): [ReleaseChannel, const title = normalizeText(release.name) ?? normalizeText(release.tag_name) ?? 'Untitled release' const tagName = normalizeText(release.tag_name) ?? 'Unknown tag' - const notes = normalizeText(release.body) ?? 'No release notes provided.' const channel: ReleaseChannel = release.prerelease === true ? 'alpha' : 'stable' return [channel, { downloads: normalizeDownloads(release.assets), githubUrl: normalizeUrl(release.html_url), - notesHtml: renderReleaseNotes(notes), + notesHtml: resolveReleaseNotesHtml(release.body_html, release.body), publishedLabel: formatPublishedLabel(release.published_at), tagName, title,