1
0
mirror of synced 2026-01-10 18:02:53 -05:00

Merge pull request #28310 from github/validate-versioning

Validate versioning
This commit is contained in:
Sarah Schneider
2022-06-10 15:15:18 -04:00
committed by GitHub
24 changed files with 109 additions and 84 deletions

View File

@@ -7,7 +7,7 @@ redirect_from:
- /actions/deployment/security-hardening-your-deployments/using-oidc-with-your-reusable-workflows
versions:
fpt: '*'
ghae: issue-4757-and-5856
ghae: issue-4757
ghec: '*'
ghes: '>=3.5'
type: how_to

View File

@@ -6,8 +6,8 @@ versions:
ghes: '*'
ghae: '*'
ghec: '*'
redirect_from:
- /github/writing-on-github/working-with-advanced-formatting/organizing-information-with-collapsed-sections
redirect_from:
- /github/writing-on-github/working-with-advanced-formatting/organizing-information-with-collapsed-sections
shortTitle: Collapsed sections
---
## Creating a collapsed section

View File

@@ -6,8 +6,8 @@ versions:
ghes: '*'
ghae: '*'
ghec: '*'
redirect_from:
- /github/writing-on-github/working-with-advanced-formatting/using-keywords-in-issues-and-pull-requests
redirect_from:
- /github/writing-on-github/working-with-advanced-formatting/using-keywords-in-issues-and-pull-requests
topics:
- Issues
- Pull requests

View File

@@ -45,7 +45,7 @@ versions:
## 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-files.js`](/tests/linting/lint-files.js).
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).
## Script to remove feature tags

View File

@@ -16,6 +16,7 @@ const plans = [
releases: [latestNonNumberedRelease],
latestRelease: latestNonNumberedRelease,
nonEnterpriseDefault: true, // permanent way to refer to this plan if the name changes
hasNumberedReleases: false,
openApiBaseName: 'api.github.com', // used for REST
miscBaseName: 'dotcom', // used for GraphQL and webhooks
},
@@ -25,6 +26,7 @@ const plans = [
shortName: 'ghec',
releases: [latestNonNumberedRelease],
latestRelease: latestNonNumberedRelease,
hasNumberedReleases: false,
openApiBaseName: 'api.github.com',
miscBaseName: 'ghec',
},
@@ -44,8 +46,11 @@ const plans = [
shortName: 'ghae',
releases: [latestNonNumberedRelease],
latestRelease: latestNonNumberedRelease,
hasNumberedReleases: false,
openApiBaseName: 'github.ae',
miscBaseName: 'ghae',
allowedFrontmatterPattern: '^issue-\\d+?$',
allowedInlinePattern: '^ghae-issue-\\d+?$',
},
]

View File

@@ -14,13 +14,6 @@ const layoutNames = [
'release-notes',
false,
]
const semverValidRange = semver.validRange
const semverRange = {
type: 'string',
conform: semverValidRange,
message: 'Must be a valid SemVer range',
}
const versionObjs = Object.values(allVersions)
const guideTypes = ['overview', 'quick_start', 'tutorial', 'how_to', 'reference']
const featureVersions = fs
@@ -246,19 +239,44 @@ const featureVersionsProp = {
},
}
const asteriskPattern = /^\*$/
schema.properties.versions = {
type: ['object', 'string'], // allow a '*' string to indicate all versions
required: true,
properties: versionObjs.reduce((acc, versionObj) => {
acc[versionObj.plan] = semverRange
acc[versionObj.shortName] = semverRange
additionalProperties: false, // don't allow any versions in FM that aren't defined in lib/all-versions
properties: Object.values(allVersions).reduce((acc, versionObj) => {
acc[versionObj.plan] = getValidProps(versionObj)
acc[versionObj.shortName] = getValidProps(versionObj)
return acc
}, featureVersionsProp),
}
// Support 'github-ae': next
schema.properties.versions.properties['github-ae'] = 'next'
schema.properties.versions.properties.ghae = 'next'
function getValidProps(versionObj) {
const valid = { type: 'string' }
// The properties attached to versionObj are defined in lib/all-versions.js.
// If a version has no numbered releases or exception pattern, the only valid value is '*'.
if (!(versionObj.hasNumberedReleases || versionObj.allowedFrontmatterPattern)) {
valid.pattern = asteriskPattern
valid.message = `Must have a value of '*'`
}
// If a version has an exception pattern, both '*' and the exception pattern are valid.
if (versionObj.allowedFrontmatterPattern) {
valid.pattern = new RegExp(`${asteriskPattern.source}|${versionObj.allowedFrontmatterPattern}`)
valid.message = `Must have a value of '*' or 'issue-###', where ### is an integer`
}
// If a version has numbered releases, any semver range is valid. Note '*' is a valid semver range.
if (versionObj.hasNumberedReleases) {
valid.conform = semver.validRange
valid.message = 'Must be a valid SemVer range'
}
return valid
}
function frontmatter(markdown, opts = {}) {
const defaults = {

View File

@@ -1,5 +0,0 @@
---
title: Page versioned for next GitHub AE release
versions:
github-ae: 'next'
---

View File

@@ -0,0 +1,7 @@
---
title: This is an article
intro: I have invalid versions frontmatter
versions:
fpt: '*'
ghae: 'issue-foo' # Only issue-<number> is allowed, per lib/all-versions.js
---

View File

@@ -86,5 +86,14 @@ export default {
description: 'final name used to map GraphQL and webhook schema names to the current version',
type: 'string',
},
allowedFrontmatterPattern: {
desciption: 'pattern used in a regex to validate versions frontmatter in lib/frontmatter.js',
type: 'string',
},
allowedInlinePattern: {
desciption:
'pattern used in a regex to valid ifversion tag in tests/linting/lint-versioning.js',
type: 'string',
},
},
}

View File

@@ -410,15 +410,13 @@ describe('lint markdown content', () => {
isEarlyAccess,
isSitePolicy,
hasExperimentalAlternative,
frontmatterErrors,
frontmatterData
beforeAll(async () => {
const fileContents = await fs.readFile(markdownAbsPath, 'utf8')
const { data, content: bodyContent, errors } = frontmatter(fileContents)
const { data, content: bodyContent } = frontmatter(fileContents)
content = bodyContent
frontmatterErrors = errors
frontmatterData = data
ast = fromMarkdown(content)
isHidden = data.hidden === true
@@ -611,13 +609,6 @@ describe('lint markdown content', () => {
})
if (!markdownRelPath.includes('data/reusables')) {
test('contains valid frontmatter', () => {
const errorMessage = frontmatterErrors
.map((error) => `- [${error.property}]: ${error.actual}, ${error.message}`)
.join('\n')
expect(frontmatterErrors.length, errorMessage).toBe(0)
})
test('frontmatter contains valid liquid', async () => {
const fmKeysWithLiquid = ['title', 'shortTitle', 'intro', 'product', 'permission'].filter(
(key) => Boolean(frontmatterData[key])

View File

@@ -2,7 +2,7 @@ import { jest } from '@jest/globals'
import fs from 'fs/promises'
import revalidator from 'revalidator'
import semver from 'semver'
import { allVersions } from '../../lib/all-versions.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'
@@ -11,18 +11,20 @@ import walkFiles from '../../script/helpers/walk-files'
import frontmatter from '../../lib/frontmatter.js'
import loadSiteData from '../../lib/site-data.js'
const versionShortNames = Object.values(allVersions).map((v) => v.shortName)
const versionShortNameExceptions = ['ghae-next', 'ghae-issue-']
/*
NOTE: This test suite does NOT validate the `versions` frontmatter in content files.
That's because lib/page.js validates frontmatter when loading all the pages (which happens
when running npm start or tests) and throws an error immediately if there are any issues.
This test suite DOES validate the data/features `versions` according to the same FM schema.
Some tests/unit/page.js tests also exercise the frontmatter validation.
*/
jest.useFakeTimers('legacy')
const siteData = loadSiteData()
const featureVersions = Object.entries(siteData.en.site.data.features)
const featureVersionNames = featureVersions.map((fv) => fv[0])
const versionKeywords = versionShortNames
.concat(['currentVersion', 'enterpriseServerReleases'])
.concat(featureVersionNames)
const allowedVersionNames = Object.keys(allVersionShortnames).concat(featureVersionNames)
// Make sure data/features/*.yml contains valid versioning.
describe('lint feature versions', () => {
@@ -79,7 +81,7 @@ describe('lint Liquid versioning', () => {
// Now that `ifversion` supports feature-based versioning, we should have few other `if` tags.
test('ifversion, not if, is used for versioning', async () => {
const ifsForVersioning = ifConditionals.filter((cond) =>
versionKeywords.some((keyword) => cond.includes(keyword))
allowedVersionNames.some((keyword) => cond.includes(keyword))
)
const errorMessage = `Found ${
ifsForVersioning.length
@@ -98,12 +100,16 @@ describe('lint Liquid versioning', () => {
})
})
// Return true if the shortname in the conditional is supported (fpt, ghec, ghes, ghae, all feature names).
// If not, see if the shortname matches any exception pattern defined in lib/all-versions.js.
function validateVersion(version) {
return (
versionShortNames.includes(version) ||
versionShortNameExceptions.some((exception) => version.startsWith(exception)) ||
featureVersionNames.includes(version)
const isSupported = allowedVersionNames.includes(version)
const isException = Object.values(allVersions).some(
(v) => v.allowedInlinePattern && new RegExp(v.allowedInlinePattern).test(version)
)
const isValid = isSupported || isException
return isValid
}
function validateIfversionConditionals(conds) {

View File

@@ -297,24 +297,6 @@ describe('Page class', () => {
return page.render(context)
}).not.toThrow()
})
test('support next GitHub AE version in frontmatter', async () => {
// This fixture has `github-ae: 'next'` hardcoded in the frontmatter
const page = await Page.init({
relativePath: 'page-versioned-for-ghae-next.md',
basePath: path.join(__dirname, '../fixtures'),
languageCode: 'en',
})
// set version to @latest
const context = {
currentVersion: 'github-ae@latest',
currentLanguage: 'en',
}
context.currentPath = `/${context.currentLanguage}/${context.currentVersion}`
await expect(() => {
return page.render(context)
}).not.toThrow()
})
})
test('preserves `languageCode`', async () => {
@@ -794,6 +776,18 @@ describe('catches errors thrown in Page class', () => {
await expect(getPage).rejects.toThrowError('versions')
})
test('invalid versions frontmatter', async () => {
async function getPage() {
return await Page.init({
relativePath: 'page-with-invalid-product-version.md',
basePath: path.join(__dirname, '../fixtures'),
languageCode: 'en',
})
}
await expect(getPage).rejects.toThrowError('versions')
})
test('English page with a version in frontmatter that its parent product is not available in', async () => {
async function getPage() {
return await Page.init({

View File

@@ -7,7 +7,7 @@ redirect_from:
- /actions/deployment/security-hardening-your-deployments/using-oidc-with-your-reusable-workflows
versions:
fpt: '*'
ghae: issue-4757-and-5856
ghae: issue-4757
ghec: '*'
ghes: '>=3.5'
type: how_to

View File

@@ -6,8 +6,8 @@ versions:
ghes: '*'
ghae: '*'
ghec: '*'
redirect_from:
- /github/writing-on-github/working-with-advanced-formatting/organizing-information-with-collapsed-sections
redirect_from:
- /github/writing-on-github/working-with-advanced-formatting/organizing-information-with-collapsed-sections
shortTitle: Secciones colapsadas
---

View File

@@ -6,8 +6,8 @@ versions:
ghes: '*'
ghae: '*'
ghec: '*'
redirect_from:
- /github/writing-on-github/working-with-advanced-formatting/using-keywords-in-issues-and-pull-requests
redirect_from:
- /github/writing-on-github/working-with-advanced-formatting/using-keywords-in-issues-and-pull-requests
topics:
- Issues
- Pull requests

View File

@@ -7,7 +7,7 @@ redirect_from:
- /actions/deployment/security-hardening-your-deployments/using-oidc-with-your-reusable-workflows
versions:
fpt: '*'
ghae: issue-4757-and-5856
ghae: issue-4757
ghec: '*'
ghes: '>=3.5'
type: how_to

View File

@@ -6,8 +6,8 @@ versions:
ghes: '*'
ghae: '*'
ghec: '*'
redirect_from:
- /github/writing-on-github/working-with-advanced-formatting/organizing-information-with-collapsed-sections
redirect_from:
- /github/writing-on-github/working-with-advanced-formatting/organizing-information-with-collapsed-sections
shortTitle: Collapsed sections
---

View File

@@ -6,8 +6,8 @@ versions:
ghes: '*'
ghae: '*'
ghec: '*'
redirect_from:
- /github/writing-on-github/working-with-advanced-formatting/using-keywords-in-issues-and-pull-requests
redirect_from:
- /github/writing-on-github/working-with-advanced-formatting/using-keywords-in-issues-and-pull-requests
topics:
- Issues
- Pull requests

View File

@@ -7,7 +7,7 @@ redirect_from:
- /actions/deployment/security-hardening-your-deployments/using-oidc-with-your-reusable-workflows
versions:
fpt: '*'
ghae: issue-4757-and-5856
ghae: issue-4757
ghec: '*'
ghes: '>=3.5'
type: how_to

View File

@@ -6,8 +6,8 @@ versions:
ghes: '*'
ghae: '*'
ghec: '*'
redirect_from:
- /github/writing-on-github/working-with-advanced-formatting/organizing-information-with-collapsed-sections
redirect_from:
- /github/writing-on-github/working-with-advanced-formatting/organizing-information-with-collapsed-sections
shortTitle: Seções colapsadas
---

View File

@@ -6,8 +6,8 @@ versions:
ghes: '*'
ghae: '*'
ghec: '*'
redirect_from:
- /github/writing-on-github/working-with-advanced-formatting/using-keywords-in-issues-and-pull-requests
redirect_from:
- /github/writing-on-github/working-with-advanced-formatting/using-keywords-in-issues-and-pull-requests
topics:
- Issues
- Pull requests

View File

@@ -7,7 +7,7 @@ redirect_from:
- /actions/deployment/security-hardening-your-deployments/using-oidc-with-your-reusable-workflows
versions:
fpt: '*'
ghae: issue-4757-and-5856
ghae: issue-4757
ghec: '*'
ghes: '>=3.5'
type: how_to

View File

@@ -6,8 +6,8 @@ versions:
ghes: '*'
ghae: '*'
ghec: '*'
redirect_from:
- /github/writing-on-github/working-with-advanced-formatting/organizing-information-with-collapsed-sections
redirect_from:
- /github/writing-on-github/working-with-advanced-formatting/organizing-information-with-collapsed-sections
shortTitle: 折叠部分
---

View File

@@ -6,8 +6,8 @@ versions:
ghes: '*'
ghae: '*'
ghec: '*'
redirect_from:
- /github/writing-on-github/working-with-advanced-formatting/using-keywords-in-issues-and-pull-requests
redirect_from:
- /github/writing-on-github/working-with-advanced-formatting/using-keywords-in-issues-and-pull-requests
topics:
- Issues
- Pull requests