From eb55f0fc20ddfc3a5c51b36b66c87c85dd9fa6e4 Mon Sep 17 00:00:00 2001 From: Rachael Sewell Date: Tue, 27 Jun 2023 15:00:31 -0700 Subject: [PATCH] update liquid deprecation script (#38644) --- .../scripts/remove-deprecated-frontmatter.js | 13 ++-- .../scripts/remove-liquid-statements.js | 6 +- .../scripts/remove-version-markup.js | 52 ++++++++++------ .../tests/remove-liquid-statements.js | 60 +++++++++---------- 4 files changed, 77 insertions(+), 54 deletions(-) diff --git a/src/ghes-releases/scripts/remove-deprecated-frontmatter.js b/src/ghes-releases/scripts/remove-deprecated-frontmatter.js index a41843bb93c2..e469050bc66b 100644 --- a/src/ghes-releases/scripts/remove-deprecated-frontmatter.js +++ b/src/ghes-releases/scripts/remove-deprecated-frontmatter.js @@ -1,3 +1,5 @@ +// Returns false when no changes were made to the frontmatter, +// true when changes were made. export default function removeDeprecatedFrontmatter( file, frontmatterVersions, @@ -5,13 +7,13 @@ export default function removeDeprecatedFrontmatter( nextOldestRelease ) { // skip files with no Enterprise Server versions frontmatter - if (!frontmatterVersions) return - if (!frontmatterVersions.ghes) return + 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 + 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: '*' @@ -22,7 +24,7 @@ export default function removeDeprecatedFrontmatter( if (appliesToAllSupportedGhesReleases) { frontmatterVersions.ghes = '*' - return + return true } // if the release to deprecate is 2.13, and the FM is either '=2.13', '<2.13', '<=2.13', or '<2.14', @@ -39,9 +41,10 @@ export default function removeDeprecatedFrontmatter( console.log( `Warning! ${file} has frontmatter versioning that will make it never appear when ${releaseToDeprecate} is deprecated. The article should probably be removed.` ) - return + return false } delete frontmatterVersions.ghes + return true } } diff --git a/src/ghes-releases/scripts/remove-liquid-statements.js b/src/ghes-releases/scripts/remove-liquid-statements.js index 4296a00ec9ac..a6aed90f9ffb 100644 --- a/src/ghes-releases/scripts/remove-liquid-statements.js +++ b/src/ghes-releases/scripts/remove-liquid-statements.js @@ -22,10 +22,11 @@ const tokenize = (str) => { // 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 + if (!blocks.length) return { newContent, contentChanged } // Decorate those blocks with more GHES versioning information. const versionBlocks = getVersionBlocks(blocks) @@ -233,6 +234,7 @@ export default function removeLiquidStatements(content, release, nextOldestRelea // 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 @@ -246,7 +248,7 @@ export default function removeLiquidStatements(content, release, nextOldestRelea } }) - return newContent + return { newContent, contentChanged } } // Hack to use a regex with lastIndexOf. diff --git a/src/ghes-releases/scripts/remove-version-markup.js b/src/ghes-releases/scripts/remove-version-markup.js index ecb0da717eb8..2233cc2f15ed 100755 --- a/src/ghes-releases/scripts/remove-version-markup.js +++ b/src/ghes-releases/scripts/remove-version-markup.js @@ -60,37 +60,55 @@ 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 - removeDeprecatedFrontmatter(file, data.versions, release, nextOldestRelease) + fileChanged ||= removeDeprecatedFrontmatter(file, data.versions, release, nextOldestRelease) // update liquid statements in content and data - const newContent = removeLiquidStatements(content, release, nextOldestRelease, file) + 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 newValue = removeLiquidStatements(value, release, nextOldestRelease, file) - data[key] = newValue + const { newContent, contentChanged } = removeLiquidStatements( + value, + release, + nextOldestRelease, + file + ) + fileChanged ||= contentChanged + data[key] = newContent } } - // 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 = '' - } + // 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 }) - // 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 + } - // if the content file is now empty, remove it - if (newContents.replace(/\s/g, '').length === 0) { - fs.unlinkSync(file) - continue + fs.writeFileSync(file, newContents) } - - fs.writeFileSync(file, newContents) } console.log(`Removed GHES ${release} markup from content and data files! Review and run tests.`) diff --git a/src/ghes-releases/tests/remove-liquid-statements.js b/src/ghes-releases/tests/remove-liquid-statements.js index 1a1baf917f01..01e70d7cb8aa 100644 --- a/src/ghes-releases/tests/remove-liquid-statements.js +++ b/src/ghes-releases/tests/remove-liquid-statements.js @@ -39,9 +39,9 @@ function processFrontmatter(contents, file) { describe('removing liquid statements only', () => { test('removes liquid statements that specify "greater than version to deprecate"', async () => { - let contents = await fs.readFile(greaterThan, 'utf8') - contents = removeLiquidStatements(contents, versionToDeprecate, nextOldestVersion) - const $ = cheerio.load(contents) + 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 @@ -65,9 +65,9 @@ Alpha\n\n{% else %}\n\nBravo\n\n{% ifversion ghes > 2.16 %}\n\nCharlie\n {% else %}\n\nBravo\n\n{% endif %}`) }) test('removes liquid statements that specify all known versions, including some nested conditionals"', async () => { - let contents = await fs.readFile(unnecessary, 'utf8') - contents = removeLiquidStatements(contents, versionToDeprecate, nextOldestVersion) - const $ = cheerio.load(contents) + 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 %}` @@ -84,9 +84,9 @@ Alpha\n\n{% else %}\n\nBravo\n\n{% ifversion ghes > 2.16 %}\n\nCharlie\n }) test('removes liquid statements that specify "and greater than version to deprecate"', async () => { - let contents = await fs.readFile(andGreaterThan1, 'utf8') - contents = removeLiquidStatements(contents, versionToDeprecate, nextOldestVersion) - const $ = cheerio.load(contents) + 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 %}' ) @@ -102,9 +102,9 @@ Alpha\n\n{% ifversion ghes > 2.16 %}\n\nBravo\n\n{% endif %}\n\n{% else %}\n\nCh }) test('removes liquid statements that specify "and greater than version to deprecate" (alternate format)', async () => { - let contents = await fs.readFile(andGreaterThan2, 'utf8') - contents = removeLiquidStatements(contents, versionToDeprecate, nextOldestVersion) - const $ = cheerio.load(contents) + 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 %}`) @@ -117,9 +117,9 @@ Alpha\n\n{% ifversion not fpt %}\n\nBravo\n\n{% endif %}\n\n{% else %}\n\nCharli }) test('removes liquid statements that specify "not equals version to deprecate"', async () => { - let contents = await fs.readFile(notEquals, 'utf8') - contents = removeLiquidStatements(contents, versionToDeprecate, nextOldestVersion) - const $ = cheerio.load(contents) + 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 @@ -136,9 +136,9 @@ Alpha\n\n{% endif %}`) describe('removing liquid statements and content', () => { test('removes interior content and liquid statements that specify "equals version to deprecate"', async () => { - let contents = await fs.readFile(equals, 'utf8') - contents = removeLiquidStatements(contents, versionToDeprecate, nextOldestVersion) - const $ = cheerio.load(contents) + 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 @@ -152,9 +152,9 @@ Alpha\n\n{% else %}\n\nCharlie\n\n{% endif %}`) }) test('removes interior content and liquid statements that specify "less than next oldest than version to deprecate"', async () => { - let contents = await fs.readFile(lessThanNextOldest, 'utf8') - contents = removeLiquidStatements(contents, versionToDeprecate, nextOldestVersion) - const $ = cheerio.load(contents) + 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 %}' @@ -193,9 +193,9 @@ describe('updating frontmatter', () => { describe('whitespace', () => { test('does not add newlines when whitespace control is used', async () => { - let contents = await fs.readFile(whitespace, 'utf8') - contents = removeLiquidStatements(contents, versionToDeprecate, nextOldestVersion) - const $ = cheerio.load(contents) + 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') @@ -203,9 +203,9 @@ describe('whitespace', () => { }) test('does not add newlines when no newlines are present', async () => { - let contents = await fs.readFile(whitespace, 'utf8') - contents = removeLiquidStatements(contents, versionToDeprecate, nextOldestVersion) - const $ = cheerio.load(contents) + 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' @@ -214,9 +214,9 @@ describe('whitespace', () => { }) test('only remove newlines when tag starts at beginning of line', async () => { - let contents = await fs.readFile(whitespace, 'utf8') - contents = removeLiquidStatements(contents, versionToDeprecate, nextOldestVersion) - const $ = cheerio.load(contents) + 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')