Skip to content

Commit fb0eee7

Browse files
heiskrCopilot
andauthored
Fix link checker false positives for enterprise-server@latest URLs (#59716)
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
1 parent 6377290 commit fb0eee7

File tree

2 files changed

+37
-4
lines changed

2 files changed

+37
-4
lines changed

src/links/lib/extract-links.ts

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import fs from 'fs'
99
import path from 'path'
1010

1111
import { allVersions } from '@/versions/lib/all-versions'
12+
import { latestStable } from '@/versions/lib/enterprise-server-releases'
1213
import { getDataByLanguage } from '@/data-directory/lib/get-data'
1314
import type { Context, Page } from '@/types'
1415

@@ -307,22 +308,31 @@ export function checkInternalLink(
307308
): { exists: boolean; isRedirect: boolean; redirectTarget?: string } {
308309
const normalized = normalizeLinkPath(href)
309310

311+
// Resolve enterprise-server@latest to actual version, mirroring runtime behavior.
312+
// Handle both /enterprise-server@latest/... and /en/enterprise-server@latest/...
313+
const latestPrefix = '/enterprise-server@latest'
314+
const stablePrefix = `/enterprise-server@${latestStable}`
315+
const resolved =
316+
normalized.startsWith(latestPrefix) || normalized.startsWith(`/en${latestPrefix}`)
317+
? normalized.replace(latestPrefix, stablePrefix)
318+
: normalized
319+
310320
// Check if it's a direct page
311-
if (pageMap[normalized]) {
321+
if (pageMap[resolved]) {
312322
return { exists: true, isRedirect: false }
313323
}
314324

315325
// Check if it's a redirect
316-
if (redirects[normalized]) {
326+
if (redirects[resolved]) {
317327
return {
318328
exists: true,
319329
isRedirect: true,
320-
redirectTarget: redirects[normalized],
330+
redirectTarget: redirects[resolved],
321331
}
322332
}
323333

324334
// Check with /en prefix (FPT pages are stored with language prefix)
325-
const withLang = `/en${normalized}`
335+
const withLang = `/en${resolved}`
326336
if (pageMap[withLang]) {
327337
return { exists: true, isRedirect: false }
328338
}

src/links/tests/extract-links.ts

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import {
66
checkAssetLink,
77
isAssetLink,
88
} from '../lib/extract-links'
9+
import { latestStable } from '@/versions/lib/enterprise-server-releases'
910

1011
describe('extractLinksFromMarkdown', () => {
1112
test('extracts simple internal links', () => {
@@ -179,6 +180,7 @@ describe('checkInternalLink', () => {
179180
'/en/actions/getting-started': {} as any,
180181
'/en/repositories/overview': {} as any,
181182
'/actions/guides': {} as any,
183+
[`/en/enterprise-server@${latestStable}/admin/overview`]: {} as any,
182184
}
183185

184186
const redirects = {
@@ -210,6 +212,27 @@ describe('checkInternalLink', () => {
210212
expect(result.exists).toBe(false)
211213
expect(result.isRedirect).toBe(false)
212214
})
215+
216+
test('resolves enterprise-server@latest to actual version', () => {
217+
const result = checkInternalLink('/enterprise-server@latest/admin/overview', pageMap, redirects)
218+
expect(result.exists).toBe(true)
219+
expect(result.isRedirect).toBe(false)
220+
})
221+
222+
test('resolves enterprise-server@latest with language prefix', () => {
223+
const result = checkInternalLink(
224+
'/en/enterprise-server@latest/admin/overview',
225+
pageMap,
226+
redirects,
227+
)
228+
expect(result.exists).toBe(true)
229+
expect(result.isRedirect).toBe(false)
230+
})
231+
232+
test('resolves enterprise-server@latest for non-existent page', () => {
233+
const result = checkInternalLink('/enterprise-server@latest/does/not/exist', pageMap, redirects)
234+
expect(result.exists).toBe(false)
235+
})
213236
})
214237

215238
describe('isAssetLink', () => {

0 commit comments

Comments
 (0)