chore(script): multiselect publishing prompt
This commit is contained in:
79
scripts/lib/getPackageDetails.ts
Normal file
79
scripts/lib/getPackageDetails.ts
Normal file
@@ -0,0 +1,79 @@
|
||||
import path from 'path'
|
||||
import fse from 'fs-extra'
|
||||
import chalk from 'chalk'
|
||||
import chalkTemplate from 'chalk-template'
|
||||
import simpleGit from 'simple-git'
|
||||
|
||||
const git = simpleGit()
|
||||
const packagesDir = path.resolve(__dirname, '../../packages')
|
||||
|
||||
export type PackageDetails = {
|
||||
name: string
|
||||
newCommits: number
|
||||
shortName: string
|
||||
packagePath: string
|
||||
publishedVersion: string
|
||||
publishDate: string
|
||||
version: string
|
||||
}
|
||||
|
||||
export const getPackageDetails = async (): Promise<PackageDetails[]> => {
|
||||
const packageDirs = fse.readdirSync(packagesDir).filter((d) => d !== 'eslint-config-payload')
|
||||
const packageDetails = await Promise.all(
|
||||
packageDirs.map(async (dirName) => {
|
||||
const packageJson = await fse.readJson(`${packagesDir}/${dirName}/package.json`)
|
||||
const isPublic = packageJson.private !== true
|
||||
if (!isPublic) return null
|
||||
|
||||
// Get published version from npm
|
||||
const json = await fetch(`https://registry.npmjs.org/${packageJson.name}`).then((res) =>
|
||||
res.json(),
|
||||
)
|
||||
|
||||
const publishedVersion = json?.['dist-tags']?.latest
|
||||
const publishDate = json?.time?.[publishedVersion]
|
||||
|
||||
const prevGitTag = `${dirName}/${packageJson.version}`
|
||||
const prevGitTagHash = await git.revparse(prevGitTag)
|
||||
|
||||
const newCommits = await git.log({
|
||||
from: prevGitTagHash,
|
||||
file: `packages/${dirName}`,
|
||||
})
|
||||
|
||||
return {
|
||||
name: packageJson.name as string,
|
||||
newCommits: newCommits.total,
|
||||
shortName: dirName,
|
||||
packagePath: `packages/${dirName}`,
|
||||
publishedVersion,
|
||||
publishDate,
|
||||
version: packageJson.version,
|
||||
}
|
||||
}),
|
||||
)
|
||||
|
||||
return packageDetails.filter((p): p is Exclude<typeof p, null> => p !== null)
|
||||
}
|
||||
|
||||
export const showPackageDetails = (details: PackageDetails[]) => {
|
||||
console.log(chalkTemplate`
|
||||
|
||||
{bold Packages:}
|
||||
|
||||
${details
|
||||
.map((p) => {
|
||||
const name = p?.newCommits ? chalk.bold.green(p?.shortName.padEnd(28)) : p?.shortName.padEnd(28)
|
||||
const publishData = `${p?.publishedVersion} at ${p?.publishDate
|
||||
.split(':')
|
||||
.slice(0, 2)
|
||||
.join(':')
|
||||
.replace('T', ' ')}`
|
||||
const newCommits = `${p?.newCommits ? `${chalk.bold.green(p?.newCommits)} new commits` : ''}`
|
||||
|
||||
return ` ${name}${publishData} ${newCommits}`
|
||||
})
|
||||
.join('\n')}
|
||||
|
||||
`)
|
||||
}
|
||||
@@ -1,74 +1,10 @@
|
||||
import path from 'path'
|
||||
import fse from 'fs-extra'
|
||||
import chalk from 'chalk'
|
||||
import chalkTemplate from 'chalk-template'
|
||||
import simpleGit from 'simple-git'
|
||||
|
||||
const git = simpleGit()
|
||||
|
||||
const packagesDir = path.resolve(__dirname, '../packages')
|
||||
import { getPackageDetails, showPackageDetails } from './lib/getPackageDetails'
|
||||
|
||||
async function main() {
|
||||
// List all public packages excluding eslint-config-payload
|
||||
const packageDirs = fse.readdirSync(packagesDir).filter((d) => d !== 'eslint-config-payload')
|
||||
const packageDetails = await Promise.all(
|
||||
packageDirs.map(async (dirName) => {
|
||||
const packageJson = await fse.readJson(`${packagesDir}/${dirName}/package.json`)
|
||||
const isPublic = packageJson.private !== true
|
||||
if (!isPublic) return null
|
||||
|
||||
// Get published version from npm
|
||||
const json = await fetch(`https://registry.npmjs.org/${packageJson.name}`).then((res) =>
|
||||
res.json(),
|
||||
)
|
||||
|
||||
const publishedVersion = json?.['dist-tags']?.latest
|
||||
const publishDate = json?.time?.[publishedVersion]
|
||||
|
||||
const prevGitTag = `${dirName}/${packageJson.version}`
|
||||
const prevGitTagHash = await git.revparse(prevGitTag)
|
||||
|
||||
const newCommits = await git.log({
|
||||
from: prevGitTagHash,
|
||||
file: `packages/${dirName}`,
|
||||
})
|
||||
|
||||
return {
|
||||
name: packageJson.name,
|
||||
newCommits: newCommits.total,
|
||||
packageDir: dirName,
|
||||
packagePath: `packages/${dirName}`,
|
||||
publishedVersion,
|
||||
publishDate,
|
||||
version: packageJson.version,
|
||||
}
|
||||
}),
|
||||
)
|
||||
console.log(chalkTemplate`
|
||||
|
||||
{bold Packages:}
|
||||
|
||||
${packageDetails
|
||||
.map((p) => {
|
||||
const name = p?.newCommits
|
||||
? chalk.bold.green(p?.packageDir.padEnd(28))
|
||||
: p?.packageDir.padEnd(28)
|
||||
const publishData = `${p?.publishedVersion} at ${p?.publishDate
|
||||
.split(':')
|
||||
.slice(0, 2)
|
||||
.join(':')
|
||||
.replace('T', ' ')}`
|
||||
const newCommits = `${p?.newCommits ? `${chalk.bold.green(p?.newCommits)} new commits` : ''}`
|
||||
|
||||
return ` ${name}${publishData} ${newCommits}`
|
||||
})
|
||||
.join('\n')}
|
||||
|
||||
`)
|
||||
const packageDetails = await getPackageDetails()
|
||||
showPackageDetails(packageDetails)
|
||||
}
|
||||
|
||||
// console.log(packageNames)
|
||||
|
||||
main().catch((error) => {
|
||||
console.error(error)
|
||||
process.exit(1)
|
||||
|
||||
@@ -4,32 +4,49 @@ import chalk from 'chalk'
|
||||
import prompts from 'prompts'
|
||||
import minimist from 'minimist'
|
||||
import chalkTemplate from 'chalk-template'
|
||||
import { PackageDetails, getPackageDetails, showPackageDetails } from './lib/getPackageDetails'
|
||||
|
||||
const execOpts: ExecSyncOptions = { stdio: 'inherit' }
|
||||
const args = minimist(process.argv.slice(2))
|
||||
|
||||
async function main() {
|
||||
const { _: packageNames, tag = 'latest', bump = 'patch' } = args
|
||||
const { tag = 'latest', bump = 'patch' } = args
|
||||
|
||||
if (packageNames.length === 0) {
|
||||
const packageDetails = await getPackageDetails()
|
||||
showPackageDetails(packageDetails)
|
||||
|
||||
const { packagesToRelease } = (await prompts({
|
||||
type: 'multiselect',
|
||||
name: 'packagesToRelease',
|
||||
message: 'Select packages to release',
|
||||
instructions: 'Space to select. Enter to submit.',
|
||||
choices: packageDetails.map((p) => {
|
||||
const title = p?.newCommits ? chalk.bold.green(p?.shortName) : p?.shortName
|
||||
return {
|
||||
title,
|
||||
value: p.shortName,
|
||||
}
|
||||
}),
|
||||
})) as { packagesToRelease: string[] }
|
||||
|
||||
if (!packagesToRelease) {
|
||||
abort()
|
||||
}
|
||||
|
||||
if (packagesToRelease.length === 0) {
|
||||
abort('Please specify a package to publish')
|
||||
}
|
||||
|
||||
if (packageNames.find((p) => p === 'payload' && packageNames.length > 1)) {
|
||||
abort('Cannot publish payload with other packages')
|
||||
if (packagesToRelease.find((p) => p === 'payload' && packagesToRelease.length > 1)) {
|
||||
abort('Cannot publish payload with other packages. Release Payload first.')
|
||||
}
|
||||
|
||||
// Get current version of each package from package.json
|
||||
const packageDetails = await Promise.all(
|
||||
packageNames.map(async (packageName) => {
|
||||
const packageDir = `packages/${packageName}`
|
||||
if (!(await fse.pathExists(packageDir))) {
|
||||
abort(`Package path ${packageDir} does not exist`)
|
||||
}
|
||||
const packageObj = await fse.readJson(`${packageDir}/package.json`)
|
||||
|
||||
return { name: packageName, version: packageObj.version, dir: packageDir }
|
||||
}),
|
||||
const packageMap = packageDetails.reduce(
|
||||
(acc, p) => {
|
||||
acc[p.shortName] = p
|
||||
return acc
|
||||
},
|
||||
{} as Record<string, PackageDetails>,
|
||||
)
|
||||
|
||||
console.log(chalkTemplate`
|
||||
@@ -38,10 +55,15 @@ async function main() {
|
||||
{bold.yellow Bump: ${bump}}
|
||||
{bold.yellow Tag: ${tag}}
|
||||
|
||||
${packageDetails.map((p) => ` ${p.name} - current: ${p.version}`).join('\n')}
|
||||
${packagesToRelease
|
||||
.map((p) => {
|
||||
const { shortName, version } = packageMap[p]
|
||||
return ` ${shortName.padEnd(24)} ${version}`
|
||||
})
|
||||
.join('\n')}
|
||||
`)
|
||||
|
||||
const confirmPublish = await confirm(`Publish ${packageNames.length} package(s)?`)
|
||||
const confirmPublish = await confirm(`Publish ${packagesToRelease.length} package(s)?`)
|
||||
|
||||
if (!confirmPublish) {
|
||||
abort()
|
||||
@@ -49,26 +71,26 @@ ${packageDetails.map((p) => ` ${p.name} - current: ${p.version}`).join('\n')}
|
||||
|
||||
const results: { name: string; success: boolean }[] = []
|
||||
|
||||
for (const pkg of packageDetails) {
|
||||
const { dir, name } = pkg
|
||||
for (const pkg of packagesToRelease) {
|
||||
const { packagePath, shortName } = packageMap[pkg]
|
||||
|
||||
try {
|
||||
console.log(chalk.bold(`\n\nPublishing ${name}...\n\n`))
|
||||
console.log(chalk.bold(`\n\nPublishing ${shortName}...\n\n`))
|
||||
|
||||
execSync(`npm --no-git-tag-version --prefix ${dir} version ${bump}`, execOpts)
|
||||
execSync(`git add ${dir}/package.json`, execOpts)
|
||||
execSync(`npm --no-git-tag-version --prefix ${packagePath} version ${bump}`, execOpts)
|
||||
execSync(`git add ${packagePath}/package.json`, execOpts)
|
||||
|
||||
const packageObj = await fse.readJson(`${dir}/package.json`)
|
||||
const packageObj = await fse.readJson(`${packagePath}/package.json`)
|
||||
const newVersion = packageObj.version
|
||||
|
||||
const tagName = `${name}/${newVersion}`
|
||||
const tagName = `${shortName}/${newVersion}`
|
||||
execSync(`git commit -m "chore(release): ${tagName}"`, execOpts)
|
||||
execSync(`git tag -a ${tagName} -m "${tagName}"`, execOpts)
|
||||
execSync(`pnpm publish -C ${dir} --no-git-checks`, execOpts)
|
||||
results.push({ name, success: true })
|
||||
execSync(`pnpm publish -C ${packagePath} --no-git-checks`, execOpts)
|
||||
results.push({ name: shortName, success: true })
|
||||
} catch (error) {
|
||||
console.error(chalk.bold.red(`ERROR: ${error.message}`))
|
||||
results.push({ name, success: false })
|
||||
results.push({ name: shortName, success: false })
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user