Skip to content

Commit a762a15

Browse files
author
Peter Bengtsson
authored
Support archived enterprise versions in /api/pageinfo (#36896)
1 parent 201f6a2 commit a762a15

File tree

3 files changed

+63
-14
lines changed

3 files changed

+63
-14
lines changed

lib/is-archived-version.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,10 @@ export default function isArchivedVersion(req) {
55
// if this is an assets path, use the referrer
66
// if this is a docs path, use the req.path
77
const pathToCheck = patterns.assetPaths.test(req.path) ? req.get('referrer') : req.path
8+
return isArchivedVersionByPath(pathToCheck)
9+
}
810

11+
export function isArchivedVersionByPath(pathToCheck) {
912
// ignore paths that don't have an enterprise version number
1013
if (
1114
!(

src/pageinfo/middleware.js

Lines changed: 37 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -12,18 +12,24 @@ import shortVersions from '../../middleware/contextualizers/short-versions.js'
1212
import contextualize from '../../middleware/context.js'
1313
import features from '../../middleware/contextualizers/features.js'
1414
import getRedirect from '../../lib/get-redirect.js'
15+
import { isArchivedVersionByPath } from '../../lib/is-archived-version.js'
1516

1617
const router = express.Router()
1718

1819
const validationMiddleware = (req, res, next) => {
19-
let { pathname } = req.query
20+
const { pathname } = req.query
2021
if (!pathname) {
2122
return res.status(400).json({ error: `No 'pathname' query` })
2223
}
2324
if (!pathname.trim()) {
2425
return res.status(400).json({ error: `'pathname' query empty` })
2526
}
27+
req.pageinfo = { pathname }
28+
return next()
29+
}
2630

31+
const pageinfoMiddleware = (req, res, next) => {
32+
let { pathname } = req.pageinfo
2733
// We can't use the `findPage` middleware utility function because we
2834
// need to know when the pathname is a redirect.
2935
// This is important so that the final `pathname` value
@@ -46,35 +52,52 @@ const validationMiddleware = (req, res, next) => {
4652
}
4753

4854
if (!(pathname in req.context.pages)) {
49-
const redirect = getRedirect(pathname, redirectsContext)
50-
if (redirect) {
51-
pathname = redirect
55+
// If a pathname is not a known page, it might *either* be a redirect,
56+
// or an archived enterprise version, or both.
57+
// That's why it's import to not bother looking at the redirects
58+
// if the pathname is an archived enterprise version.
59+
// This mimics how our middleware work and their order.
60+
req.pageinfo.archived = isArchivedVersionByPath(pathname)
61+
if (!req.pageinfo.archived.isArchived) {
62+
const redirect = getRedirect(pathname, redirectsContext)
63+
if (redirect) {
64+
pathname = redirect
65+
}
5266
}
5367
}
54-
const page = req.context.pages[pathname]
5568

56-
if (!page) {
57-
return res.status(400).json({ error: `No page found for '${pathname}'` })
58-
}
59-
60-
req.pageinfo = {
61-
pathname,
62-
page,
63-
}
69+
// Remember this might yield undefined if the pathname is not a page
70+
req.pageinfo.page = req.context.pages[pathname]
71+
// The pathname might have changed if it was a redirect
72+
req.pageinfo.pathname = pathname
6473

6574
return next()
6675
}
6776

6877
router.get(
6978
'/v1',
7079
validationMiddleware,
80+
pageinfoMiddleware,
7181
catchMiddlewareError(async function pageInfo(req, res) {
7282
// Remember, the `validationMiddleware` will use redirects if the
7383
// `pathname` used is a redirect (e.g. /en/articles/foo or
7484
// /articles or '/en/enterprise-server@latest/foo/bar)
7585
// So by the time we get here, the pathname should be one of the
7686
// page's valid permalinks.
77-
const { page, pathname } = req.pageinfo
87+
const { page, pathname, archived } = req.pageinfo
88+
89+
if (archived && archived.isArchived) {
90+
const { requestedVersion } = archived
91+
const title = `GitHub Enterprise Server ${requestedVersion} Help Documentation`
92+
const intro = ''
93+
const product = 'GitHub Enterprise Server'
94+
defaultCacheControl(res)
95+
return res.json({ info: { intro, title, product } })
96+
}
97+
98+
if (!page) {
99+
return res.status(400).json({ error: `No page found for '${pathname}'` })
100+
}
78101

79102
const pagePermalinks = page.permalinks.map((p) => p.href)
80103
if (!pagePermalinks.includes(pathname)) {

src/pageinfo/tests/pageinfo.js

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -151,4 +151,27 @@ describe('pageinfo api', () => {
151151
expect(info.title).toMatch('GitHub Enterprise Server Fixture Documentation')
152152
}
153153
})
154+
155+
test('archived enterprise versions', async () => {
156+
// For example /en/[email protected] is a valid Page in the
157+
// site tree, but /en/[email protected] is not. Yet we can
158+
// 200 OK and serve content for that. This needs to be reflected in
159+
// page info too. Even if we have to "fabricate" the title a bit.
160+
161+
// At the time of writing, the latest archived version
162+
{
163+
const res = await get(makeURL('/en/[email protected]'))
164+
expect(res.statusCode).toBe(200)
165+
const { info } = JSON.parse(res.body)
166+
expect(info.title).toMatch('GitHub Enterprise Server 3.2 Help Documentation')
167+
}
168+
169+
// The oldest known archived version that we proxy
170+
{
171+
const res = await get(makeURL('/en/enterprise/11.10.340'))
172+
expect(res.statusCode).toBe(200)
173+
const { info } = JSON.parse(res.body)
174+
expect(info.title).toMatch('GitHub Enterprise Server 11.10.340 Help Documentation')
175+
}
176+
})
154177
})

0 commit comments

Comments
 (0)