1
0
mirror of synced 2025-12-23 21:07:12 -05:00

Adding internal links version rule with fixes (#43346)

This commit is contained in:
Grace Park
2023-09-27 17:56:48 -07:00
committed by GitHub
parent 7ba2595790
commit b0890a5494
5 changed files with 95 additions and 18 deletions

View File

@@ -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,

View File

@@ -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
)
}
}
})
},
}

View File

@@ -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',

View File

@@ -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) || []

View 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)
})
})