Skip to content

Commit 7642cb4

Browse files
Merge pull request #48 from open-telemetry/changelog-issue-10
Fix RSS feed markdown handling
2 parents c6f108a + 4fc34a4 commit 7642cb4

File tree

6 files changed

+81
-5
lines changed

6 files changed

+81
-5
lines changed

netlify.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
[build]
2-
command = "npm run build"
2+
command = "npm ci && npm run build"
33
publish = ".next"
44

55
[[plugins]]

package-lock.json

Lines changed: 13 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
"@netlify/blobs": "^8.1.0",
1717
"@netlify/functions": "^3.0.0",
1818
"@octokit/webhooks-types": "^7.6.1",
19+
"marked": "^15.0.9",
1920
"@radix-ui/react-select": "^2.2.2",
2021
"@radix-ui/react-slot": "^1.2.0",
2122
"class-variance-authority": "^0.7.1",

src/app/api/test/route.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ export async function POST() {
1717
const testEntry: ChangelogEntry = {
1818
id: Date.now(), // Use timestamp as ID for test entries
1919
title: `Test Entry ${new Date().toISOString()}`,
20-
description: "This is a test entry to verify cache revalidation",
20+
description: "This is a test entry with **bold text**, *italic* and a [link text](http://example.com) to verify markdown handling in RSS feed.",
2121
date: new Date().toISOString(),
2222
metadata: {
2323
sourceRepo: "open-telemetry/test-repo",

src/app/feed/route.ts

Lines changed: 52 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,54 @@
44
*/
55

66
import { getAllEntries } from "@/lib/store";
7+
import { marked } from "marked";
78

89
export const dynamic = "force-dynamic";
910
export const revalidate = 60;
1011

12+
// Convert markdown to HTML for RSS feeds
13+
function markdownToHtml(markdown: string): string {
14+
try {
15+
// Use marked.parse with synchronous option to ensure it returns a string
16+
return marked.parse(markdown, { async: false }) as string;
17+
} catch (error) {
18+
console.warn("Failed to convert markdown to HTML:", error);
19+
return markdown;
20+
}
21+
}
22+
23+
// Process GitHub-specific markdown like PR references, commit SHAs, etc.
24+
function processGitHubMarkdown(text: string, repoFullName: string): string {
25+
let processedText = text;
26+
27+
// Replace PR references first (including those in parentheses)
28+
const prPattern = /(?:^|\s|[([])#(\d+)(?=[\s\n\])]|$)/g;
29+
processedText = processedText.replace(prPattern, (match, issue) => {
30+
const prefix = match.startsWith("(") || match.startsWith("[") ? match[0] : " ";
31+
return `${prefix}[#${issue}](https://github.com/${repoFullName}/issues/${issue})`;
32+
});
33+
34+
// Replace commit SHAs
35+
const shaPattern = /(\s|^)([0-9a-f]{40})(?=[\s\n]|$)/g;
36+
processedText = processedText.replace(shaPattern, (match, space, sha) => {
37+
return `${space}[${sha}](https://github.com/${repoFullName}/commit/${sha})`;
38+
});
39+
40+
// Replace user mentions
41+
const userPattern = /(?:^|\s)@([a-zA-Z0-9-]+)(?=[\s\n]|$)/g;
42+
processedText = processedText.replace(userPattern, (match, username) => {
43+
return ` [@${username}](https://github.com/${username})`;
44+
});
45+
46+
// Replace repository references with issue numbers
47+
const repoPattern = /([a-zA-Z0-9-]+\/[a-zA-Z0-9-._-]+)#(\d+)(?=[\s\n]|$)/g;
48+
processedText = processedText.replace(repoPattern, (match, repo, issue) => {
49+
return `[${repo}#${issue}](https://github.com/${repo}/issues/${issue})`;
50+
});
51+
52+
return processedText;
53+
}
54+
1155
export async function GET() {
1256
const entries = await getAllEntries();
1357
const baseUrl =
@@ -23,13 +67,18 @@ export async function GET() {
2367
<language>en-US</language>
2468
${entries
2569
.map(
26-
(entry) => `
70+
(entry) => {
71+
// Process GitHub markdown first, then convert to HTML
72+
const processedDescription = processGitHubMarkdown(entry.description, entry.metadata.sourceRepo);
73+
const htmlDescription = markdownToHtml(processedDescription);
74+
75+
return `
2776
<item>
2877
<title><![CDATA[${entry.title}]]></title>
2978
<link>${baseUrl}/entry/${entry.id}</link>
3079
<guid isPermaLink="false">${entry.id}</guid>
3180
<pubDate>${new Date(entry.date).toUTCString()}</pubDate>
32-
<description><![CDATA[${entry.description}]]></description>
81+
<description><![CDATA[${htmlDescription}]]></description>
3382
${
3483
entry.metadata.sourceRepo
3584
? `
@@ -38,7 +87,7 @@ export async function GET() {
3887
: ""
3988
}
4089
</item>
41-
`,
90+
`}
4291
)
4392
.join("")}
4493
</channel>

tests/api.spec.ts

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,19 @@ test.describe('API Routes', () => {
1818
expect(body).toContain('<rss');
1919
expect(body).toContain('<channel>');
2020
});
21+
22+
test('feed should handle markdown in descriptions', async ({ request }) => {
23+
// This test will pass once we implement the markdown parsing fix
24+
const response = await request.get('/feed');
25+
expect(response.status()).toBe(200);
26+
27+
const body = await response.text();
28+
29+
// The test endpoint adds entries with markdown, let's verify we don't see raw markdown
30+
// This will initially fail until we fix the issue
31+
expect(body).not.toMatch(/\*\*bold text\*\*/);
32+
expect(body).not.toMatch(/\[link text\]\(http:\/\/example\.com\)/);
33+
});
2134

2235
test('test API should work in development', async ({ request }) => {
2336
// When testing in CI, we're likely in development mode

0 commit comments

Comments
 (0)