import { execSync } from 'node:child_process' import { $fetch } from 'ofetch' import { inc } from 'semver' import { generateMarkDown, getCurrentGitBranch, loadChangelogConfig } from 'changelogen' import { consola } from 'consola' import { determineBumpType, getContributors, getLatestCommits, getLatestReleasedTag, getLatestTag, getPreviousReleasedCommits, loadWorkspace } from './_utils' const handleSeparateBranch = true async function main () { const releaseBranch = await getCurrentGitBranch() const workspace = await loadWorkspace(process.cwd()) const config = await loadChangelogConfig(process.cwd(), {}) const prevMessages = new Set(handleSeparateBranch ? await getPreviousReleasedCommits().then(r => r.map(c => c.message)) : []) const commits = await getLatestCommits().then(commits => commits.filter( c => config.types[c.type] && !(c.type === 'chore' && c.scope === 'deps') && !prevMessages.has(c.message), )) const bumpType = await determineBumpType() || 'patch' const newVersion = inc(workspace.find('nuxt').data.version, bumpType) const changelog = await generateMarkDown(commits, config) // Create and push a branch with bumped versions if it has not already been created const branchExists = execSync(`git ls-remote --heads origin v${newVersion}`).toString().trim().length > 0 if (!branchExists) { execSync('git config --global user.email "daniel@roe.dev"') execSync('git config --global user.name "Daniel Roe"') execSync(`git checkout -b v${newVersion}`) 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}`) execSync(`git push -u origin v${newVersion}`) } // Get the current PR for this release, if it exists const [currentPR] = await $fetch(`https://api.github.com/repos/nuxt/nuxt/pulls?head=nuxt:v${newVersion}`) const contributors = await getContributors() const latestTag = await getLatestTag() const previousReleasedTag = handleSeparateBranch ? await getLatestReleasedTag() : latestTag const releaseNotes = [ currentPR?.body.replace(/## 👉 Changelog[\s\S]*$/, '') || `> ${newVersion} is the next ${bumpType} release.\n>\n> **Timetable**: to be announced.`, '## 👉 Changelog', changelog .replace(/^## v.*\n/, '') .replace(`...${releaseBranch}`, `...v${newVersion}`) .replace(/### ❤️ Contributors[\s\S]*$/, '') .replace(/[\n\r]+/g, '\n') .replace(latestTag, previousReleasedTag), '### ❤️ Contributors', contributors.map(c => `- ${c.name} (@${c.username})`).join('\n'), ].join('\n') // Create a PR with release notes if none exists if (!currentPR) { return await $fetch('https://api.github.com/repos/nuxt/nuxt/pulls', { method: 'POST', headers: { Authorization: `token ${process.env.GITHUB_TOKEN}`, }, body: { title: `v${newVersion}`, head: `v${newVersion}`, base: releaseBranch, body: releaseNotes, draft: true, }, }) } // Update release notes if the pull request does exist await $fetch(`https://api.github.com/repos/nuxt/nuxt/pulls/${currentPR.number}`, { method: 'PATCH', headers: { Authorization: `token ${process.env.GITHUB_TOKEN}`, }, body: { body: releaseNotes, }, }) } main().catch((err) => { consola.error(err) process.exit(1) })