shadcn-vue/scripts/changelog.ts
2024-04-01 20:30:33 +03:30

144 lines
4.5 KiB
TypeScript

import { execSync } from 'node:child_process'
import { consola } from 'consola'
import { versionBump } from 'bumpp'
import { type SemverBumpType, generateMarkDown, getCurrentGitBranch, loadChangelogConfig } from 'changelogen'
import { inc } from 'semver'
import { $fetch } from 'ofetch'
import { determineBumpType, getContributors, getLatestCommits, isGitClean, loadWorkspace, updateChangelogFile } from './utils'
import 'dotenv/config'
const remoteName = 'origin'
// Taken from Nuxt Repo (https://github.com/nuxt/nuxt/tree/main/scripts)
async function main() {
const isClean = isGitClean()
if (!isClean) {
consola.error('Git Repository is not clean, there are changes that are not commited yet.')
process.exit(1)
}
const workspace = await loadWorkspace(process.cwd())
const currentVersion = workspace.find('www').data.version
const bumpType: SemverBumpType = await determineBumpType() || 'patch'
const inferredNewVersion = inc(currentVersion, bumpType)
const isInferredOk = await consola.prompt(`Staring to release '${bumpType}' version from v${currentVersion} -> v${inferredNewVersion}, is this OK?`, {
type: 'confirm',
})
// exit process when no valid input is recieved
if (typeof isInferredOk !== 'boolean')
process.exit()
let newVersion: string | null = null
if (isInferredOk) {
newVersion = inferredNewVersion
}
else {
consola.info('Please select next version manually.')
const result = await versionBump({
currentVersion,
files: [],
})
newVersion = result.newVersion
}
consola.info(`Releasing version: v${newVersion}`)
const config = await loadChangelogConfig(process.cwd(), {})
const repo = config.repo.repo!
const releaseBranch = await getCurrentGitBranch()
consola.info(`Fetching latest commits ...`)
const allCommits = await getLatestCommits()
const filteredCommits = allCommits.filter((commit) => {
const isChore = commit.type === 'chore'
const isDependencyScope = commit.scope === 'deps'
const isBreaking = commit.isBreaking
const isTypeInConfig = config.types[commit.type]
return isTypeInConfig && (!isChore || !isDependencyScope || isBreaking)
})
consola.info(`Generating changelog ...`)
const changelog = await generateMarkDown(filteredCommits, config)
// Create and push a branch with bumped versions if it has not already been created
const branchExists = execSync(`git ls-remote --heads ${remoteName} v${newVersion}`).toString().trim().length > 0
if (!branchExists) {
consola.info(`Pushing a new branch named v${newVersion} to ${remoteName}`)
execSync(`git checkout -b v${newVersion}`, { stdio: 'ignore' })
for (const pkg of workspace.packages.filter(p => !p.data.private))
workspace.setVersion(pkg.data.name, newVersion!)
await workspace.save()
execSync(`git commit -am v${newVersion}`, { stdio: 'ignore' })
consola.info(`Updating changelog.md file ...`)
updateChangelogFile(`v${currentVersion}`, `v${newVersion}`)
execSync(`git commit --amend --no-edit`, { stdio: 'ignore' })
execSync(`git push -u ${remoteName} v${newVersion}`, { stdio: 'ignore' })
}
// Get the current PR for this release, if it exists
consola.info(`Fetching the created PR ...`)
const [currentPR] = await $fetch<any[]>(`https://api.github.com/repos/${repo}/pulls?head=v${newVersion}`)
const contributors = await getContributors(repo, process.env.githubToken!)
const releaseNotes = [
currentPR?.body,
changelog
.replace(/### ❤️ Contributors[\s\S]*$/, ''),
'### ❤️ Contributors',
contributors.map(c => `- ${c.name} (@${c.username})`).join('\n'),
].join('\n')
// Create a PR with release notes if none exists
if (!currentPR) {
consola.info(`Creating v${newVersion} PR with release notes`)
await $fetch(`https://api.github.com/repos/${repo}/pulls`, {
method: 'POST',
headers: {
Authorization: `token ${process.env.githubToken}`,
},
body: {
title: `v${newVersion}`,
head: `v${newVersion}`,
base: releaseBranch,
body: releaseNotes,
draft: true,
},
})
}
else {
consola.info(`Updating v${newVersion} PR with release notes`)
await $fetch(`https://api.github.com/repos/${repo}/pulls/${currentPR.number}`, {
method: 'PATCH',
headers: {
Authorization: `token ${process.env.githubToken}`,
},
body: {
body: releaseNotes,
},
})
}
consola.success(`Done, check https://github.com/${repo}/pulls`)
}
main().catch((err) => {
consola.error(err)
process.exit(1)
})