1
0
mirror of synced 2025-12-19 18:10:59 -05:00

Remove superseded deprecation scripts (#55451)

This commit is contained in:
Rachael Sewell
2025-04-30 11:13:40 -07:00
committed by GitHub
parent 0af4954f45
commit 97c3236ff9
20 changed files with 12 additions and 1860 deletions

View File

@@ -57,7 +57,6 @@ jobs:
- events
- fixtures
- frame
- ghes-releases
- github-apps
- graphql
- landings

View File

@@ -19,7 +19,6 @@
"all-documents": "tsx src/content-render/scripts/all-documents/cli.ts",
"analyze-text": "tsx src/search/scripts/analyze-text.ts",
"analyze-comment": "tsx src/events/scripts/analyze-comment-cli.ts",
"archive-version": "tsx --max-old-space-size=16384 src/ghes-releases/scripts/archive-version.ts",
"build": "next build",
"check-content-type": "tsx src/workflows/check-content-type.ts",
"check-github-github-links": "tsx src/links/scripts/check-github-github-links.ts",
@@ -76,7 +75,6 @@
"ready-for-docs-review": "tsx src/workflows/ready-for-docs-review.ts",
"release-banner": "tsx src/ghes-releases/scripts/release-banner.js",
"reusables": "tsx src/content-render/scripts/reusables-cli.ts",
"remove-version-markup": "tsx src/ghes-releases/scripts/remove-version-markup.js",
"rendered-content-link-checker": "tsx src/links/scripts/rendered-content-link-checker.ts",
"rendered-content-link-checker-cli": "tsx src/links/scripts/rendered-content-link-checker-cli.ts",
"rest-dev": "tsx src/rest/scripts/update-files.js",

View File

@@ -54,15 +54,15 @@ To enable a new version of GHES on GitHub Docs, update the site's supported vers
- [ ] For `supported`, prepend the new version. For example, if the array contains 3.9, 3.8, 3.7, and 3.6, add 3.10:
```js
export const supported = ['3.10', '3.9', '3.8', '3.7', '3.6']
```
```js
export const supported = ["3.10", "3.9", "3.8", "3.7", "3.6"];
```
- [ ] For `releaseCandidate`, change the variable definition from `null` to the release version. For example, if the release version is 3.10:
```js
export const releaseCandidate = '3.10'
```
```js
export const releaseCandidate = "3.10";
```
- [ ] Add and commit the changes.
@@ -71,7 +71,7 @@ To enable a new version of GHES on GitHub Docs, update the site's supported vers
- [ ] Run the following script.
```shell
src/ghes-releases/scripts/sync-automated-pipeline-data.js
npm run deprecate-ghes -- pipelines
```
- [ ] Add and commit the changes.
@@ -101,6 +101,7 @@ Our link checker validates links the site. If links are broken immediately after
If you aren't familiar with the content with the broken link, consult the DRI for the content's focus area. See the [README](https://github.com/github/docs-content/blob/main/focus-areas/README.md) in `github/docs-content`.
For broken links due to in-progress work elsewhere in the docs, you can comment out problematic versioning temporarily by:
- using {% raw %}`{% comment %}`{% endraw %} tags in Liquid or
- prepending `#` in YAML front matter.
@@ -118,9 +119,9 @@ For content from the OpenAPI schema, note the affected content with broken links
1. Go to the [`index-general-search.yml` workflow](https://github.com/github/docs-internal/actions/workflows/index-general-search.yml)
1. Click on the **Run workflow** drop down and set the following parameters:
- `Branch:` set to the name of the publication branch
- `Version` set to the version you're publishing (e.g., `ghes-3.12` if you're publishing GHES 3.12)
- `Languages` left as default (blank, all languages. If time is a concern, can also set to just `en` and wait for the workflow to automatically include the other languages in later runs)
- `Branch:` set to the name of the publication branch
- `Version` set to the version you're publishing (e.g., `ghes-3.12` if you're publishing GHES 3.12)
- `Languages` left as default (blank, all languages. If time is a concern, can also set to just `en` and wait for the workflow to automatically include the other languages in later runs)
1. Click **Run workflow** and wait for the workflow to finish running, which can take up to 30 minutes.
_Note_: After performing these steps, search indices will be automatically updated when the workflow runs on `main`, once every 4 hours. However, it will not do so until you first complete the steps above which will manually create a search index for the new release.
@@ -135,7 +136,7 @@ After your publication PR's are passing, complete the following maintenance **da
1. Check out `main`, then pull the latest changes.
1. Check out your publication branch, <code>ghes-VERSION-rc</code>, then merge changes from `main`.
1. Check out your publication branch, <code>ghes-VERSION-rc</code>, then merge changes from `main`.
1. Push the changes.

View File

@@ -1,151 +0,0 @@
// See https://github.com/harttle/liquidjs/discussions/294#discussioncomment-305068
import { Tokenizer } from 'liquidjs'
const tokenize = (str) => {
const tokenizer = new Tokenizer(str)
return tokenizer.readTopLevelTokens()
}
// Return an array of just the conditional strings.
function getLiquidConditionals(str, tagNames) {
if (!tagNames) throw new Error(`Must provide a tag name!`)
if (typeof str !== 'string') throw new Error('Must provide a string!')
tagNames = Array.isArray(tagNames) ? tagNames : [tagNames]
return tokenize(str)
.filter((token) => tagNames.includes(token.name))
.map((token) => token.args)
}
// Return an array of objects, where the `conditional` prop contains the conditional string,
// and the `text` prop contains the contents between the start tag and the end tag.
function getLiquidConditionalsWithContent(str, tagName) {
if (!tagName) throw new Error(`Must provide a tag name!`)
if (typeof tagName !== 'string') throw new Error(`Must provide a single tag name as a string!`)
const numberOfTags = (str.match(new RegExp(`{%-? ${tagName}`, 'g')) || []).length
if (!numberOfTags) return []
const endTagName = tagName === 'ifversion' || tagName === 'elsif' ? 'endif' : `end${tagName}`
// Get the raw tokens, which includes versions, data tags, etc.,
// Also this captures start tags, content, and end tags as _individual_ tokens, but we want to group them.
const tokens = tokenize(str).map((token) => {
return {
conditional: token.name,
text: token.getText(),
position: token.getPosition(),
}
})
// Parse the raw tokens and group them, so that start tags, content, and end tags are
// all considered to be part of the same block, and return that block.
const grouped = groupTokens(tokens, tagName, endTagName)
// Run recursively so we can also capture nested conditionals.
const nestedConditionals = grouped.flatMap((group) => {
// Remove the start tag and the end tag so we are left with nested tags, if any.
const nested = group.text
.replace(group.conditional, '')
.split('')
.reverse()
.join('')
.replace(new RegExp(`{%-? ${endTagName} -?%}`), '')
.split('')
.reverse()
.join('')
const nestedGroups = getLiquidConditionalsWithContent(nested, tagName)
// Remove the start tag but NOT the end tag, so we are left with elsif tags and their endifs, if any.
const elsifs = group.text.replace(group.conditional, '')
const elsifGroups = getLiquidConditionalsWithContent(elsifs, 'elsif')
return [group].concat(nestedGroups, elsifGroups)
})
return nestedConditionals
}
function groupTokens(tokens, tagName, endTagName, newArray = []) {
const startIndex = tokens.findIndex((token) => token.conditional === tagName)
// The end tag name is currently in a separate token, but we want to group it with the start tag and content.
const endIndex = tokens.findIndex(
(token, index) => token.conditional === endTagName && index > startIndex,
)
// Once all tags are grouped and removed from `tokens`, this findIndex will not find anything,
// so we can return the grouped result at this point.
if (startIndex === -1) return newArray
const condBlockArr = tokens.slice(startIndex, endIndex + 1)
if (!condBlockArr.length) return newArray
const [newBlockArr, newEndIndex] = handleNestedTags(
condBlockArr,
endIndex,
tagName,
endTagName,
tokens,
)
// Combine the text of the groups so it's all together.
const condBlock = newBlockArr.map((t) => t.text).join('')
const startToken = tokens[startIndex]
const endToken = tokens[endIndex]
newArray.push({
conditional: startToken.text,
text: condBlock,
endIfText: endToken.text,
positionStart: startToken.position,
positionEnd: endToken.position,
})
// Remove the already-processed tokens.
const numberOfItemsToRemove = newEndIndex + 1 - startIndex
tokens.splice(startIndex, numberOfItemsToRemove)
// Run recursively until we reach the end of the tokens.
return groupTokens(tokens, tagName, endTagName, newArray)
}
function handleNestedTags(condBlockArr, endIndex, tagName, endTagName, tokens) {
// Return early if there are no nested tags to be handled.
if (!hasUnhandledNestedTags(condBlockArr, tagName, endTagName)) {
return [condBlockArr, endIndex]
}
// If a nested conditional is found, we have to peek forward to the next endif tag after the one we found.
const tempEndIndex = tokens
.slice(endIndex + 1)
.findIndex((token) => token.conditional === endTagName)
// Include the content up to the next endif tag.
const additionalTokens = tokens.slice(endIndex + 1, endIndex + tempEndIndex + 2)
const newBlockArray = condBlockArr.concat(...additionalTokens)
const newEndIndex = endIndex + tempEndIndex + 1
// Run this function recursively in case there are more nested tags to be handled.
return handleNestedTags(newBlockArray, newEndIndex, tagName, endTagName, tokens)
}
function hasUnhandledNestedTags(condBlockArr, tagName, endTagName) {
const startTags = condBlockArr.filter((t) => {
// some blocks that start with ifversion still have if tags nested inside
return tagName === 'ifversion'
? t.conditional === tagName || t.conditional === 'if'
: t.conditional === tagName
})
const endTags = condBlockArr.filter((t) => t.conditional === endTagName)
const hasMoreStartTagsThanEndTags = startTags.length > endTags.length
// Do not consider multiple elsifs an unhandled nesting. We only care about nested ifs.
const startTagsAreElsifs = startTags.every((t) => t.conditional === 'elsif')
const hasUnhandledNestedTags = hasMoreStartTagsThanEndTags && !startTagsAreElsifs
return hasUnhandledNestedTags
}
export { getLiquidConditionals, getLiquidConditionalsWithContent }

View File

@@ -1,58 +0,0 @@
import supportedOperators from '#src/content-render/liquid/ifversion-supported-operators.js'
// Turn an array of Liquid conditional objects that results from ./get-liquid-conditionals.js into a more
// detailed array of objects that includes GHES versioning information.
export default function getVersionBlocks(rawBlocks) {
const versionBlocks = []
rawBlocks.forEach((block) => {
const condKeyword = block.conditional.includes('ifversion') ? 'ifversion' : 'elsif'
const condOnly = block.conditional.replace(/{%-? /, '').replace(/ -?%}/, '')
const condWithLiquid = block.conditional
// E.g., [ 'ghes', 'ghes < 2.21' ]
const condArgs = condOnly
.replace('ifversion ', '')
.replace('elsif ', '')
// Obfuscate with an arbitrary character we don't want to preserve, so we can split on that character.
// TODO: If preserving `or` and `and` turns out NOT to be important, we can split on those words instead.
.replaceAll(/ (or|and) /g, ' ~$1 ')
.split('~')
.map((arg) => arg.trim())
// E.g., [ 'ghes', '<', '2.21' ]
const ranges = condArgs
.map((arg) => arg.split(' '))
.filter(
(args) =>
args.some((arg) => supportedOperators.includes(arg)) &&
args.some((arg) => arg === 'ghes'),
)
.map((args) => args.filter((arg) => !(arg === 'or' || (arg === 'and') | (arg === ''))))
// Remove the start tag and the end tag so we are left with the inner text.
// We don't need to do anything with this inner text other than check for nested conds.
let innerText = block.text.replace(condWithLiquid, '')
const indexOfLastEndif = innerText.lastIndexOf(' endif ')
innerText = innerText.slice(0, indexOfLastEndif)
// Remove any nested conditional content so we can check the top-level only.
const topLevelContent = innerText.replace(/{%-? ifversion[\S\s]+{%-? endif -?%}/g, '')
versionBlocks.push({
condKeyword,
condOnly,
condWithLiquid,
condArgs,
ranges,
content: block.text,
hasElsif: /{%-? elsif /.test(topLevelContent), // see if there is a nested elsif
hasElse: /{%-? else -?%}/.test(topLevelContent),
endIfText: block.endIfText,
startTagColumn1: block.positionStart[1] === 1,
endTagColumn1: block.positionEnd[1] === 1,
})
})
return versionBlocks
}

View File

@@ -1,50 +0,0 @@
// Returns false when no changes were made to the frontmatter,
// true when changes were made.
export default function removeDeprecatedFrontmatter(
file,
frontmatterVersions,
releaseToDeprecate,
nextOldestRelease,
) {
// skip files with no Enterprise Server versions frontmatter
if (!frontmatterVersions) return false
if (!frontmatterVersions.ghes) return false
const ghesRange = frontmatterVersions.ghes
// skip files with versions frontmatter that already applies to all enterprise-server releases
if (ghesRange === '*') return false
// if the release to deprecate is 2.13, and the FM is either '>=2.13', '>2.13', or '>=2.14',
// we can safely change the FM to ghes: '*'
const appliesToAllSupportedGhesReleases =
ghesRange === `>=${releaseToDeprecate}` ||
ghesRange === `>${releaseToDeprecate}` ||
ghesRange === `>=${nextOldestRelease}`
if (appliesToAllSupportedGhesReleases) {
frontmatterVersions.ghes = '*'
return true
}
// if the release to deprecate is 2.13, and the FM is either '=2.13', '<2.13', '<=2.13', or '<2.14',
// delete (aka deprecate) the ghes frontmatter property.
const appliesToNoSupportedGhesReleases =
ghesRange === `=${releaseToDeprecate}` ||
ghesRange === `<${releaseToDeprecate}` ||
ghesRange === `<=${releaseToDeprecate}` ||
ghesRange === `<${nextOldestRelease}`
if (appliesToNoSupportedGhesReleases) {
// Throw a warning if there are no other frontmatter versions specified.
if (Object.keys(frontmatterVersions).length === 1) {
console.log(
`Warning! ${file} has frontmatter versioning that will make it never appear when ${releaseToDeprecate} is deprecated. The article should probably be removed.`,
)
return false
}
delete frontmatterVersions.ghes
return true
}
}

View File

@@ -1,268 +0,0 @@
import { Tokenizer } from 'liquidjs'
import { getLiquidConditionalsWithContent } from './get-liquid-conditionals.js'
import getVersionBlocks from './get-version-blocks.js'
import { allVersions } from '#src/versions/lib/all-versions.js'
const supportedShortVersions = Object.values(allVersions).map((v) => v.shortName)
const updateRangeKeepGhes = 'updateRangeKeepGhes'
const updateRangeRemoveGhes = 'updateRangeRemoveGhes'
const removeRangeAndContent = 'removeRangeAndContent'
const removeConditionals = 'removeConditionals'
const tokenize = (str) => {
const tokenizer = new Tokenizer(str)
return tokenizer.readTopLevelTokens()
}
// This module is used by
// `npm run remove-version-markup` to remove
// and update Liquid conditionals when a GHES release is being deprecated. It is also used by
// src/ghes-releases/tests/remove-liquid-statements.js.
export default function removeLiquidStatements(content, release, nextOldestRelease, file) {
let newContent = content
let contentChanged = false
// Get an array of ifversion blocks with their content included.
const blocks = getLiquidConditionalsWithContent(newContent, 'ifversion')
if (!blocks.length) return { newContent, contentChanged }
// Decorate those blocks with more GHES versioning information.
const versionBlocks = getVersionBlocks(blocks)
// Determine whether we should remove the GHES range only or the GHES range and the content.
for (const versionBlock of versionBlocks) {
const actionMap = {}
versionBlock.isGhesOnly = versionBlock.condArgs.every((arg) => arg.includes('ghes'))
versionBlock.hasSingleRange = versionBlock.ranges.length === 1
versionBlock.andGhesRanges = versionBlock.condArgs.filter((arg) => arg.includes('and ghes'))
const isSafeToRemoveContent =
versionBlock.isGhesOnly && (versionBlock.hasSingleRange || versionBlock.andGhesRanges.length)
if (canConditionalBeRemoved(supportedShortVersions, versionBlock.condOnly)) {
actionMap[removeConditionals] = true
}
for (const rangeArgs of versionBlock.ranges) {
const rangeOperator = rangeArgs[1]
const releaseNumber = rangeArgs[2]
// We are only concerned with the release we are deprecating and the next oldest release..
if (!(releaseNumber === release || releaseNumber === nextOldestRelease)) continue
// But are not concerned with conditionals _equal_ to the next oldest release, as those are still valid.
if (rangeOperator === '=' && releaseNumber === nextOldestRelease) continue
// Remove Liquid in these scenarios.
const greaterThanVersionToDeprecate = rangeOperator === '>' && releaseNumber === release
const notEqualsVersionToDeprecate = rangeOperator === '!=' && releaseNumber === release
// Remove Liquid and content in these scenarios, IF AND ONLY IF it's safe to remove content.
// For example, when there is no other versioning in the conditional.
const lessThanNextOldestVersion =
rangeOperator === '<' && (releaseNumber === nextOldestRelease || releaseNumber === release)
const equalsVersionToDeprecate = rangeOperator === '=' && releaseNumber === release
let action
// Determine which action to take: removeRangeAndContent, updateRangeRemoveGhes, updateRangeKeepGhes.
if (greaterThanVersionToDeprecate || notEqualsVersionToDeprecate) {
// If the original is `ghes > 2.21` or `fpt or ghes > 2.21`, we want to replace it with `ghes`;
// If the original is `ghes > 2.21 and ghes < 3.0`, we want to remove the range and leave just `ghes < 3.0`.
action = versionBlock.hasSingleRange ? updateRangeKeepGhes : updateRangeRemoveGhes
}
if (lessThanNextOldestVersion || equalsVersionToDeprecate) {
// If it's not safe to remove content, we want to at least remove `ghes` from the range.
action = isSafeToRemoveContent ? removeRangeAndContent : updateRangeRemoveGhes
}
if (action) {
actionMap[action] = versionBlock.condArgs.find((arg) => arg.endsWith(rangeArgs.join(' ')))
}
}
versionBlock.action = Object.keys(actionMap).length ? actionMap : 'none'
}
// Create the new content and add it to each block.
versionBlocks
.filter((versionBlock) => versionBlock.action !== 'none')
.forEach((versionBlock) => {
const indexOfLastEndif = lastIndexOfRegex(versionBlock.content, /{%-? endif -?%}/g)
// ----- REMOVE RANGE AND CONTENT -----
if (versionBlock.action.removeRangeAndContent) {
// If the block has an else, remove the content up to the else, plus the final endif, leaving
// the content inside the else block as is.
if (versionBlock.hasElse) {
// If the ifversion conditional starts at the beginning of a line
// we can remove the newline after the else. If the if condition
// doesn't start at the beginning of a new line, the content before
// the ifversion tag will be concatenated to the content after the
// else condition on a single line.
const replaceRegex = versionBlock.startTagColumn1
? new RegExp(`${versionBlock.condWithLiquid}[\\S\\s]+?{%-? else -?%}\n?`)
: new RegExp(`${versionBlock.condWithLiquid}[\\S\\s]+?{%-? else -?%}`)
versionBlock.newContent = versionBlock.content
.slice(0, indexOfLastEndif)
.replace(replaceRegex, '')
if (versionBlock.endTagColumn1 && versionBlock.newContent.endsWith('\n'))
versionBlock.newContent = versionBlock.newContent.slice(0, -1)
}
// If the block has an elsif, remove the content up to the elsif, and change the elsif to an if (or leave it
// an elsif this this block is itself an elsif), leaving the content inside the elsif block as is. The elsif
// condition is evaluated separately so we don't need to worry about evaluating it here.
if (versionBlock.hasElsif) {
const replaceRegex = new RegExp(`${versionBlock.condWithLiquid}[\\S\\s]+?({%-?) elsif`)
versionBlock.newContent = versionBlock.content.replace(
replaceRegex,
`$1 ${versionBlock.condKeyword}`,
)
}
// For all other scenarios, remove the Liquid and the content.
if (!(versionBlock.hasElse || versionBlock.hasElsif)) {
versionBlock.newContent = ''
}
}
// ----- UPDATE RANGE AND REMOVE `GHES` -----
if (versionBlock.action.updateRangeRemoveGhes) {
// Make the replacement and get the new conditional.
const newCondWithLiquid = versionBlock.condWithLiquid
.replace(versionBlock.action.updateRangeRemoveGhes, '')
.replace(/\s\s+/, ' ')
// Update the conditional.
versionBlock.newContent = versionBlock.content.replace(
versionBlock.condWithLiquid,
newCondWithLiquid,
)
}
// ----- UPDATE RANGE AND KEEP `GHES` -----
let canBeRemoved
if (versionBlock.action.updateRangeKeepGhes) {
const replacement = versionBlock.action.updateRangeKeepGhes.replace(/ghes.+$/, 'ghes')
// Make the replacement and get the new conditional.
const newCondWithLiquid = versionBlock.condWithLiquid
.replace(versionBlock.action.updateRangeKeepGhes, replacement)
.replace(/\s\s+/, ' ')
// If the new conditional contains all the currently supported versions, no conditional
// is actually needed, and it can be removed. Any `else` statements and their content should
// also be removed.
canBeRemoved = canConditionalBeRemoved(supportedShortVersions, newCondWithLiquid)
if (!canBeRemoved) {
versionBlock.newContent = versionBlock.content.replace(
versionBlock.condWithLiquid,
newCondWithLiquid,
)
}
}
// ----- REMOVE CONDITIONALS -----
// this happens if either:
// (a) the the conditional was updated in a previous step to contain all the currently supported versions, or
// (b) the conditional was not touched but its arguments already contained all supported versions, making it unnecessary
if (canBeRemoved || versionBlock.action.removeConditionals) {
versionBlock.newContent = versionBlock.content
// If this block does not contain else/elsifs, start by removing the final endif.
// (We'll handle the endif separately in those scenarios.)
if (!versionBlock.hasElse && !versionBlock.hasElsif) {
const indexOfLastEndif = lastIndexOfRegex(versionBlock.content, /{%-? endif -?%}/g)
versionBlock.newContent = versionBlock.newContent.slice(0, indexOfLastEndif)
if (versionBlock.endTagColumn1 && versionBlock.newContent.endsWith('\n'))
versionBlock.newContent = versionBlock.newContent.slice(0, -1)
}
// If start tag is on it's own line, remove line ending (\\n?)
// and remove white space (//s*) after line ending to
// preserve indentation of next line
const removeStartTagRegex = versionBlock.startTagColumn1
? new RegExp(`${versionBlock.condWithLiquid}\\n?\\s*`)
: new RegExp(`${versionBlock.condWithLiquid}`)
// For ALL scenarios, remove the start tag.
versionBlock.newContent = versionBlock.newContent.replace(removeStartTagRegex, '')
// If the block has an elsif, change the elsif to an if (or leave it an elsif this this block is itself an elsif),
// leaving the content inside the elsif block as is. Also leave the endif in this scenario.
if (versionBlock.hasElsif) {
versionBlock.newContent = versionBlock.newContent.replace(
/({%-?) elsif/,
`$1 ${versionBlock.condKeyword}`,
)
}
// If the block has an else, remove the else, its content, and the endif.
if (versionBlock.hasElse) {
let elseStartIndex
let ifCondFlag = false
// tokenize the content including the nested conditionals to find
// the unmatched else tag. Remove content from the start of the
// else tag to the end of the content. The tokens return have different
// `kind`s and can be liquid tags, HTML, and a variety of things.
// A value of 4 is a liquid tag. See https://liquidjs.com/api/enums/parser_token_kind_.tokenkind.html.
tokenize(versionBlock.newContent)
.filter((elem) => elem.kind === 4)
.forEach((tag) => {
if (tag.name === 'ifversion' || tag.name === 'if') {
ifCondFlag = true
} else if (tag.name === 'endif' && ifCondFlag === true) {
ifCondFlag = false
} else if (tag.name === 'else' && ifCondFlag === false) {
elseStartIndex = tag.begin
}
})
versionBlock.newContent = versionBlock.newContent.slice(0, elseStartIndex)
}
}
})
// Now that we have the old and new content attached to each block, make the replacement
// in the general content and return the updated general content.
versionBlocks.forEach((versionBlock) => {
if (versionBlock.action !== 'none') {
contentChanged = true
const newBlockContent = versionBlock.newContent.replaceAll(/\n\n\n+?/g, '\n\n')
newContent = newContent
.replaceAll(versionBlock.content, newBlockContent)
.replaceAll(/({%-? ifversion |{%-? elsif )(and|or) /g, '$1') // clean up stray and/ors :/
.replaceAll(/\n\n\n+?/g, '\n\n')
if (file && file.includes('/data/')) {
newContent = newContent.trim()
}
}
})
return { newContent, contentChanged }
}
// Hack to use a regex with lastIndexOf.
// Inspired by https://stackoverflow.com/a/21420210
function lastIndexOfRegex(str, regex, fromIndex) {
const myStr = fromIndex ? str.substring(0, fromIndex) : str
const match = myStr.match(regex)
return match ? myStr.lastIndexOf(match[match.length - 1]) : -1
}
// Checks if a conditional is necessary given all the supported versions and the arguments in a conditional
// If all supported versions show up in the arguments, it's not necessary! Additionally, builds in support
// for when feature-based versioning is used, which looks like "issue" versions for upcoming GHAE releases
function canConditionalBeRemoved(supportedVersions, conditional) {
if (typeof conditional !== 'string') throw new Error('Expecting a string.')
return supportedVersions.every((arg) => conditional.includes(arg))
}

View File

@@ -1,62 +0,0 @@
// [start-readme]
//
// This script removes the static GraphQL, REST, and webhook files for any
// deprecated GHES versions.
//
// [end-readme]
import fs from 'fs'
import path from 'path'
import { rimraf } from 'rimraf'
import walk from 'walk-sync'
import { allVersions } from '#src/versions/lib/all-versions.js'
import { deprecated } from '#src/versions/lib/enterprise-server-releases.js'
const webhooksStaticDir = path.join(process.cwd(), 'src/webhooks/data')
const graphqlStaticDir = path.join(process.cwd(), 'src/graphql/data')
const restDecoratedDir = path.join(process.cwd(), 'src/rest/data')
const ghesReleaseNotesDir = 'data/release-notes/enterprise-server'
const supportedEnterpriseVersions = Object.values(allVersions).filter(
(v) => v.plan === 'enterprise-server',
)
// GHES release notes
const deprecatedVersionsHyphenated = deprecated.map((v) => v.replace(/\./g, '-'))
walk(ghesReleaseNotesDir)
// Only directories end with a /
.filter((file) => file.endsWith('/'))
// Check if the directory name contains a deprecated GHES version
.filter((dir) => deprecatedVersionsHyphenated.some((version) => dir.includes(version)))
// Remove the directory
.map((dir) => rimraf.sync(path.join(ghesReleaseNotesDir, dir)))
// webhooks and GraphQL
const supportedMiscVersions = supportedEnterpriseVersions.map((v) => v.miscVersionName)
// The miscBaseName is the same for all GHES versions (currently `ghes-`), so we can just grab the first one
const miscBaseName = supportedEnterpriseVersions.map((v) => v.miscBaseName)[0]
;[graphqlStaticDir, webhooksStaticDir].forEach((dir) => {
removeFiles(dir, miscBaseName, supportedMiscVersions)
})
// REST
const supportedOpenApiVersions = supportedEnterpriseVersions.map((v) => v.openApiVersionName)
// The openApiBaseName is the same for all GHES versions (currently `ghes-`), so we can just grab the first one
const openApiBaseName = supportedEnterpriseVersions.map((v) => v.openApiBaseName)[0]
;[restDecoratedDir].forEach((dir) => {
removeFiles(dir, openApiBaseName, supportedOpenApiVersions)
})
function removeFiles(dir, baseName, supportedVersions) {
fs.readdirSync(dir)
.filter((file) => file.includes(baseName))
.filter((file) => supportedVersions.every((version) => !file.includes(version)))
.forEach((file) => {
const fullPath = path.join(dir, file)
console.log(`removing ${fullPath}`)
rimraf.sync(fullPath)
})
}

View File

@@ -1,113 +0,0 @@
// [start-readme]
//
// Run this script after an Enterprise deprecation to remove Liquid statements and frontmatter that
// contain the deprecated Enterprise version. See the Enterprise deprecation issue template for instructions.
//
// [end-readme]
import fs from 'fs'
import { program } from 'commander'
import frontmatter from '#src/frame/lib/read-frontmatter.js'
import removeLiquidStatements from './remove-liquid-statements.js'
import removeDeprecatedFrontmatter from './remove-deprecated-frontmatter.js'
import { all, getNextReleaseNumber } from '#src/versions/lib/enterprise-server-releases.js'
import walkFiles from '#src/workflows/walk-files.ts'
program
.description(
'Remove Liquid conditionals and update versions frontmatter for a given Enterprise Server release.',
)
.option('-r, --release <NUMBER>', 'Enterprise Server release number. Example: 2.19')
.parse(process.argv)
const release = program.opts().release
// verify CLI options
if (!release) {
console.log(program.description() + '\n')
program.options.forEach((opt) => {
console.log(opt.flags)
console.log(opt.description + '\n')
})
process.exit(1)
}
if (!all.includes(release)) {
console.log(
`You specified ${release}! Please specify a supported or deprecated release number from lib/enterprise-server-releases.js`,
)
process.exit(1)
}
const nextOldestRelease = getNextReleaseNumber(release)
console.log(`Deprecating GHES ${release}!\n`)
console.log(`Next oldest version: ${nextOldestRelease}\n`)
// gather content and data files
const contentFiles = walkFiles('content', '.md', { includeEarlyAccess: true })
const reusables = walkFiles('data/reusables', '.md', { includeEarlyAccess: true })
const variables = walkFiles('data/variables', '.yml', { includeEarlyAccess: true })
const learningTracks = walkFiles('data/learning-tracks', '.yml', { includeEarlyAccess: true })
const allFiles = contentFiles.concat(reusables, variables, learningTracks)
main()
async function main() {
for (const file of allFiles) {
const oldContents = fs.readFileSync(file, 'utf8')
const { content, data } = frontmatter(oldContents)
let fileChanged = false
// update frontmatter versions prop
fileChanged ||= removeDeprecatedFrontmatter(file, data.versions, release, nextOldestRelease)
// update liquid statements in content and data
const { newContent, contentChanged } = removeLiquidStatements(
content,
release,
nextOldestRelease,
file,
)
fileChanged ||= contentChanged
// update liquid statements in content frontmatter (like intro and title)
for (const key in data) {
const value = data[key]
if (typeof value === 'string' && value.includes('{% ifversion')) {
const { newContent, contentChanged } = removeLiquidStatements(
value,
release,
nextOldestRelease,
file,
)
fileChanged ||= contentChanged
data[key] = newContent
}
}
// When stringifying frontmatter, the frontmatter is also formatted.
// This means that even if there were no Liquid versioning changes,
// the frontmatter may still be modified to modify line breaks or quotes.
// This an already difficult PR noisier to review. This prevents writing
// the file unless there are versioning changes made.
if (fileChanged) {
// make sure any intro fields that exist and are empty return an empty string, not null
if (typeof data.intro !== 'undefined' && !data.intro) {
data.intro = ''
}
// put it all back together
const newContents = frontmatter.stringify(newContent, data, { lineWidth: 10000 })
// if the content file is now empty, remove it
if (newContents.replace(/\s/g, '').length === 0) {
fs.unlinkSync(file)
continue
}
fs.writeFileSync(file, newContents)
}
}
console.log(`Removed GHES ${release} markup from content and data files! Review and run tests.`)
}

View File

@@ -1,92 +0,0 @@
---
title: And Greater Than Version To Deprecate 1
intro: Remove liquid only
---
## 1
<div class="example1">
{% ifversion not fpt and ghes > 2.13 %}
Alpha
{% endif %}
</div>
## 2
<div class="example2">
{% ifversion not fpt and ghes > 2.13 %}
Alpha
{% else %}
Bravo
{% endif %}
</div>
## 3
<div class="example3">
{% ifversion ghes > 2.16 %}
Alpha
{% else %}
Bravo
{% ifversion not fpt and ghes > 2.13 %}
Charlie
{% endif %}
{% endif %}
</div>
## 4
<div class="example4">
{% ifversion ghes < 2.16 %}
Alpha
{% ifversion not fpt and ghes > 2.13 %}
Bravo
{% endif %}
{% else %}
Charlie
{% endif %}
</div>
## 5
<div class="example5">
{% ifversion not fpt and ghes > 2.13 %}
Alpha
{% ifversion ghes > 2.16 %}
Bravo
{% endif %}
{% else %}
Charlie
{% endif %}
</div>

View File

@@ -1,93 +0,0 @@
---
title: And Greater Than Version To Deprecate 2
intro: Remove liquid only
---
## 1
<div class="example1">
{% ifversion ghes > 2.13 and ghes < 2.16 %}
Alpha
{% endif %}
</div>
## 2
<div class="example2">
{% ifversion ghes > 2.13 and ghes < 2.16 %}
Alpha
{% else %}
Bravo
{% endif %}
</div>
## 3
<div class="example3">
{% ifversion fpt %}
Alpha
{% else %}
Bravo
{% ifversion ghes > 2.13 and ghes < 2.16 %}
Charlie
{% endif %}
{% endif %}
</div>
## 4
<div class="example4">
{% ifversion not fpt %}
Alpha
{% ifversion ghes > 2.13 and ghes < 2.16 %}
Bravo
{% endif %}
{% else %}
Charlie
{% endif %}
</div>
## 5
<div class="example5">
{% ifversion ghes > 2.13 and ghes < 2.16 %}
Alpha
{% ifversion not fpt %}
Bravo
{% endif %}
{% else %}
Charlie
{% endif %}
</div>

View File

@@ -1,110 +0,0 @@
---
title: Equals Version To Deprecate
intro: Remove liquid and content
---
## 1
<div class="example1">
{% ifversion ghes = 2.13 %}
Alpha
{% endif %}
</div>
## 2
<div class="example2">
{% ifversion not fpt and ghes = 2.13 %}
Alpha
{% endif %}
</div>
## 3
<div class="example3">
{% ifversion fpt %}
Alpha
{% else %}
Bravo
{% ifversion ghes = 2.13 %}
Charlie
{% endif %}
{% endif %}
</div>
## 4
<div class="example4">
{% ifversion fpt %}
Alpha
{% ifversion ghes = 2.13 %}
Bravo
{% endif %}
{% else %}
Charlie
{% endif %}
</div>
## 5
<div class="example5">
{% ifversion ghes = 2.13 %}
Alpha
{% ifversion fpt %}
Bravo
{% endif %}
{% else %}
Charlie
{% endif %}
</div>
## 6
<div class="example6">
{% ifversion ghes = 2.13 %}
Alpha
{% else %}
Charlie
{% ifversion fpt or ghes > 2.13 %}
Bravo
{% endif %}
{% endif %}
</div>

View File

@@ -1,6 +0,0 @@
---
title: Frontmatter
versions:
fpt: '*'
ghes: '>=2.13'
---

View File

@@ -1,6 +0,0 @@
---
title: Frontmatter
versions:
fpt: '*'
ghes: '>=2.14'
---

View File

@@ -1,189 +0,0 @@
---
title: Greater Than Version To Deprecate
intro: Remove liquid only
---
## 1
<div class="example1">
{% ifversion ghes > 2.13 %}
Alpha
{% endif %}
</div>
## 2
<div class="example2">
{% ifversion fpt or ghes > 2.13 %}
Alpha
{% endif %}
</div>
## 3
<div class="example3">
{% ifversion ghes > 2.13 %}
Alpha
{% else %}
Bravo
{% endif %}
</div>
## 4
<div class="example4">
{% ifversion ghes > 2.16 %}
Alpha
{% else %}
Bravo
{% ifversion ghes > 2.13 %}
Charlie
{% endif %}
{% endif %}
</div>
## 5
<div class="example5">
{% ifversion ghes < 2.16 %}
Alpha
{% ifversion ghes > 2.13 %}
Bravo
{% endif %}
{% else %}
Charlie
{% endif %}
</div>
## 6
<div class="example6">
{% ifversion ghes > 2.13 %}
Alpha
{% ifversion ghes < 2.16 %}
Bravo
{% endif %}
{% else %}
Charlie
{% endif %}
</div>
## 7
<div class="example7">
{% ifversion ghes > 2.13 %}
Alpha
{% ifversion ghes > 2.16 %}
Bravo
{% else %}
Charlie
{% endif %}
{% endif %}
</div>
## 8
<div class="example8">
{% ifversion ghes > 2.13 %}
Alpha
{% else %}
Bravo
{% ifversion not fpt %}
Charlie
{% endif %}
Delta
{% endif %}
</div>
## 9
<div class="example9">
{% ifversion fpt %}
Alpha
{% else %}
Bravo
{% ifversion ghes > 2.16 %}
Charlie
{% endif %}
{% ifversion ghes > 2.13 %}
Delta
{% endif %}
{% endif %}
</div>
## 10
<div class="example10">
{% ifversion ghes > 2.13 %}
Alpha
{% else %}
Bravo
{% endif %}
</div>

View File

@@ -1,163 +0,0 @@
---
title: Less Than Version To Deprecate
intro: Remove liquid and content
---
## 1
<div class="example1">
Alpha
{% ifversion ghes < 2.14 %}
Bravo
{% endif %}
</div>
## 2
<div class="example2">
Alpha
{% ifversion fpt or ghes < 2.14 %}
Bravo
{% endif %}
</div>
## 3
<div class="example3">
{% ifversion fpt %}
Alpha
{% else %}
Bravo
{% ifversion ghes < 2.14 %}
Charlie
{% endif %}
{% endif %}
</div>
## 4
<div class="example4">
{% ifversion fpt %}
Alpha
{% ifversion ghes < 2.14 %}
Bravo
{% endif %}
{% else %}
Charlie
{% endif %}
</div>
## 5
<div class="example5">
{% ifversion ghes < 2.14 %}
Alpha
{% ifversion fpt %}
Bravo
{% endif %}
{% else %}
Charlie
{% endif %}
</div>
## 6
<div class="example6">
{% ifversion ghes < 2.16 %}
Alpha
{% else %}
Charlie
{% ifversion not fpt and ghes < 2.14 %}
Bravo
{% endif %}
{% endif %}
</div>
## 7
<div class="example7">
{% ifversion not fpt and ghes < 2.14 %}
Alpha
{% ifversion ghes < 2.14 %}
Bravo
{% else %}
Charlie
{% endif %}
{% endif %}
</div>
## 8
<div class="example8">
{% ifversion ghes < 2.14 %}
Alpha
{% else %}
Bravo
{% ifversion ghes > 2.16 %}
Charlie
{% else %}
Delta
{% endif %}
Echo
{% endif %}
</div>

View File

@@ -1,100 +0,0 @@
---
title: Not Equals To Version To Deprecate
intro: Remove liquid only
---
## 1
<div class="example1">
{% ifversion ghes != 2.13 %}
Alpha
{% endif %}
</div>
## 2
<div class="example2">
{% ifversion fpt or ghes != 2.13 %}
Alpha
{% endif %}
</div>
## 3
<div class="example3">
{% ifversion fpt %}
Alpha
{% else %}
Bravo
{% ifversion ghes != 2.13 %}
Charlie
{% endif %}
{% endif %}
</div>
## 4
<div class="example4">
{% ifversion fpt %}
Alpha
{% ifversion ghes != 2.13 %}
Bravo
{% endif %}
{% else %}
Charlie
{% endif %}
</div>
## 5
<div class="example5">
{% ifversion ghes != 2.13 %}
Alpha
{% ifversion fpt %}
Bravo
{% endif %}
{% else %}
Charlie
{% endif %}
</div>
## 6
<div class="example6">
{% ifversion not fpt and ghes != 2.13 %}
Alpha
{% endif %}
</div>

View File

@@ -1,72 +0,0 @@
---
title: Remove unnecessary conditionals including nested
intro: Remove liquid only
---
## 1
<div class="example1">
{% ifversion fpt or ghes or ghae or ghec %}
Alpha
{% endif %}
</div>
## 2
<div class="example2">
{% ifversion fpt or ghes or ghae or ghec %}
Alpha
{% ifversion fpt or ghec %}
Bravo
{% endif %}
{% endif %}
</div>
## 3
<div class="example3">
{% ifversion fpt or ghes or ghae or ghec %}
Alpha
{% ifversion fpt or ghec %}
Bravo
{% else %}
Delta
{% endif %}
{% endif %}
</div>
## 4
<div class="example4">
{% ifversion fpt or ghes or ghae or ghec %}
Alpha
{% ifversion fpt or ghec %}
Bravo
{% ifversion ghae %}
Charlie
{% endif %}
{% endif %}
{% endif %}
</div>
## 5
<div class="example5">
{% ifversion fpt or ghes or ghae or ghec %}
Alpha
{% ifversion fpt or ghec %}
Bravo
{% ifversion ghae %}
Charlie
{% endif %}
{% else %}
Delta
{% endif %}
{% endif %}
</div>

View File

@@ -1,85 +0,0 @@
---
title: Whitespace tests
---
## 1
<div class="example1">
{% ifversion ghes > 2.13 %}
Alpha
{% endif %}
</div>
## 2
<div class="example2">
{%- ifversion ghes > 2.13 %}
Alpha
{% endif %}
</div>
## 3
<div class="example3">
{% ifversion fpt or ghes > 2.13 %}
Alpha
{%- endif %}
</div>
## 4
<div class="example4">
{%- ifversion fpt or ghes > 2.13 %}
Alpha
{%- endif %}
</div>
## 5
<div class="example5">
{% ifversion ghes > 2.13 %}
Alpha
{% endif %}
</div>
## 6
<div class="example6">
Alpha
{% ifversion fpt or ghes > 2.13 %}
Bravo
{% endif %}
Charlie
</div>
## 7
<div class="example7">
Alpha{% ifversion fpt or ghes > 2.13 %}
Bravo{% endif %}
</div>
## 8
<div class="example8">
Alpha{% ifversion fpt or ghec or ghae or ghes > 2.13 %}
Bravo{% endif %}
</div>
## 9
<div class="example9">
Alpha
{% ifversion fpt or ghec or ghae or ghes > 2.13 %}
Bravo
{% endif %}
</div>
## 10
<div class="example10">
Pre{% ifversion ghes < 2.14 %}
Alpha
{% else %}
Bravo
{% endif %}
</div>
## 11
<div class="example11">
Pre
{% ifversion ghes < 2.14 %}
Alpha
{% else %}
Bravo{% endif %}
</div>

View File

@@ -1,228 +0,0 @@
import { fileURLToPath } from 'url'
import path from 'path'
import fs from 'fs/promises'
import cheerio from 'cheerio'
import matter from 'gray-matter'
import { describe, expect, test } from 'vitest'
import removeLiquidStatements from '../scripts/remove-liquid-statements'
import removeDeprecatedFrontmatter from '../scripts/remove-deprecated-frontmatter'
const __dirname = path.dirname(fileURLToPath(import.meta.url))
const removeLiquidStatementsFixtures = path.join(__dirname, './fixtures/remove-liquid-statements')
// Hardcode values so tests don't go out of date
const versionToDeprecate = '2.13'
const nextOldestVersion = '2.14'
// Remove liquid only
const greaterThan = path.join(removeLiquidStatementsFixtures, 'greater-than.md')
const unnecessary = path.join(removeLiquidStatementsFixtures, 'unnecessary.md')
const andGreaterThan1 = path.join(removeLiquidStatementsFixtures, 'and-greater-than1.md')
const andGreaterThan2 = path.join(removeLiquidStatementsFixtures, 'and-greater-than2.md')
const notEquals = path.join(removeLiquidStatementsFixtures, 'not-equals.md')
// Remove liquid and content
const lessThanNextOldest = path.join(removeLiquidStatementsFixtures, 'less-than-next-oldest.md')
const equals = path.join(removeLiquidStatementsFixtures, 'equals.md')
// Check whitespace
const whitespace = path.join(removeLiquidStatementsFixtures, 'whitespace.md')
// Update frontmatter
const frontmatter1 = path.join(removeLiquidStatementsFixtures, 'frontmatter1.md')
const frontmatter2 = path.join(removeLiquidStatementsFixtures, 'frontmatter2.md')
// process frontmatter
function processFrontmatter(contents, file) {
const { content, data } = matter(contents)
removeDeprecatedFrontmatter(file, data.versions, versionToDeprecate, nextOldestVersion)
return matter.stringify(content, data, { lineWidth: 10000 })
}
describe('removing liquid statements only', () => {
test('removes liquid statements that specify "greater than version to deprecate"', async () => {
const content = await fs.readFile(greaterThan, 'utf8')
const { newContent } = removeLiquidStatements(content, versionToDeprecate, nextOldestVersion)
const $ = cheerio.load(newContent)
expect($('.example1').text().trim()).toBe(`{% ifversion ghes %}\n
Alpha\n\n{% endif %}`)
expect($('.example2').text().trim()).toBe(`{% ifversion fpt or ghes %}\n
Alpha\n\n{% endif %}`)
expect($('.example3').text().trim()).toBe(`{% ifversion ghes %}\n
Alpha\n\n{% else %}\n\nBravo\n\n{% endif %}`)
expect($('.example4').text().trim()).toBe(`{% ifversion ghes > 2.16 %}\n
Alpha\n\n{% else %}\n\nBravo\n\n{% ifversion ghes %}\n\nCharlie\n\n{% endif %}\n\n{% endif %}`)
expect($('.example5').text().trim()).toBe(`{% ifversion ghes < 2.16 %}\n
Alpha\n\n{% ifversion ghes %}\n\nBravo\n\n{% endif %}\n\n{% else %}\n\nCharlie\n\n{% endif %}`)
expect($('.example6').text().trim()).toBe(`{% ifversion ghes %}\n\nAlpha\n
{% ifversion ghes < 2.16 %}\n\nBravo\n\n{% endif %}\n\n{% else %}\n\nCharlie\n\n{% endif %}`)
expect($('.example7').text().trim()).toBe(`{% ifversion ghes %}\n\nAlpha\n
{% ifversion ghes > 2.16 %}\n\nBravo\n\n{% else %}\n\nCharlie\n\n{% endif %}\n\n{% endif %}`)
expect($('.example8').text().trim()).toBe(`{% ifversion ghes %}\n\nAlpha\n
{% else %}\n\nBravo\n\n{% ifversion not fpt %}\n\nCharlie\n\n{% endif %}\n\nDelta\n\n{% endif %}`)
expect($('.example9').text().trim()).toBe(`{% ifversion fpt %}\n
Alpha\n\n{% else %}\n\nBravo\n\n{% ifversion ghes > 2.16 %}\n\nCharlie\n
{% endif %}\n\n{% ifversion ghes %}\n\nDelta\n\n{% endif %}\n\n{% endif %}`)
expect($('.example10').text().trim()).toBe(`{% ifversion ghes %}\n\nAlpha\n
{% else %}\n\nBravo\n\n{% endif %}`)
})
test('removes liquid statements that specify all known versions, including some nested conditionals"', async () => {
const content = await fs.readFile(unnecessary, 'utf8')
const { newContent } = removeLiquidStatements(content, versionToDeprecate, nextOldestVersion)
const $ = cheerio.load(newContent)
expect($('.example1').text().trim()).toBe(`Alpha`)
expect($('.example2').text().trim()).toBe(
`Alpha\n {% ifversion fpt or ghec %}\n Bravo\n {% endif %}`,
)
expect($('.example3').text().trim()).toBe(
`Alpha\n {% ifversion fpt or ghec %}\n Bravo\n {% else %}\n Delta\n {% endif %}`,
)
expect($('.example4').text().trim()).toBe(
`Alpha\n {% ifversion fpt or ghec %}\n Bravo\n {% ifversion ghae %}\n Charlie\n {% endif %}\n {% endif %}`,
)
expect($('.example5').text().trim()).toBe(
`Alpha\n {% ifversion fpt or ghec %}\n Bravo\n {% ifversion ghae %}\n Charlie\n {% endif %}\n {% else %}\n Delta\n {% endif %}`,
)
})
test('removes liquid statements that specify "and greater than version to deprecate"', async () => {
const content = await fs.readFile(andGreaterThan1, 'utf8')
const { newContent } = removeLiquidStatements(content, versionToDeprecate, nextOldestVersion)
const $ = cheerio.load(newContent)
expect($('.example1').text().trim()).toBe(
'{% ifversion not fpt and ghes %}\n\nAlpha\n\n{% endif %}',
)
expect($('.example2').text().trim())
.toBe(`{% ifversion not fpt and ghes %}\n\nAlpha\n\n{% else %}\n
Bravo\n\n{% endif %}`)
expect($('.example3').text().trim()).toBe(`{% ifversion ghes > 2.16 %}\n
Alpha\n\n{% else %}\n\nBravo\n\n{% ifversion not fpt and ghes %}\n\nCharlie\n\n{% endif %}\n{% endif %}`)
expect($('.example4').text().trim()).toBe(`{% ifversion ghes < 2.16 %}\n
Alpha\n\n{% ifversion not fpt and ghes %}\n\nBravo\n\n{% endif %}\n\n{% else %}\n\nCharlie\n\n{% endif %}`)
expect($('.example5').text().trim()).toBe(`{% ifversion not fpt and ghes %}\n
Alpha\n\n{% ifversion ghes > 2.16 %}\n\nBravo\n\n{% endif %}\n\n{% else %}\n\nCharlie\n\n{% endif %}`)
})
test('removes liquid statements that specify "and greater than version to deprecate" (alternate format)', async () => {
const content = await fs.readFile(andGreaterThan2, 'utf8')
const { newContent } = removeLiquidStatements(content, versionToDeprecate, nextOldestVersion)
const $ = cheerio.load(newContent)
expect($('.example1').text().trim()).toBe('{% ifversion ghes < 2.16 %}\n\nAlpha\n\n{% endif %}')
expect($('.example2').text().trim()).toBe(`{% ifversion ghes < 2.16 %}\n\nAlpha\n\n{% else %}\n
Bravo\n\n{% endif %}`)
expect($('.example3').text().trim()).toBe(`{% ifversion fpt %}\n
Alpha\n\n{% else %}\n\nBravo\n\n{% ifversion ghes < 2.16 %}\n\nCharlie\n\n{% endif %}\n\n{% endif %}`)
expect($('.example4').text().trim()).toBe(`{% ifversion not fpt %}\n
Alpha\n\n{% ifversion ghes < 2.16 %}\n\nBravo\n\n{% endif %}\n\n{% else %}\n\nCharlie\n\n{% endif %}`)
expect($('.example5').text().trim()).toBe(`{% ifversion ghes < 2.16 %}\n
Alpha\n\n{% ifversion not fpt %}\n\nBravo\n\n{% endif %}\n\n{% else %}\n\nCharlie\n\n{% endif %}`)
})
test('removes liquid statements that specify "not equals version to deprecate"', async () => {
const content = await fs.readFile(notEquals, 'utf8')
const { newContent } = removeLiquidStatements(content, versionToDeprecate, nextOldestVersion)
const $ = cheerio.load(newContent)
expect($('.example1').text().trim()).toBe('{% ifversion ghes %}\n\nAlpha\n\n{% endif %}')
expect($('.example2').text().trim()).toBe('{% ifversion fpt or ghes %}\n\nAlpha\n\n{% endif %}')
expect($('.example3').text().trim()).toBe(`{% ifversion fpt %}\n
Alpha\n\n{% else %}\n\nBravo\n\n{% ifversion ghes %}\n\nCharlie\n\n{% endif %}\n\n{% endif %}`)
expect($('.example4').text().trim()).toBe(`{% ifversion fpt %}\n
Alpha\n\n{% ifversion ghes %}\n\nBravo\n\n{% endif %}\n\n{% else %}\n\nCharlie\n\n{% endif %}`)
expect($('.example5').text().trim())
.toBe(`{% ifversion ghes %}\n\nAlpha\n\n{% ifversion fpt %}\n
Bravo\n\n{% endif %}\n\n{% else %}\n\nCharlie\n\n{% endif %}`)
expect($('.example6').text().trim()).toBe(`{% ifversion not fpt and ghes %}\n
Alpha\n\n{% endif %}`)
})
})
describe('removing liquid statements and content', () => {
test('removes interior content and liquid statements that specify "equals version to deprecate"', async () => {
const content = await fs.readFile(equals, 'utf8')
const { newContent } = removeLiquidStatements(content, versionToDeprecate, nextOldestVersion)
const $ = cheerio.load(newContent)
expect($('.example1').text().trim()).toBe('')
expect($('.example2').text().trim()).toBe('{% ifversion not fpt %}\n\nAlpha\n\n{% endif %}')
expect($('.example3').text().trim()).toBe(`{% ifversion fpt %}\n
Alpha\n\n{% else %}\n\nBravo\n\n{% endif %}`)
expect($('.example4').text().trim()).toBe(`{% ifversion fpt %}\n
Alpha\n\n{% else %}\n\nCharlie\n\n{% endif %}`)
expect($('.example5').text().trim()).toBe('Charlie')
expect($('.example6').text().trim()).toBe(
'Charlie\n\n{% ifversion fpt or ghes %}\n\nBravo\n\n{% endif %}',
)
})
test('removes interior content and liquid statements that specify "less than next oldest than version to deprecate"', async () => {
const content = await fs.readFile(lessThanNextOldest, 'utf8')
const { newContent } = removeLiquidStatements(content, versionToDeprecate, nextOldestVersion)
const $ = cheerio.load(newContent)
expect($('.example1').text().trim()).toBe('Alpha')
expect($('.example2').text().trim()).toBe(
'Alpha\n\n{% ifversion fpt %}\n\nBravo\n\n{% endif %}',
)
expect($('.example3').text().trim()).toBe(`{% ifversion fpt %}\n
Alpha\n\n{% else %}\n\nBravo\n\n{% endif %}`)
expect($('.example4').text().trim()).toBe(`{% ifversion fpt %}\n
Alpha\n\n{% else %}\n\nCharlie\n\n{% endif %}`)
expect($('.example5').text().trim()).toBe('Charlie')
expect($('.example6').text().trim()).toBe(`{% ifversion ghes < 2.16 %}\n
Alpha\n\n{% else %}\n\nCharlie\n\n{% ifversion not fpt %}\n\nBravo\n\n{% endif %}\n\n{% endif %}`)
expect($('.example7').text().trim()).toBe(`{% ifversion not fpt %}\n
Alpha\n\nCharlie\n\n{% endif %}`)
expect($('.example8').text().trim()).toBe(`Bravo\n\n{% ifversion ghes > 2.16 %}\n
Charlie\n\n{% else %}\n\nDelta\n\n{% endif %}\n\nEcho`)
})
})
describe('updating frontmatter', () => {
test('updates frontmatter versions Enterprise if set to greater-than-or-equal-to version to deprecate', async () => {
let contents = await fs.readFile(frontmatter1, 'utf8')
contents = processFrontmatter(contents, frontmatter1)
const $ = cheerio.load(contents)
expect($.text().includes("ghes: '*'")).toBe(true)
expect($.text().includes("ghes: '>=2.13'")).toBe(false)
})
test('updates frontmatter versions Enterprise if set to greater-than-or-equal-to next oldest version', async () => {
let contents = await fs.readFile(frontmatter2, 'utf8')
contents = processFrontmatter(contents, frontmatter2)
const $ = cheerio.load(contents)
expect($.text().includes("ghes: '*'")).toBe(true)
expect($.text().includes("ghes: '>=2.14'")).toBe(false)
})
})
describe('whitespace', () => {
test('does not add newlines when whitespace control is used', async () => {
const content = await fs.readFile(whitespace, 'utf8')
const { newContent } = removeLiquidStatements(content, versionToDeprecate, nextOldestVersion)
const $ = cheerio.load(newContent)
expect($('.example1').text()).toBe('\n{% ifversion ghes %}\n Alpha\n{% endif %}\n')
expect($('.example2').text()).toBe('\n{%- ifversion ghes %}\n Alpha\n{% endif %}\n')
expect($('.example3').text()).toBe('\n{% ifversion fpt or ghes %}\n Alpha\n{%- endif %}\n')
expect($('.example4').text()).toBe('\n{%- ifversion fpt or ghes %}\n Alpha\n{%- endif %}\n')
})
test('does not add newlines when no newlines are present', async () => {
const content = await fs.readFile(whitespace, 'utf8')
const { newContent } = removeLiquidStatements(content, versionToDeprecate, nextOldestVersion)
const $ = cheerio.load(newContent)
expect($('.example5').text()).toBe('\n{% ifversion ghes %}\n Alpha\n{% endif %}\n')
expect($('.example6').text()).toBe(
'\n Alpha\n{% ifversion fpt or ghes %}\n Bravo\n{% endif %}\n Charlie\n',
)
expect($('.example7').text()).toBe('\nAlpha{% ifversion fpt or ghes %}\nBravo{% endif %}\n')
})
test('only remove newlines when tag starts at beginning of line', async () => {
const content = await fs.readFile(whitespace, 'utf8')
const { newContent } = removeLiquidStatements(content, versionToDeprecate, nextOldestVersion)
const $ = cheerio.load(newContent)
expect($('.example8').text()).toBe('\nAlpha\nBravo\n')
expect($('.example9').text()).toBe('\nAlpha\nBravo\n')
expect($('.example10').text()).toBe('\nPre\nBravo\n')
expect($('.example11').text()).toBe('\nPre\nBravo\n')
})
})