update old script
This commit is contained in:
17
script/helpers/walk-files.js
Normal file
17
script/helpers/walk-files.js
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
const path = require('path')
|
||||||
|
const walk = require('walk-sync')
|
||||||
|
|
||||||
|
// [start-readme]
|
||||||
|
//
|
||||||
|
// A helper that returns an array of files for a given path and file extension.
|
||||||
|
//
|
||||||
|
// [end-readme]
|
||||||
|
|
||||||
|
module.exports = function walkFiles (dir, ext, opts = {}) {
|
||||||
|
const dirPath = path.posix.join(process.cwd(), dir)
|
||||||
|
const walkSyncOpts = { includeBasePath: true, directories: false }
|
||||||
|
|
||||||
|
return walk(dirPath, walkSyncOpts)
|
||||||
|
.filter(file => file.endsWith(ext) && !file.endsWith('README.md'))
|
||||||
|
.filter(file => opts.includeEarlyAccess ? file : !file.includes('/early-access/'))
|
||||||
|
}
|
||||||
@@ -1,129 +1,80 @@
|
|||||||
#!/usr/bin/env node
|
#!/usr/bin/env node
|
||||||
|
|
||||||
const assert = require('assert')
|
|
||||||
const fs = require('fs')
|
const fs = require('fs')
|
||||||
const path = require('path')
|
const path = require('path')
|
||||||
const walk = require('walk-sync')
|
const mkdirp = require('mkdirp').sync
|
||||||
|
const program = require('commander')
|
||||||
const { execSync } = require('child_process')
|
const { execSync } = require('child_process')
|
||||||
const matter = require('gray-matter')
|
const frontmatter = require('../lib/read-frontmatter')
|
||||||
const addRedirectToFrontmatter = require('./helpers/add-redirect-to-frontmatter')
|
const addRedirectToFrontmatter = require('./helpers/add-redirect-to-frontmatter')
|
||||||
const contentDir = path.join(__dirname, '../content')
|
const walkFiles = require('./helpers/walk-files')
|
||||||
|
const contentFiles = walkFiles('content', '.md')
|
||||||
|
const contentDir = path.posix.join(process.cwd(), 'content')
|
||||||
|
|
||||||
// [start-readme]
|
// [start-readme]
|
||||||
//
|
//
|
||||||
// Pass this script three arguments:
|
// Move the files from a category directory to a top-level product and add redirects.
|
||||||
// 1. current category path (e.g., `github/automating-your-workflows-with-github-actions`)
|
|
||||||
// 2. new product ID (e.g., `actions`)
|
|
||||||
// 3. new product name in quotes (e.g., `"GitHub Actions"`)
|
|
||||||
// and it does everything that needs to be done to make the category into a new product.
|
|
||||||
//
|
//
|
||||||
// [end-readme]
|
// [end-readme]
|
||||||
|
|
||||||
// derive global values
|
program
|
||||||
const [relativePath, productId, productName] = process.argv.slice(2)
|
.description('Move a category-level docs set to the product level.')
|
||||||
assert(relativePath, 'first arg must be a path to an existing category, e.g., github/working-with-github-pages')
|
.requiredOption('-c, --category <PATH>', 'Provide the path of the existing category, e.g., github/github-pages')
|
||||||
assert(productId, 'second arg must be the ID of the new product, e.g., pages')
|
.requiredOption('-p, --product <PATH>', 'Provide the path of the new product, e.g., pages')
|
||||||
assert(productName, 'third arg must be the full name of the new product in quotes, e.g., "GitHub Pages"')
|
.parse(process.argv)
|
||||||
assert.strictEqual(relativePath.split('/').length, 2, 'first arg must only contain one slash, e.g., github/working-with-github-pages')
|
|
||||||
|
|
||||||
const oldCategoryDir = path.join(contentDir, relativePath)
|
const oldCategory = program.opts().category.replace('content/', '')
|
||||||
assert(fs.existsSync(oldCategoryDir), `directory does not exist: ${oldCategoryDir}`)
|
const newProduct = program.opts().product.replace('content/', '')
|
||||||
|
|
||||||
const productDir = path.join(contentDir, productId)
|
const [oldProductId, oldCategoryId] = oldCategory.split('/')
|
||||||
|
const oldCategoryPath = path.posix.join(contentDir, oldCategory)
|
||||||
|
const oldProductPath = path.posix.join(contentDir, oldProductId)
|
||||||
|
|
||||||
const [oldproductId, categoryName] = relativePath.split('/')
|
if (!fs.existsSync(oldProductPath)) {
|
||||||
|
console.error(`Error! Can't find ${oldProductPath}`)
|
||||||
// do all the moving/renaming/updating
|
process.exit(1)
|
||||||
makeNewProductDir()
|
|
||||||
moveFilesToNewDir()
|
|
||||||
createNewProductToc()
|
|
||||||
removeCategoryFromOldProductToc()
|
|
||||||
updateFrontmatter()
|
|
||||||
|
|
||||||
console.log(`Moved files to content/${productId} and updated frontmatter!\n\nNext steps:\n`)
|
|
||||||
|
|
||||||
// display data that needs to be manually added to lib files
|
|
||||||
printProductsModuleUpdate()
|
|
||||||
printFrontmatterSchemaUpdate()
|
|
||||||
|
|
||||||
function makeNewProductDir () {
|
|
||||||
if (!fs.existsSync(productDir)) {
|
|
||||||
execSync(`mkdir ${productDir}`)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function moveFilesToNewDir () {
|
const oldCategoryFiles = contentFiles.filter(file => file.includes(`/${oldCategoryId}/`))
|
||||||
execSync(`git mv ${oldCategoryDir} ${productDir}`)
|
|
||||||
|
if (!oldCategoryFiles.length) {
|
||||||
|
console.error(`Error! Can't find ${oldCategory} files`)
|
||||||
|
process.exit(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
function createNewProductToc () {
|
const newProductPath = path.posix.join(process.cwd(), 'content', newProduct)
|
||||||
const productTocPath = path.join(productDir, 'index.md')
|
|
||||||
const data = {}
|
|
||||||
data.title = `${productName} Documentation`
|
|
||||||
data.productVersions = {}
|
|
||||||
data.productVersions[productId] = '*'
|
|
||||||
const content = `\n{% link_with_intro /${categoryName} %}`
|
|
||||||
|
|
||||||
fs.writeFileSync(productTocPath, matter.stringify(content, data, { lineWidth: 10000 }))
|
main()
|
||||||
}
|
|
||||||
|
|
||||||
function removeCategoryFromOldProductToc () {
|
function main () {
|
||||||
const oldProductTocPath = path.join(contentDir, oldproductId, 'index.md')
|
// Create the new product dir.
|
||||||
const tocContents = fs.readFileSync(oldProductTocPath, 'utf8')
|
mkdirp(newProductPath)
|
||||||
const { content, data } = matter(tocContents)
|
|
||||||
|
|
||||||
const link = `(\n<!-- if page.version.*? -->)?\n{% link_in_list /${categoryName} %}\n(<!-- endif -->)?`
|
// Add redirects to the frontmatter of the to-be-moved files.
|
||||||
|
oldCategoryFiles.forEach(file => {
|
||||||
const newContent = content.replace(new RegExp(link), '')
|
const { content, data } = frontmatter(fs.readFileSync(file, 'utf8'))
|
||||||
|
const redirectString = file
|
||||||
fs.writeFileSync(oldProductTocPath, matter.stringify(newContent, data, { lineWidth: 10000 }))
|
.replace(contentDir, '')
|
||||||
}
|
.replace('index.md', '')
|
||||||
|
.replace('.md', '')
|
||||||
function updateFrontmatter () {
|
|
||||||
const newCategoryDir = path.join(productDir, categoryName)
|
|
||||||
|
|
||||||
// for every article in the category, update productVersions and redirect frontmatter
|
|
||||||
walk(newCategoryDir, { includeBasePath: true }).forEach(file => {
|
|
||||||
const articleContents = fs.readFileSync(file, 'utf8')
|
|
||||||
const { content, data } = matter(articleContents)
|
|
||||||
|
|
||||||
const baseFilename = file.endsWith('index.md') ? '' : path.basename(file, '.md')
|
|
||||||
|
|
||||||
const redirectString = path.join('/', oldproductId, categoryName, baseFilename)
|
|
||||||
data.redirect_from = addRedirectToFrontmatter(data.redirect_from, redirectString)
|
data.redirect_from = addRedirectToFrontmatter(data.redirect_from, redirectString)
|
||||||
|
fs.writeFileSync(file, frontmatter.stringify(content, data, { lineWidth: 10000 }))
|
||||||
data.productVersions = {}
|
|
||||||
data.productVersions[productId] = '*'
|
|
||||||
|
|
||||||
const newContents = matter.stringify(content, data, { lineWidth: 10000 })
|
|
||||||
fs.writeFileSync(file, newContents)
|
|
||||||
})
|
})
|
||||||
}
|
|
||||||
|
// // Move the files.
|
||||||
function printProductsModuleUpdate () {
|
execSync(`git mv ${oldCategoryPath}/* ${newProductPath}`)
|
||||||
const newProduct = {
|
|
||||||
id: productId,
|
// Remove the category from the old product TOC.
|
||||||
name: productName,
|
const oldProductTocPath = path.posix.join(oldProductPath, 'index.md')
|
||||||
href: path.join('/', productId),
|
const productToc = frontmatter(fs.readFileSync(oldProductTocPath, 'utf8'))
|
||||||
dir: path.join('content/', productId),
|
productToc.data.children = productToc.data.children.filter(child => child !== `/${oldCategoryId}`)
|
||||||
toc: path.join('content/', productId, 'index.md')
|
fs.writeFileSync(oldProductTocPath, frontmatter.stringify(productToc.content, productToc.data, { lineWidth: 10000 }))
|
||||||
}
|
|
||||||
const obj = {}
|
// Add the new product to the homepage TOC.
|
||||||
obj[productId] = newProduct
|
const homepage = path.posix.join(contentDir, 'index.md')
|
||||||
|
const homepageToc = frontmatter(fs.readFileSync(homepage, 'utf8'))
|
||||||
console.log('1. Add the following block to lib/products.js. Note: the order of this file determines the product order everywhere on the site.\n')
|
homepageToc.data.children.push(newProduct)
|
||||||
console.log(obj)
|
fs.writeFileSync(homepage, frontmatter.stringify(homepageToc.content, homepageToc.data, { lineWidth: 10000 }))
|
||||||
}
|
|
||||||
|
console.log(`Moved ${oldCategory} files to ${newProduct}, added redirects, and updated TOCs!`)
|
||||||
function printFrontmatterSchemaUpdate () {
|
|
||||||
const newFrontmatter = {
|
|
||||||
type: 'string',
|
|
||||||
conform: '(add validSemverRange here)',
|
|
||||||
message: 'Must be a valid SemVer range'
|
|
||||||
}
|
|
||||||
const obj = {}
|
|
||||||
obj[productId] = newFrontmatter
|
|
||||||
|
|
||||||
console.log('\n2. Add the following block to the productVersions object in lib/frontmatter.js (ordered alphabetically). Make sure the \'conform\' property looks like the others. \n')
|
|
||||||
console.log(obj)
|
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user