зеркало из https://github.com/github/docs.git
Content linting dir (#36833)
Co-authored-by: Rachael Sewell <rachmari@github.com>
This commit is contained in:
Родитель
61fd4ca80b
Коммит
e8d75f960e
|
@ -47,7 +47,7 @@ jobs:
|
|||
{ name: 'graphql', path: 'src/graphql/tests', },
|
||||
{ name: 'rest', path: 'src/rest/tests', },
|
||||
{ name: 'webhooks', path: 'src/webhooks/tests', },
|
||||
{ name: 'linting', path: 'tests/linting', },
|
||||
{ name: 'linting', path: 'src/content-linter/tests', },
|
||||
{ name: 'meta', path: 'tests/meta', },
|
||||
{ name: 'routing', path: 'tests/routing', },
|
||||
{ name: 'rendering', path: 'tests/rendering', },
|
||||
|
@ -140,7 +140,7 @@ jobs:
|
|||
echo $DIFF
|
||||
|
||||
# So that becomes a string like `foo.js path/bar.md`
|
||||
# Must to do this because the list of files can be HUGE. Especially
|
||||
# Must do this because the list of files can be HUGE. Especially
|
||||
# in a repo-sync when there are lots of translation files involved.
|
||||
echo __ format, write to get_diff_files.txt __
|
||||
echo $DIFF | tr '\n' ' ' > get_diff_files.txt
|
||||
|
|
|
@ -40,7 +40,7 @@ You cannot use `feature:` to specify multiple concurrent versions, as this is no
|
|||
|
||||
## Schema enforcement
|
||||
|
||||
The schema for validating the feature versioning lives in [`tests/helpers/schemas/feature-versions-schema.js`](/tests/helpers/schemas/feature-versions-schema.js) and is exercised by [`tests/linting/lint-versioning.js`](/tests/linting/lint-versioning.js).
|
||||
The schema for validating the feature versioning lives in [`src/content-linter/lib/feature-versions-schema.js`](src/content-linter/lib/feature-versions-schema.js) and is exercised by [`tests/linting/lint-versioning.js`](tests/linting/lint-versioning.js).
|
||||
|
||||
## Script to remove feature tags
|
||||
|
||||
|
|
|
@ -53,4 +53,4 @@ If the `versions` property is not included, it's assumed the track is available
|
|||
|
||||
## Schema enforcement
|
||||
|
||||
The schema for validating the learning track YAML lives in [`tests/helpers/schemas/learning-tracks-schema.js`](tests/helpers/schemas/learning-tracks-schema.js) and is exercised by [`tests/content/lint-files.js`](tests/content/lint-files.js).
|
||||
The schema for validating the learning track YAML lives in [`src/content-linter/lib/learning-tracks-schema.js`](src/content-linter/lib/learning-tracks-schema.js) and is exercised by [`tests/content/lint-files.js`](tests/content/lint-files.js).
|
||||
|
|
|
@ -41,6 +41,6 @@ The release notes page has a custom design with CSS in `stylesheets/release-note
|
|||
|
||||
### Schema
|
||||
|
||||
The schema that validates the YAML data lives in `tests/helpers/schemas/release-notes-schema.js`. See the schema file to find out the required and optional properties.
|
||||
The schema that validates the YAML data lives in `src/content-linter/lib/release-notes-schema.js`. See the schema file to find out the required and optional properties.
|
||||
|
||||
The schema is exercised by a test in `tests/linting/lint-files.js`. The test will fail if the data does not pass validation.
|
||||
The schema is exercised by a test in `src/content-linter/tests/lint-files.js`. The test will fail if the data does not pass validation.
|
||||
|
|
|
@ -30,6 +30,6 @@ The release notes page has a custom design with CSS in `stylesheets/release-note
|
|||
|
||||
### Schema
|
||||
|
||||
The schema that validates the YAML data lives in `tests/helpers/schemas/release-notes-schema.js`. See the schema file to find out the required and optional properties.
|
||||
The schema that validates the YAML data lives in `src/content-linter/lib/release-notes-schema.js`. See the schema file to find out the required and optional properties.
|
||||
|
||||
The schema is exercised by a test in `tests/linting/lint-files.js`. The test will fail if the data does not pass validation.
|
||||
The schema is exercised by a test in `src/content-linter/tests/lint-files.js`. The test will fail if the data does not pass validation.
|
||||
|
|
|
@ -189,7 +189,7 @@
|
|||
"fixture-test": "cross-env ROOT=tests/fixtures npm test -- tests/rendering-fixtures",
|
||||
"index-test-fixtures": "node src/search/scripts/index-elasticsearch.js -l en -l ja -V ghae -V dotcom --index-prefix tests -- src/search/tests/fixtures/search-indexes",
|
||||
"lint": "eslint '**/*.{js,mjs,ts,tsx}'",
|
||||
"lint-translation": "cross-env NODE_OPTIONS=--experimental-vm-modules jest tests/linting/lint-files.js",
|
||||
"lint-translation": "cross-env NODE_OPTIONS=--experimental-vm-modules jest src/content-linter/tests/lint-files.js",
|
||||
"playwright-test": "playwright test --project=\"Google Chrome\"",
|
||||
"prepare": "husky install",
|
||||
"prettier": "prettier -w \"**/*.{ts,tsx,js,mjs,scss,yml,yaml}\"",
|
||||
|
|
|
@ -0,0 +1,21 @@
|
|||
# Content Linter
|
||||
|
||||
## Linting Tests
|
||||
- [lint-files](lint-files.js): Linter for `content`, `data/reusables`, `data/variables`, `data/glossaries`, `data/release-notes`, `data/learning-tracks`, and `data/features`. This lints markdown in the `content` and `data` directories, including early-access, GitHub Enterprise Server release notes, and yaml content. It checks for:
|
||||
- No placeholder strings
|
||||
- Hidden docs
|
||||
- Transcripts
|
||||
- Valid links
|
||||
- Yaml content
|
||||
- Early Access controls
|
||||
- Hard-coded code/versions/domains
|
||||
- Valid schema
|
||||
- Valid liquid
|
||||
- Valid syntax
|
||||
- Valid frontmatter
|
||||
- [lint-secret-scanning-data](lint-secret-scanning-data.js): Linter for `data/secret-scanning.yml`, which validates that the secret scanning data matches its schema.
|
||||
- [lint-versioning](lint-versioning.js): This validates the `data/features` `versions` according to the same frontmatter schema.
|
||||
- [category-pages](category-pages.js): This checks that the `children` frontmatter has a matching markdown article.
|
||||
- [liquid-line-breaks](liquid-line-breaks.js): This will match Liquid variable references that contain at least one line break
|
||||
between the variable reference and either the `{{` or `}}` tag boundaries.
|
||||
- [site-data-references](site-data-references.js): Validates that any data reference found in the English content files is defined and has a value.
|
|
@ -2,20 +2,21 @@ import { fileURLToPath } from 'url'
|
|||
import path from 'path'
|
||||
import fs from 'fs'
|
||||
import walk from 'walk-sync'
|
||||
import matter from '../../lib/read-frontmatter.js'
|
||||
import { zip, difference } from 'lodash-es'
|
||||
import GithubSlugger from 'github-slugger'
|
||||
import { decode } from 'html-entities'
|
||||
import renderContent from '../../lib/render-content/index.js'
|
||||
import getApplicableVersions from '../../lib/get-applicable-versions.js'
|
||||
import contextualize from '../../middleware/context.js'
|
||||
import shortVersions from '../../middleware/contextualizers/short-versions.js'
|
||||
|
||||
import matter from '../../../lib/read-frontmatter.js'
|
||||
import renderContent from '../../../lib/render-content/index.js'
|
||||
import getApplicableVersions from '../../../lib/get-applicable-versions.js'
|
||||
import contextualize from '../../../middleware/context.js'
|
||||
import shortVersions from '../../../middleware/contextualizers/short-versions.js'
|
||||
|
||||
const __dirname = path.dirname(fileURLToPath(import.meta.url))
|
||||
|
||||
const slugger = new GithubSlugger()
|
||||
|
||||
const contentDir = path.join(__dirname, '../../content')
|
||||
const contentDir = path.join(__dirname, '../../../content')
|
||||
|
||||
describe('category pages', () => {
|
||||
const walkOptions = {
|
23
tests/linting/lint-files.js → src/content-linter/tests/lint-files.js
Normal file → Executable file
23
tests/linting/lint-files.js → src/content-linter/tests/lint-files.js
Normal file → Executable file
|
@ -12,17 +12,18 @@ import { visit } from 'unist-util-visit'
|
|||
import fs from 'fs/promises'
|
||||
import { existsSync } from 'fs'
|
||||
import semver from 'semver'
|
||||
import { frontmatter, deprecatedProperties } from '../../lib/frontmatter.js'
|
||||
import languages from '../../lib/languages.js'
|
||||
import { tags } from '../../lib/liquid-tags/extended-markdown.js'
|
||||
import releaseNotesSchema from '../helpers/schemas/release-notes-schema.js'
|
||||
import learningTracksSchema from '../helpers/schemas/learning-tracks-schema.js'
|
||||
import renderContent from '../../lib/render-content/index.js'
|
||||
import getApplicableVersions from '../../lib/get-applicable-versions.js'
|
||||
import { allVersions } from '../../lib/all-versions.js'
|
||||
import { jest } from '@jest/globals'
|
||||
import { getDiffFiles } from '../helpers/diff-files.js'
|
||||
import { formatAjvErrors } from '../helpers/schemas.js'
|
||||
|
||||
import { frontmatter, deprecatedProperties } from '../../../lib/frontmatter.js'
|
||||
import languages from '../../../lib/languages.js'
|
||||
import { tags } from '../../../lib/liquid-tags/extended-markdown.js'
|
||||
import releaseNotesSchema from '../lib/release-notes-schema.js'
|
||||
import learningTracksSchema from '../lib/learning-tracks-schema.js'
|
||||
import renderContent from '../../../lib/render-content/index.js'
|
||||
import getApplicableVersions from '../../../lib/get-applicable-versions.js'
|
||||
import { allVersions } from '../../../lib/all-versions.js'
|
||||
import { getDiffFiles } from '../lib/diff-files.js'
|
||||
import { formatAjvErrors } from '../../../tests/helpers/schemas.js'
|
||||
|
||||
jest.useFakeTimers({ legacyFakeTimers: true })
|
||||
|
||||
|
@ -31,7 +32,7 @@ const enterpriseServerVersions = Object.keys(allVersions).filter((v) =>
|
|||
v.startsWith('enterprise-server@')
|
||||
)
|
||||
|
||||
const rootDir = path.join(__dirname, '../..')
|
||||
const rootDir = path.join(__dirname, '../../..')
|
||||
const contentDir = path.join(rootDir, 'content')
|
||||
const reusablesDir = path.join(rootDir, 'data/reusables')
|
||||
const variablesDir = path.join(rootDir, 'data/variables')
|
|
@ -4,7 +4,9 @@ import { get } from 'lodash-es'
|
|||
import Ajv from 'ajv'
|
||||
import addErrors from 'ajv-errors'
|
||||
import semver from 'semver'
|
||||
import schema from '../helpers/schemas/secret-scanning-schema.js'
|
||||
|
||||
import schema from '../lib/secret-scanning-schema.js'
|
||||
|
||||
const data = yaml.load(fs.readFileSync('data/secret-scanning.yml', 'utf8'))
|
||||
|
||||
const ajv = new Ajv({ allErrors: true, allowUnionTypes: true })
|
|
@ -3,14 +3,15 @@ import fs from 'fs/promises'
|
|||
import Ajv from 'ajv'
|
||||
import addErrors from 'ajv-errors'
|
||||
import semver from 'semver'
|
||||
import { allVersions, allVersionShortnames } from '../../lib/all-versions.js'
|
||||
import { supported, next, nextNext, deprecated } from '../../lib/enterprise-server-releases.js'
|
||||
import { getLiquidConditionals } from '../../script/helpers/get-liquid-conditionals.js'
|
||||
import allowedVersionOperators from '../../lib/liquid-tags/ifversion-supported-operators.js'
|
||||
import featureVersionsSchema from '../helpers/schemas/feature-versions-schema.js'
|
||||
import walkFiles from '../../script/helpers/walk-files'
|
||||
import { getDeepDataByLanguage } from '../../lib/get-data.js'
|
||||
import { formatAjvErrors } from '../helpers/schemas.js'
|
||||
|
||||
import { allVersions, allVersionShortnames } from '../../../lib/all-versions.js'
|
||||
import { supported, next, nextNext, deprecated } from '../../../lib/enterprise-server-releases.js'
|
||||
import { getLiquidConditionals } from '../../../script/helpers/get-liquid-conditionals.js'
|
||||
import allowedVersionOperators from '../../../lib/liquid-tags/ifversion-supported-operators.js'
|
||||
import featureVersionsSchema from '../lib/feature-versions-schema.js'
|
||||
import walkFiles from '../../../script/helpers/walk-files.js'
|
||||
import { getDeepDataByLanguage } from '../../../lib/get-data.js'
|
||||
import { formatAjvErrors } from '../../../tests/helpers/schemas.js'
|
||||
|
||||
/*
|
||||
NOTE: This test suite does NOT validate the `versions` frontmatter in content files.
|
|
@ -1,13 +1,14 @@
|
|||
import { fileURLToPath } from 'url'
|
||||
import path from 'path'
|
||||
import walk from 'walk-sync'
|
||||
import matter from '../../lib/read-frontmatter.js'
|
||||
import { zip } from 'lodash-es'
|
||||
import yaml from 'js-yaml'
|
||||
import fs from 'fs/promises'
|
||||
|
||||
import matter from '../../../lib/read-frontmatter.js'
|
||||
|
||||
const __dirname = path.dirname(fileURLToPath(import.meta.url))
|
||||
const rootDir = path.join(__dirname, '../..')
|
||||
const rootDir = path.join(__dirname, '../../..')
|
||||
const contentDir = path.join(rootDir, 'content')
|
||||
const reusablesDir = path.join(rootDir, 'data/reusables')
|
||||
const variablesDir = path.join(rootDir, 'data/variables')
|
|
@ -1,14 +1,13 @@
|
|||
import fs from 'fs/promises'
|
||||
import { fileURLToPath } from 'url'
|
||||
import path from 'path'
|
||||
|
||||
import { isEqual, uniqWith } from 'lodash-es'
|
||||
import { jest } from '@jest/globals'
|
||||
|
||||
import { loadPages } from '../../lib/page-data.js'
|
||||
import patterns from '../../lib/patterns.js'
|
||||
import frontmatter from '../../lib/read-frontmatter.js'
|
||||
import { getDataByLanguage, getDeepDataByLanguage } from '../../lib/get-data.js'
|
||||
import { loadPages } from '../../../lib/page-data.js'
|
||||
import patterns from '../../../lib/patterns.js'
|
||||
import frontmatter from '../../../lib/read-frontmatter.js'
|
||||
import { getDataByLanguage, getDeepDataByLanguage } from '../../../lib/get-data.js'
|
||||
|
||||
const __dirname = path.dirname(fileURLToPath(import.meta.url))
|
||||
|
||||
|
@ -56,7 +55,7 @@ describe('data references', () => {
|
|||
await Promise.all(
|
||||
pages.map(async (page) => {
|
||||
const metadataFile = path.join('content', page.relativePath)
|
||||
const fileContents = await fs.readFile(path.join(__dirname, '../..', metadataFile))
|
||||
const fileContents = await fs.readFile(path.join(__dirname, '../../..', metadataFile))
|
||||
const { data: metadata } = frontmatter(fileContents, { filepath: page.fullPath })
|
||||
const metadataRefs = getDataReferences(JSON.stringify(metadata))
|
||||
metadataRefs.forEach((key) => {
|
||||
|
@ -80,7 +79,7 @@ describe('data references', () => {
|
|||
reusables.map(async (reusablesPerFile) => {
|
||||
let reusableFile = path.join(
|
||||
__dirname,
|
||||
'../../data/reusables/',
|
||||
'../../../data/reusables/',
|
||||
getFilenameByValue(allReusables, reusablesPerFile)
|
||||
)
|
||||
reusableFile = await getFilepath(reusableFile)
|
||||
|
@ -108,7 +107,7 @@ describe('data references', () => {
|
|||
variables.map(async (variablesPerFile) => {
|
||||
let variableFile = path.join(
|
||||
__dirname,
|
||||
'../../data/variables/',
|
||||
'../../../data/variables/',
|
||||
getFilenameByValue(allVariables, variablesPerFile)
|
||||
)
|
||||
variableFile = await getFilepath(variableFile)
|
||||
|
@ -141,5 +140,5 @@ async function getFilepath(filepath) {
|
|||
}
|
||||
|
||||
// we only need the relative path
|
||||
return filepath.replace(path.join(__dirname, '../../'), '')
|
||||
return filepath.replace(path.join(__dirname, '../../../'), '')
|
||||
}
|
Загрузка…
Ссылка в новой задаче