Adding internal links version rule with fixes (#43346)
This commit is contained in:
@@ -12,6 +12,7 @@ import { listFirstWordCapitalization } from './list-first-word-capitalization.js
|
||||
import { linkPunctuation } from './link-punctuation.js'
|
||||
import { earlyAccessReferences } from './early-access-references.js'
|
||||
import { yamlScheduledJobs } from './yaml-scheduled-jobs.js'
|
||||
import { internalLinksOldVersion } from './internal-links-old-version.js'
|
||||
import { hardcodedDataVariable } from './hardcoded-data-variable.js'
|
||||
import { githubOwnedActionReferences } from './github-owned-action-references.js'
|
||||
import { liquidQuotedConditionalArg } from './liquid-quoted-conditional-arg.js'
|
||||
@@ -39,6 +40,7 @@ export const gitHubDocsMarkdownlint = {
|
||||
linkPunctuation,
|
||||
earlyAccessReferences,
|
||||
yamlScheduledJobs,
|
||||
internalLinksOldVersion,
|
||||
hardcodedDataVariable,
|
||||
githubOwnedActionReferences,
|
||||
liquidQuotedConditionalArg,
|
||||
|
||||
@@ -0,0 +1,57 @@
|
||||
import { filterTokens, addError } from 'markdownlint-rule-helpers'
|
||||
import { getRange } from '../helpers/utils.js'
|
||||
|
||||
export const internalLinksOldVersion = {
|
||||
names: ['GHD010', 'internal-links-old-version'],
|
||||
description: 'Internal links must not have a hardcoded version using old versioning patterns',
|
||||
tags: ['links', 'url'],
|
||||
information: new URL('https://github.com/github/docs/blob/main/src/content-linter/README.md'),
|
||||
function: function GHD010(params, onError) {
|
||||
filterTokens(params, 'inline', (token) => {
|
||||
if (
|
||||
params.name.endsWith('migrating-from-github-enterprise-1110x-to-2123.md') ||
|
||||
params.name.endsWith('all-releases.md')
|
||||
)
|
||||
return
|
||||
for (const child of token.children) {
|
||||
if (child.type !== 'link_open') continue
|
||||
// Things matched by this RegExp:
|
||||
// - /enterprise/2.19/admin/blah
|
||||
// - https://docs.github.com/enterprise/11.10.340/admin/blah
|
||||
// - http://help.github.com/enterprise/2.8/admin/blah
|
||||
//
|
||||
// Things intentionally NOT matched by this RegExp:
|
||||
// - https://someservice.com/enterprise/1.0/blah
|
||||
// - /github/site-policy/enterprise/2.2/admin/blah
|
||||
const versionLinkRegEx =
|
||||
/(?:(?:https?:\/\/(?:help|docs|developer)\.github\.com)(?:\/enterprise\/\d+(\.\d+)+\/[^)\s]*)?|^\/enterprise\/\d+(\.\d+)+\/[^)\s]*)(?=\s|$)/gm
|
||||
// Example child.attrs:
|
||||
// [
|
||||
// ['href', 'get-started'], ['target', '_blank'],
|
||||
// ['rel', 'canonical'],
|
||||
// ]
|
||||
const hrefsMissingSlashes = child.attrs
|
||||
// The attribute could also be `target` or `rel`
|
||||
.filter((attr) => attr[0] === 'href')
|
||||
.filter((attr) => attr[1].startsWith('/') || !attr[1].startsWith('//'))
|
||||
// Filter out link paths that matches the version link regex
|
||||
.filter((attr) => attr[1].match(versionLinkRegEx))
|
||||
// Get the link path from the attribute
|
||||
.map((attr) => attr[1])
|
||||
|
||||
// Create errors for each link path that includes a hardcoded version
|
||||
for (const linkPath of hrefsMissingSlashes) {
|
||||
const range = getRange(child.line, linkPath)
|
||||
addError(
|
||||
onError,
|
||||
child.lineNumber,
|
||||
`There looks to be a hardcoded version in this link: ${linkPath}`,
|
||||
linkPath,
|
||||
range,
|
||||
null, // No fix possible
|
||||
)
|
||||
}
|
||||
}
|
||||
})
|
||||
},
|
||||
}
|
||||
@@ -44,6 +44,11 @@ const githubDocsConfig = {
|
||||
severity: 'error',
|
||||
'partial-markdown-files': true,
|
||||
},
|
||||
'internal-links-old-version': {
|
||||
// GHD010
|
||||
severity: 'error',
|
||||
'partial-markdown-files': true,
|
||||
},
|
||||
'list-first-word-capitalization': {
|
||||
// GH011
|
||||
severity: 'warning',
|
||||
|
||||
@@ -476,24 +476,6 @@ describe('lint markdown content', () => {
|
||||
expect(matches.length, errorMessage).toBe(0)
|
||||
})
|
||||
|
||||
test('URLs must not contain a hard-coded version number', async () => {
|
||||
const initialMatches = content.match(versionLinkRegEx) || []
|
||||
|
||||
// Filter out some very specific false positive matches
|
||||
const matches = initialMatches.filter(() => {
|
||||
if (
|
||||
markdownRelPath.endsWith('migrating-from-github-enterprise-1110x-to-2123.md') ||
|
||||
markdownRelPath.endsWith('all-releases.md')
|
||||
) {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
})
|
||||
|
||||
const errorMessage = formatLinkError(versionLinkErrorText, matches)
|
||||
expect(matches.length, errorMessage).toBe(0)
|
||||
})
|
||||
|
||||
test('URLs must not contain a hard-coded domain name', async () => {
|
||||
const initialMatches = content.match(domainLinkRegex) || []
|
||||
|
||||
|
||||
31
src/content-linter/tests/unit/internal-links-old-version.js
Normal file
31
src/content-linter/tests/unit/internal-links-old-version.js
Normal file
@@ -0,0 +1,31 @@
|
||||
import { runRule } from '../../lib/init-test.js'
|
||||
import { internalLinksOldVersion } from '../../lib/linting-rules/internal-links-old-version.js'
|
||||
|
||||
describe(internalLinksOldVersion.names.join(' - '), () => {
|
||||
test('links with old hardcoded versioning fail', async () => {
|
||||
const markdown = [
|
||||
'[Enterprise 2.19](/enterprise/2.19/admin/site/blah)',
|
||||
'[Link to Enterprise 11.10.340](https://docs.github.com/enterprise/11.10.340/admin/yes)',
|
||||
'[Enterprise 2.8](http://help.github.com/enterprise/2.8/admin/)',
|
||||
].join('\n')
|
||||
const result = await runRule(internalLinksOldVersion, { strings: { markdown } })
|
||||
const errors = result.markdown
|
||||
expect(errors.length).toBe(3)
|
||||
expect(errors.map((error) => error.lineNumber)).toEqual([1, 2, 3])
|
||||
expect(errors[0].errorRange).toEqual([19, 32])
|
||||
expect(errors[1].errorRange).toEqual([32, 54])
|
||||
expect(errors[2].errorRange).toEqual([18, 44])
|
||||
})
|
||||
|
||||
test('links without old hardcoded versions pass', async () => {
|
||||
const markdown = [
|
||||
// External links with enterprise in them
|
||||
'[External link](https://someservice.com/enterprise/1.0/admin/yes)',
|
||||
// Current versioning links is excluded from this test
|
||||
'[New versioning](/github/site-policy/enterprise/2.2/yes)',
|
||||
].join('\n')
|
||||
const result = await runRule(internalLinksOldVersion, { strings: { markdown } })
|
||||
const errors = result.markdown
|
||||
expect(errors.length).toBe(0)
|
||||
})
|
||||
})
|
||||
Reference in New Issue
Block a user