LouisMazel/maz-ui

View on GitHub
changelog-generate.ts

Summary

Maintainability
A
2 hrs
Test Coverage
import { exec } from 'node:child_process'
import { existsSync, promises as fsp } from 'node:fs'
import {
  generateMarkDown,
  getGitDiff,
  parseCommits,
  loadChangelogConfig,
  syncGithubRelease,
} from 'changelogen'
import { version } from './lerna.json'

async function execPromise(command: string): Promise<{ stdout: string; stderr: string }> {
  return await new Promise((resolve, reject) => {
    exec(command, (error, stdout, stderr) => {
      if (error) {
        console.error(`🔴 [cli](${command}) Execution failed - ${error.message}.`)
        reject(error)
      } else {
        resolve({ stdout, stderr })
      }
    })
  })
}

async function updateChangelog() {
  // const { stdout: penultimateTag } = await execPromise("git tag --sort=-v:refname | sed -n '2p'")
  const { stdout: previousTag } = await execPromise("git tag --sort=-v:refname | sed -n '1p'")
  const previousTagTrimed = previousTag.trim()

  const newTag = `v${version.trim()}`

  await execPromise(`git tag ${newTag}`)
  await execPromise(`git push origin ${newTag}`)

  console.log('Tag pushed to GitHub.')
  console.log()

  const config = await loadChangelogConfig(process.cwd(), {
    from: previousTagTrimed,
    to: newTag,
  })

  const rawCommits = await getGitDiff(previousTagTrimed, newTag)
  const commits = parseCommits(rawCommits, config).filter((commit) => {
    return (
      config.types[commit.type] &&
      !(commit.type === 'chore' && ['release'].includes(commit.scope) && !commit.isBreaking)
    )
  })

  const newChangelog = await generateMarkDown(commits, config)

  let changelogMD: string

  if (typeof config.output === 'string' && existsSync(config.output)) {
    changelogMD = await fsp.readFile(config.output, 'utf8')
  } else {
    changelogMD = '# Changelog\n\n'
  }

  const lastEntry = changelogMD.match(/^###?\s+.*$/m)

  if (lastEntry) {
    changelogMD =
      changelogMD.slice(0, lastEntry.index) +
      newChangelog +
      '\n\n' +
      changelogMD.slice(lastEntry.index)
  } else {
    changelogMD += '\n' + newChangelog + '\n\n'
  }

  await fsp.writeFile(config.output as string, changelogMD)

  await execPromise('pnpm format')

  const changelogWithoutTitle = newChangelog.split('\n').slice(2).join('\n')

  console.log(changelogWithoutTitle)

  await execPromise(`git add -u`)
  await execPromise(`git commit -m "chore(release): bump version to ${newTag}"`)
  await execPromise(`git push origin HEAD`)

  try {
    await syncGithubRelease(config, {
      version: newTag.replace('v', ''),
      body: changelogWithoutTitle,
    })

    console.log()
    console.log('Release pushed to GitHub.')
    console.log()
  } catch (error: any) {
    console.error('error', error)
  }
}

updateChangelog()