Skip to content

Commit 31d83ed

Browse files
authored
Break up giant content linter test suite (#42144)
1 parent bdf9be5 commit 31d83ed

File tree

12 files changed

+207
-282
lines changed

12 files changed

+207
-282
lines changed

.github/workflows/test.yml

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,16 +53,18 @@ jobs:
5353
{ name: 'github-apps', path: 'src/github-apps/tests', },
5454
{ name: 'graphql', path: 'src/graphql/tests', },
5555
{ name: 'landings', path: 'src/landings/tests', },
56-
// { name: 'learning-track', path: 'src/learning-track/tests', },
56+
{ name: 'learning-track', path: 'src/learning-track/tests', },
5757
{ name: 'linting', path: 'src/content-linter/tests', },
5858
{ name: 'observability', path: 'src/observability/tests' },
5959
{ name: 'pageinfo', path: 'src/pageinfo/tests', },
6060
{ name: 'redirects', path: 'src/redirects/tests', },
61+
{ name: 'release-notes', path: 'src/release-notes/tests', },
6162
{ name: 'rendering', path: 'tests/rendering', },
6263
{ name: 'rendering-fixtures', path: 'tests/rendering-fixtures', },
6364
{ name: 'rest', path: 'src/rest/tests', },
6465
{ name: 'routing', path: 'tests/routing', },
6566
{ name: 'search', path: 'src/search/tests', },
67+
{ name: 'secret-scanning', path: 'src/secret-scanning/tests',},
6668
{ name: 'shielding', path: 'src/shielding/tests', },
6769
context.payload.repository.full_name === 'github/docs-internal' &&
6870
{ name: 'languages', path: 'src/languages/tests', },

lib/ajv-validate.js

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
import Ajv from 'ajv'
2+
import addErrors from 'ajv-errors'
3+
import addFormats from 'ajv-formats'
4+
import semver from 'semver'
5+
6+
const ajv = new Ajv({ allErrors: true, allowUnionTypes: true })
7+
addFormats(ajv)
8+
addErrors(ajv)
9+
// *** TODO: We can drop this override once the frontmatter schema has been updated to work with AJV. ***
10+
ajv.addFormat('semver', {
11+
validate: (x) => semver.validRange(x),
12+
})
13+
14+
export function ajvValidate(schema) {
15+
return ajv.compile(schema)
16+
}

src/content-linter/tests/lint-code-languages.js

Lines changed: 0 additions & 18 deletions
This file was deleted.

src/content-linter/tests/lint-files.js

Lines changed: 2 additions & 222 deletions
Original file line numberDiff line numberDiff line change
@@ -4,23 +4,16 @@ import slash from 'slash'
44
import walk from 'walk-sync'
55
import { zip } from 'lodash-es'
66
import yaml from 'js-yaml'
7-
import Ajv from 'ajv'
8-
import addErrors from 'ajv-errors'
9-
import addFormats from 'ajv-formats'
107
import { fromMarkdown } from 'mdast-util-from-markdown'
118
import { visit } from 'unist-util-visit'
129
import fs from 'fs/promises'
1310
import { existsSync } from 'fs'
14-
import semver from 'semver'
1511
import { jest } from '@jest/globals'
1612

1713
import { frontmatter, deprecatedProperties } from '../../../lib/frontmatter.js'
1814
import languages from '#src/languages/lib/languages.js'
19-
import releaseNotesSchema from '../lib/release-notes-schema.js'
20-
import learningTracksSchema from '../lib/learning-tracks-schema.js'
2115
import { liquid } from '#src/content-render/index.js'
2216
import { getDiffFiles } from '../lib/diff-files.js'
23-
import { formatAjvErrors } from '../../../tests/helpers/schemas.js'
2417

2518
jest.useFakeTimers({ legacyFakeTimers: true })
2619

@@ -31,9 +24,6 @@ const contentDir = path.join(rootDir, 'content')
3124
const reusablesDir = path.join(rootDir, 'data/reusables')
3225
const variablesDir = path.join(rootDir, 'data/variables')
3326
const glossariesDir = path.join(rootDir, 'data/glossaries')
34-
const ghesReleaseNotesDir = path.join(rootDir, 'data/release-notes/enterprise-server')
35-
const ghaeReleaseNotesDir = path.join(rootDir, 'data/release-notes/github-ae')
36-
const learningTracks = path.join(rootDir, 'data/learning-tracks')
3727
const fbvDir = path.join(rootDir, 'data/features')
3828

3929
const languageCodes = Object.keys(languages)
@@ -217,7 +207,7 @@ const yamlWalkOptions = {
217207
}
218208

219209
// different lint rules apply to different content types
220-
let mdToLint, ymlToLint, ghesReleaseNotesToLint, ghaeReleaseNotesToLint, learningTracksToLint
210+
let mdToLint, ymlToLint
221211

222212
// compile lists of all the files we want to lint
223213

@@ -294,35 +284,11 @@ const FbvYamlAbsPaths = walk(fbvDir, yamlWalkOptions).sort()
294284
const FbvYamlRelPaths = FbvYamlAbsPaths.map((p) => slash(path.relative(rootDir, p)))
295285
const fbvTuples = zip(FbvYamlRelPaths, FbvYamlAbsPaths)
296286

297-
// GHES release notes
298-
const ghesReleaseNotesYamlAbsPaths = walk(ghesReleaseNotesDir, yamlWalkOptions).sort()
299-
const ghesReleaseNotesYamlRelPaths = ghesReleaseNotesYamlAbsPaths.map((p) =>
300-
slash(path.relative(rootDir, p)),
301-
)
302-
ghesReleaseNotesToLint = zip(ghesReleaseNotesYamlRelPaths, ghesReleaseNotesYamlAbsPaths)
303-
304-
// GHAE release notes
305-
const ghaeReleaseNotesYamlAbsPaths = walk(ghaeReleaseNotesDir, yamlWalkOptions).sort()
306-
const ghaeReleaseNotesYamlRelPaths = ghaeReleaseNotesYamlAbsPaths.map((p) =>
307-
slash(path.relative(rootDir, p)),
308-
)
309-
ghaeReleaseNotesToLint = zip(ghaeReleaseNotesYamlRelPaths, ghaeReleaseNotesYamlAbsPaths)
310-
311-
// Learning tracks
312-
const learningTracksYamlAbsPaths = walk(learningTracks, yamlWalkOptions).sort()
313-
const learningTracksYamlRelPaths = learningTracksYamlAbsPaths.map((p) =>
314-
slash(path.relative(rootDir, p)),
315-
)
316-
learningTracksToLint = zip(learningTracksYamlRelPaths, learningTracksYamlAbsPaths)
317-
318287
// Put all the yaml files together
319288
ymlToLint = [].concat(
320289
variableYamlTuples, // These "tuples" not tested independently; they are only tested as part of ymlToLint.
321290
glossariesYamlTuples,
322291
fbvTuples,
323-
ghesReleaseNotesToLint,
324-
ghaeReleaseNotesToLint,
325-
learningTracksToLint,
326292
)
327293

328294
function formatLinkError(message, links) {
@@ -361,19 +327,9 @@ if (diffFiles.length > 0) {
361327
)
362328
mdToLint = filterFiles(mdToLint)
363329
ymlToLint = filterFiles(ymlToLint)
364-
ghesReleaseNotesToLint = filterFiles(ghesReleaseNotesToLint)
365-
ghaeReleaseNotesToLint = filterFiles(ghaeReleaseNotesToLint)
366-
learningTracksToLint = filterFiles(learningTracksToLint)
367330
}
368331

369-
if (
370-
mdToLint.length +
371-
ymlToLint.length +
372-
ghesReleaseNotesToLint.length +
373-
ghaeReleaseNotesToLint.length +
374-
learningTracksToLint.length <
375-
1
376-
) {
332+
if (mdToLint.length + ymlToLint.length < 1) {
377333
// With this in place, at least one `test()` is called and you don't
378334
// get the `Your test suite must contain at least one test.` error
379335
// from `jest`.
@@ -382,18 +338,6 @@ if (
382338
})
383339
}
384340

385-
// ajv for schema validation tests
386-
const ajv = new Ajv({ allErrors: true, allowUnionTypes: true })
387-
addFormats(ajv)
388-
addErrors(ajv)
389-
// *** TODO: We can drop this override once the frontmatter schema has been updated to work with AJV. ***
390-
ajv.addFormat('semver', {
391-
validate: (x) => semver.validRange(x),
392-
})
393-
// *** End TODO ***
394-
const ghesValidate = ajv.compile(releaseNotesSchema)
395-
const learningTracksValidate = ajv.compile(learningTracksSchema)
396-
397341
describe('lint markdown content', () => {
398342
if (mdToLint.length < 1) return
399343

@@ -881,167 +825,3 @@ describe('lint yaml content', () => {
881825
})
882826
})
883827
})
884-
885-
describe('lint GHES release notes', () => {
886-
if (ghesReleaseNotesToLint.length < 1) return
887-
describe.each(ghesReleaseNotesToLint)('%s', (yamlRelPath, yamlAbsPath) => {
888-
let dictionary
889-
let dictionaryError = false
890-
891-
beforeAll(async () => {
892-
const fileContents = await fs.readFile(yamlAbsPath, 'utf8')
893-
try {
894-
dictionary = yaml.load(fileContents, { filename: yamlRelPath })
895-
} catch (error) {
896-
dictionaryError = error
897-
}
898-
})
899-
900-
it('can be parsed as a single yaml document', () => {
901-
expect(dictionaryError).toBe(false)
902-
})
903-
904-
it('matches the schema', () => {
905-
const valid = ghesValidate(dictionary)
906-
let errors
907-
908-
if (!valid) {
909-
errors = formatAjvErrors(ghesValidate.errors)
910-
}
911-
912-
expect(valid, errors).toBe(true)
913-
})
914-
915-
it('contains valid liquid', () => {
916-
const { intro, sections } = dictionary
917-
let toLint = { intro }
918-
for (const key in sections) {
919-
const section = sections[key]
920-
const label = `sections.${key}`
921-
section.forEach((part) => {
922-
if (Array.isArray(part)) {
923-
toLint = { ...toLint, ...{ [label]: section.join('\n') } }
924-
} else {
925-
for (const prop in section) {
926-
toLint = { ...toLint, ...{ [`${label}.${prop}`]: section[prop] } }
927-
}
928-
}
929-
})
930-
}
931-
932-
for (const key in toLint) {
933-
if (!toLint[key]) continue
934-
expect(() => liquid.parse(toLint[key]), `${key} contains invalid liquid`).not.toThrow()
935-
}
936-
})
937-
})
938-
})
939-
940-
describe('lint GHAE release notes', () => {
941-
if (ghaeReleaseNotesToLint.length < 1) return
942-
const currentWeeksFound = []
943-
describe.each(ghaeReleaseNotesToLint)('%s', (yamlRelPath, yamlAbsPath) => {
944-
let dictionary
945-
let dictionaryError = false
946-
947-
beforeAll(async () => {
948-
const fileContents = await fs.readFile(yamlAbsPath, 'utf8')
949-
try {
950-
dictionary = yaml.load(fileContents, { filename: yamlRelPath })
951-
} catch (error) {
952-
dictionaryError = error
953-
}
954-
})
955-
956-
it('can be parsed as a single yaml document', () => {
957-
expect(dictionaryError).toBe(false)
958-
})
959-
960-
it('matches the schema', () => {
961-
const valid = ghesValidate(dictionary)
962-
let errors
963-
964-
if (!valid) {
965-
errors = formatAjvErrors(ghesValidate.errors)
966-
}
967-
968-
expect(valid, errors).toBe(true)
969-
})
970-
971-
it('does not have more than one yaml file with currentWeek set to true', () => {
972-
if (dictionary.currentWeek) currentWeeksFound.push(yamlRelPath)
973-
const errorMessage = `Found more than one file with currentWeek set to true: ${currentWeeksFound.join(
974-
'\n',
975-
)}`
976-
expect(currentWeeksFound.length, errorMessage).not.toBeGreaterThan(1)
977-
})
978-
979-
it('contains valid liquid', () => {
980-
const { intro, sections } = dictionary
981-
let toLint = { intro }
982-
for (const key in sections) {
983-
const section = sections[key]
984-
const label = `sections.${key}`
985-
section.forEach((part) => {
986-
if (Array.isArray(part)) {
987-
toLint = { ...toLint, ...{ [label]: section.join('\n') } }
988-
} else {
989-
for (const prop in section) {
990-
toLint = { ...toLint, ...{ [`${label}.${prop}`]: section[prop] } }
991-
}
992-
}
993-
})
994-
}
995-
996-
for (const key in toLint) {
997-
if (!toLint[key]) continue
998-
expect(() => liquid.parse(toLint[key]), `${key} contains invalid liquid`).not.toThrow()
999-
}
1000-
})
1001-
})
1002-
})
1003-
1004-
describe('lint learning tracks', () => {
1005-
if (learningTracksToLint.length < 1) return
1006-
1007-
describe.each(learningTracksToLint)('%s', (yamlRelPath, yamlAbsPath) => {
1008-
let dictionary
1009-
let dictionaryError = false
1010-
1011-
beforeAll(async () => {
1012-
const fileContents = await fs.readFile(yamlAbsPath, 'utf8')
1013-
try {
1014-
dictionary = yaml.load(fileContents, { filename: yamlRelPath })
1015-
} catch (error) {
1016-
dictionaryError = error
1017-
}
1018-
})
1019-
1020-
it('can be parsed as a single yaml document', () => {
1021-
expect(dictionaryError).toBe(false)
1022-
})
1023-
1024-
it('matches the schema', () => {
1025-
const valid = learningTracksValidate(dictionary)
1026-
let errors
1027-
1028-
if (!valid) {
1029-
errors = formatAjvErrors(learningTracksValidate.errors)
1030-
}
1031-
1032-
expect(valid, errors).toBe(true)
1033-
})
1034-
1035-
it('contains valid liquid', () => {
1036-
const toLint = []
1037-
Object.values(dictionary).forEach(({ title, description }) => {
1038-
toLint.push(title)
1039-
toLint.push(description)
1040-
})
1041-
1042-
toLint.forEach((element) => {
1043-
expect(() => liquid.parse(element), `${element} contains invalid liquid`).not.toThrow()
1044-
})
1045-
})
1046-
})
1047-
})

src/content-linter/tests/lint-secret-scanning-data.js

Lines changed: 0 additions & 41 deletions
This file was deleted.

0 commit comments

Comments
 (0)