pockethost/plopfile.mjs
2024-02-22 13:22:28 -08:00

170 lines
5.6 KiB
JavaScript

import chalk from 'chalk'
import { execSync } from 'child_process'
import { readFileSync } from 'fs'
import yaml from 'js-yaml'
import ora from 'ora'
import { join } from 'path'
import { cwd } from 'process'
import factory from 'rizzdown'
/** @typedef {import('plop').NodePlopAPI} Plop */
export default function (/** @type {Plop} */ plop) {
plop.setHelper('isoTimestamp', function () {
return new Date().toISOString()
})
plop.setHelper('yamlEncode', function (text) {
return yaml.dump(text).trim()
})
plop.setGenerator('blog-article', {
description: 'Generate a new blog article',
prompts: [
{
type: 'input',
name: 'synopsis',
message: '30-50 word synopsis of the news you wish to announce',
},
],
actions: [
async function (data) {
const profilePath = join(cwd(), `.rizzdown/blog`)
const subjectMatter = data.synopsis
const { factory } = await import('rizzdown')
const { generate } = factory({ profilePath, subjectMatter })
const spin = async (title, prompt) => {
const spinner = ora().start(title)
const res = await generate(prompt, {})
spinner.stopAndPersist({ symbol: chalk.green(`✔︎`) })
return res
}
data.title = await spin(
`Generating title...`,
`A title for this blog post, no more than 10 words. No exaggerations or puffery. Factual. ASCII characters only. Do not enclose in quotations.`,
)
data.description = await spin(
`Generating description...`,
`An OpenGraph summary/description for this blog post, no more than 50 words. A call to action. Factual. ASCII characters only.`,
)
data.summary = await spin(
`Generating summary...`,
`A one-paragraph introductory summary. ASCII characters only.`,
)
data.detail = await spin(
`Generating detail...`,
`A detailed analysis of the importance and use of this news. ASCII characters only.`,
)
console.log({ data })
},
{
type: 'add',
path: 'frontends/lander/content/blog/{{dashCase title}}.md',
templateFile: 'plop-templates/blog.hbs',
},
],
})
plop.setGenerator('blog-release', {
description: 'Generate a new release announcement',
prompts: [
{
type: 'list',
name: 'releaseType',
choices: ['major', 'minor', 'patch'],
message: `What type of release is this?`,
default: 2,
},
{
type: 'input',
name: 'summary',
message: `What is this release about, generally?`,
},
],
actions: (data) => {
if (!data) throw new Error(`data expected`)
return [
async () => {
const { releaseType, summary } = data
const commitsSinceLast = execSync(
`git log $(git describe --tags --abbrev=0)..HEAD --oneline | grep -E "fix:|enh:|feat:" | sed 's/^[^ ]*/\*/' | sort`,
)
.toString()
.replace(/^\S+?\s/gm, '')
.split(/\n/)
.filter((v) => !!v)
console.log(`Commits since last release:`)
commitsSinceLast.forEach((line) => console.log(` * ${line}`))
execSync(`npm version --no-git-tag-version ${releaseType}`)
const { version } = JSON.parse(
readFileSync(join(cwd(), './package.json')).toString(),
)
console.log(
`Great, a ${releaseType} release. The new version will be ${version}.`,
)
const summaries = []
// for (let i = 0; i < commitsSinceLast.length; i++) {
// const commit = commitsSinceLast[i]
// const { summary } = await inquirer.prompt({
// type: 'input',
// name: 'summary',
// message: `Please summarize this commit log (enter to leave as is):`,
// default: commit,
// })
// summaries.push(summary)
// }
summaries.push(...commitsSinceLast)
const profilePath = join(cwd(), `.rizzdown/blog`)
const subjectMatter = `# PocketHost v${version} release\n\n## Summary\n\n${summary}\n\n###Detailed updates\n\n${summaries.join(
`\n`,
)}`
const { generate } = factory({ profilePath, subjectMatter })
const spin = async (
/** @type {string} */ title,
/** @type {string} */ prompt,
) => {
const spinner = ora().start(title)
const res = await generate(prompt, {})
spinner.stopAndPersist({ symbol: chalk.green(`✔︎`) })
return res
}
data.version = version
data.title = `PocketHost v${version}`
data.opengraph = await spin(
`Generating description...`,
`An OpenGraph summary/description for this blog post, no more than 50 words. A call to action. Factual. ASCII characters only. Use reflective and dry technical language, no calls to action or 'consumer' sounding language.`,
)
data.overview = await spin(
`Generating overview...`,
`1-3 short paragraphs organizing the major changes and discussing their importance. ASCII characters only. Use reflective and dry technical language, no calls to action or 'consumer' sounding language`,
)
data.change_log = summaries.map((line) => `* ${line}`).join(`\n`)
},
{
type: 'add',
path: 'frontends/lander/content/blog/{{dashCase title}}.md',
templateFile: 'plop-templates/blog.hbs',
},
]
},
})
}