diff --git a/lib/changelog.js b/lib/changelog.js index a3f85bf5e4..477c327460 100644 --- a/lib/changelog.js +++ b/lib/changelog.js @@ -1,6 +1,6 @@ import Parser from 'rss-parser' -export async function getRssFeed(url) { +async function getRssFeed(url) { const parser = new Parser({ timeout: 5000 }) const feedUrl = `${url}/feed` let feed @@ -15,7 +15,16 @@ export async function getRssFeed(url) { return feed } -export async function getChangelogItems(prefix, feed) { +const globalCache = new Map() + +export async function getChangelogItems(prefix, feedUrl) { + const cacheKey = prefix + feedUrl + if (globalCache.get(cacheKey)) { + return globalCache.get(cacheKey) + } + + const feed = await getRssFeed(feedUrl) + if (!feed || !feed.items) { console.log(feed) console.error('feed is not valid or has no items') @@ -34,7 +43,10 @@ export async function getChangelogItems(prefix, feed) { } }) + // We don't cache the raw payload we'd get from the network request + // because it would waste memory. Instead we store the "serialized" + // object that's created from the raw payload. + globalCache.set(cacheKey, changelog) + return changelog } - -export default { getRssFeed, getChangelogItems } diff --git a/middleware/contextualizers/whats-new-changelog.js b/middleware/contextualizers/whats-new-changelog.js index 522573449e..948e1edd4d 100644 --- a/middleware/contextualizers/whats-new-changelog.js +++ b/middleware/contextualizers/whats-new-changelog.js @@ -1,10 +1,10 @@ -import { getRssFeed, getChangelogItems } from '../../lib/changelog.js' +import { getChangelogItems } from '../../lib/changelog.js' import getApplicableVersions from '../../lib/get-applicable-versions.js' export default async function whatsNewChangelog(req, res, next) { if (!req.context.page) return next() if (!req.context.page.changelog) return next() - const label = req.context.page.changelog.label + const label = req.context.page.changelog.label.split(/\s+/g).join('') // If there is no `versions` prop in the changelog frontmatter, assume the changelog should display in all versions. if (req.context.page.changelog.versions) { @@ -23,7 +23,9 @@ export default async function whatsNewChangelog(req, res, next) { req.context.changelogUrl = labelUrls[label] || `https://github.blog/changelog/label/${label}` - const feed = await getRssFeed(req.context.changelogUrl) - req.context.whatsNewChangelog = await getChangelogItems(req.context.page.changelog.prefix, feed) + req.context.whatsNewChangelog = await getChangelogItems( + req.context.page.changelog.prefix, + req.context.changelogUrl + ) return next() } diff --git a/tests/unit/get-rss-feeds.js b/tests/unit/get-rss-feeds.js index 2c5d1f5252..f1b936804a 100644 --- a/tests/unit/get-rss-feeds.js +++ b/tests/unit/get-rss-feeds.js @@ -1,20 +1,29 @@ -import Parser from 'rss-parser' -import { getChangelogItems } from '../../lib/changelog.js' import fs from 'fs/promises' import path from 'path' -const parser = new Parser({ timeout: 5000 }) -const rssFeedContent = await fs.readFile( - path.join(process.cwd(), 'tests/fixtures/rss-feed.xml'), - 'utf8' -) + +import nock from 'nock' + +import { getChangelogItems } from '../../lib/changelog.js' describe('getChangelogItems module', () => { let changelog + beforeAll(async () => { - const feed = await parser.parseString(rssFeedContent) - changelog = await getChangelogItems('GitHub Actions:', feed) + const rssFeedContent = await fs.readFile( + path.join(process.cwd(), 'tests/fixtures/rss-feed.xml'), + 'utf8' + ) + + nock('https://github.blog').get('/changelog/label/packages/feed').reply(200, rssFeedContent) + + changelog = await getChangelogItems( + 'GitHub Actions:', + 'https://github.blog/changelog/label/packages' + ) }) + afterAll(() => nock.cleanAll()) + it('changelog contains 3 items', async () => { expect(changelog.length).toEqual(3) })