Skip to content

Commit

Permalink
feat: refactor cli
Browse files Browse the repository at this point in the history
  • Loading branch information
antfu committed Jun 13, 2022
1 parent 2323832 commit b8412b1
Show file tree
Hide file tree
Showing 7 changed files with 151 additions and 118 deletions.
1 change: 1 addition & 0 deletions build.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { defineBuildConfig } from 'unbuild'
export default defineBuildConfig({
entries: [
'src/index',
'src/cli',
],
declaration: true,
clean: true,
Expand Down
24 changes: 1 addition & 23 deletions cli.mjs
Original file line number Diff line number Diff line change
@@ -1,24 +1,2 @@
#!/usr/bin/env node
import minimist from 'minimist'
import changelogithub from './dist/index.mjs'

const args = minimist(process.argv.slice(2), {
boolean: [
'draft',
'prerelease',
'dry',
],
string: [
'token',
'from',
'to',
'name',
],
alias: {
draft: 'd',
},
})

args.token = args.token || process.env.GITHUB_TOKEN

changelogithub(args)
import './dist/cli.mjs'
58 changes: 58 additions & 0 deletions src/cli.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
#!/usr/bin/env node
import minimist from 'minimist'
import { blue, bold, cyan, dim, red, yellow } from 'kolorist'
import { version } from '../package.json'
import { generate, sendRelease } from './index'

const args = minimist(process.argv.slice(2), {
boolean: [
'draft',
'dry',
],
string: [
'token',
'from',
'to',
'name',
],
default: {
prerelease: undefined,
},
alias: {
draft: 'd',
},
})

args.token = args.token || process.env.GITHUB_TOKEN

async function run() {
const { config, md } = await generate(args as any)

console.log()
console.log(dim(`changelo${bold('github')} `) + dim(`v${version}`))
console.log(bold(config.github))
console.log(cyan(config.from) + dim(' -> ') + blue(config.to))
console.log(dim('--------------'))
console.log()
console.log(md.replaceAll(' ', ''))
console.log()
console.log(dim('--------------'))

if (config.dry)
return console.log(yellow('Dry run, skipped.'))

if (!config.to.startsWith('v')) {
console.log(yellow('Release version must starts with `v`, skipped.'))
process.exitCode = 1
return
}

await sendRelease(config, md)
}

run()
.catch((e) => {
console.error(red(String(e)))
console.error(dim(e.stack?.split('\n').slice(1).join('\n')))
process.exit(1)
})
31 changes: 31 additions & 0 deletions src/generate.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import { getGitDiff, parseCommits } from 'changelogen'
import type { ChangelogOptions } from './types'
import { getCurrentGitBranch, getGitHubRepo, getLastGitTag, isPrerelease } from './git'
import { generateMarkdown } from './markdown'

export async function generate(options: ChangelogOptions) {
const config: ChangelogOptions = {
scopeMap: {},
types: {
feat: { title: '🚀 Features' },
fix: { title: '🐞 Bug Fixes' },
perf: { title: '🏎 Performance' },
},
breakingChangeMessage: '🚨 Breaking Changes',
...options as any,
}

config.from = config.from || await getLastGitTag()
config.to = config.to || await getCurrentGitBranch()
config.github = config.github || await getGitHubRepo()
config.prerelease = config.prerelease ?? isPrerelease(config.to)

if (config.to === config.from)
config.from = await getLastGitTag(-2)

const rawCommits = await getGitDiff(config.from, config.to)
const commits = parseCommits(rawCommits, config)
const md = generateMarkdown(commits, config)

return { config, md, commits }
}
13 changes: 12 additions & 1 deletion src/git.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
import { execa } from 'execa'
import semver from 'semver'

export async function getGitHubRepo() {
const res = await execa('git', ['config', '--get', 'remote.origin.url'])
const url = String(res.stdout).trim()
const match = url.match(/github\.com[\/:]([\w\d._-]+)\/([\w\d._-]+)(\.git)?$/i)
const match = url.match(/github\.com[\/:]([\w\d._-]+?)\/([\w\d._-]+?)(\.git)?$/i)
if (!match)
throw new Error(`Can not parse GitHub repo from url ${url}`)
return `${match[1]}/${match[2]}`
Expand All @@ -18,6 +19,16 @@ export async function getLastGitTag(delta = -1) {
return tags[tags.length + delta]
}

export function isPrerelease(version: string) {
version = version.startsWith('v') ? version.slice(1) : version
try {
return semver.parse(version)!.prerelease.length > 0
}
catch (e) {
return false
}
}

async function execCommand(cmd: string, args: string[]) {
const { execa } = await import('execa')
const res = await execa(cmd, args)
Expand Down
43 changes: 43 additions & 0 deletions src/github.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
/* eslint-disable no-console */
import { $fetch } from 'ohmyfetch'
import { cyan, green } from 'kolorist'
import type { ChangelogOptions } from './types'

export async function sendRelease(
options: ChangelogOptions,
content: string,
) {
const headers = {
accept: 'application/vnd.github.v3+json',
authorization: `token ${options.token}`,
}
let url = `https://api.github.com/repos/${options.github}/releases`
let method = 'POST'
try {
const exists = await $fetch(`https://api.github.com/repos/${options.github}/releases/tags/${options.to}`, {
headers,
})
if (exists.url) {
url = exists.url
method = 'PATCH'
}
}
catch (e) {
}

const body = {
body: content,
draft: options.draft || false,
name: options.name || options.to,
prerelease: options.prerelease,
tag_name: options.to,
}

console.log(cyan(method === 'POST' ? 'Creating release notes...' : 'Updating release notes...'))
const res = await $fetch(url, {
method,
body: JSON.stringify(body),
headers,
})
console.log(green(`Released on ${res.html_url}`))
}
99 changes: 5 additions & 94 deletions src/index.ts
Original file line number Diff line number Diff line change
@@ -1,94 +1,5 @@
/* eslint-disable no-console */
import { $fetch } from 'ohmyfetch'
import { getGitDiff, parseCommits } from 'changelogen'
import semver from 'semver'
import { blue, bold, cyan, dim, green } from 'kolorist'
import type { ChangelogOptions } from './types'
import { getCurrentGitBranch, getGitHubRepo, getLastGitTag } from './git'
import { generateMarkdown } from './markdown'

export default async function changelogithub(
options: ChangelogOptions,
) {
const config: ChangelogOptions = {
scopeMap: {},
types: {
feat: { title: '🚀 Features' },
fix: { title: '🐞 Bug Fixes' },
perf: { title: '🏎 Performance' },
},
breakingChangeMessage: '🚨 Breaking Changes',
...options as any,
}

config.from = config.from || await getLastGitTag()
config.to = config.to || await getCurrentGitBranch()
config.github = config.github || await getGitHubRepo()

if (config.to === config.from)
config.from = await getLastGitTag(-2)

const rawCommits = await getGitDiff(config.from, config.to)
const commits = parseCommits(rawCommits, config)

if (!commits.length) {
console.log('No commits')
process.exitCode = 1
return
}

const md = generateMarkdown(commits, config)

console.log(bold(config.github))
console.log(cyan(config.from) + dim(' -> ') + blue(config.to))
console.log(dim('--------------'))
console.log()
console.log(md)
console.log()
console.log(dim('--------------'))

if (config.dry)
return

await sendRelease(config, md)
}

async function sendRelease(
options: ChangelogOptions,
content: string,
) {
const headers = {
accept: 'application/vnd.github.v3+json',
authorization: `token ${options.token}`,
}
let url = `https://api.github.com/repos/${options.github}/releases`
let method = 'POST'
try {
const exists = await $fetch(`https://api.github.com/repos/${options.github}/releases/tags/${options.to}`, {
headers,
})
if (exists.url) {
url = exists.url
method = 'PATCH'
}
}
catch (e) {
}

const version = options.from.startsWith('v') ? options.to.slice(1) : options.to
const body = {
body: content,
draft: options.draft || false,
name: options.name || options.to,
prerelease: options.prerelease || semver.parse(version)!.prerelease.length > 0,
tag_name: options.to,
}

console.log(cyan(method === 'POST' ? 'Creating release notes...' : 'Updating release notes...'))
const res = await $fetch(url, {
method,
body: JSON.stringify(body),
headers,
})
console.log(green(`Release: ${res.html_url}`))
}
export * from './types'
export * from './github'
export * from './git'
export * from './markdown'
export * from './generate'

0 comments on commit b8412b1

Please sign in to comment.