Skip to content

Commit 4e02179

Browse files
committed
feat: add execute release feature
1 parent 2ea0435 commit 4e02179

File tree

6 files changed

+102
-19
lines changed

6 files changed

+102
-19
lines changed

.babelrc

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
11
{
2-
"presets": ["@babel/preset-env"]
2+
"presets": ["@babel/preset-env"],
3+
"plugins": ["@babel/plugin-transform-runtime"]
34
}

bin/perfekt.js

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,16 @@
11
#!/usr/bin/env node
22

33
const { program } = require('commander')
4-
const { changelog } = require('../dist').default
4+
const { changelog, release } = require('../dist')
55

66
program
77
.command('changelog')
88
.description('generate package changelog')
99
.action(() => changelog())
1010

11+
program
12+
.command('release <version>')
13+
.description('execute a new release')
14+
.action(version => release(version))
15+
1116
program.parse(process.argv)

package-lock.json

Lines changed: 25 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,10 +30,12 @@
3030
],
3131
"license": "MIT",
3232
"dependencies": {
33-
"commander": "^5.0.0"
33+
"commander": "^5.0.0",
34+
"semver": "^7.3.2"
3435
},
3536
"devDependencies": {
3637
"@babel/core": "^7.9.0",
38+
"@babel/plugin-transform-runtime": "^7.9.0",
3739
"@babel/preset-env": "^7.9.5",
3840
"@commitlint/cli": "^8.3.5",
3941
"@commitlint/config-conventional": "^8.3.4",

src/index.js

Lines changed: 34 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,39 @@
1-
import { exec } from 'child_process'
1+
import semver from 'semver'
2+
import { commitRelease, getCommitDetails, getCommits } from './utils'
23

3-
const changelog = () =>
4-
exec('git log --format="%H %s"', (_, res) => {
5-
let changelog = '## Latest\n\n'
6-
const commits = res.split('\n').filter(commit => commit)
7-
commits.forEach(commit => {
8-
const {
9-
groups: { hash, title }
10-
} = commit.match(/(?<hash>.{40}) (?<title>.*)/)
11-
const {
12-
groups: { scope }
13-
} = title.match(/(\w*)(?:\((?<scope>.*)\))?:/)
4+
export const changelog = async version => {
5+
const title = version || 'Latest'
6+
const commits = await getCommits()
7+
const latestCommit = getCommitDetails(commits[0])
8+
const isReleaseLatest = latestCommit.scope === 'release'
9+
let changelog = isReleaseLatest ? '' : `## ${title}\n\n`
1410

15-
if (scope !== 'changelog') changelog += `- ${title} ${hash.slice(0, 8)}\n`
16-
})
11+
commits.forEach((commit, index) => {
12+
const { title, scope, hash, message } = getCommitDetails(commit)
13+
const nextCommit = getCommitDetails(commits[index + 1])
14+
const isReleaseNext = nextCommit && nextCommit.scope === 'release'
1715

18-
return process.stdout.write(changelog)
16+
if (scope === 'release') return (changelog += `## ${message}\n\n`)
17+
if (scope !== 'changelog') {
18+
return (changelog += `- ${title} ${hash.slice(0, 8)}\n${
19+
isReleaseNext ? '\n' : ''
20+
}`)
21+
}
1922
})
2023

21-
export default { changelog }
24+
return process.stdout.write(changelog)
25+
}
26+
27+
export const release = version => {
28+
const newVersion = semver.valid(semver.coerce(version))
29+
if (!newVersion) {
30+
return console.error(`Version '${version}' doesnt look right`)
31+
}
32+
33+
try {
34+
changelog(newVersion)
35+
commitRelease(newVersion)
36+
} catch (error) {
37+
console.error(error)
38+
}
39+
}

src/utils/index.js

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
import { exec } from 'child_process'
2+
3+
export const commitRelease = version =>
4+
new Promise((resolve, reject) => {
5+
exec(`git commit -m 'chore(release): ${version}'`, (err, res) => {
6+
if (err) return reject(err)
7+
resolve()
8+
})
9+
})
10+
11+
export const getCommits = () =>
12+
new Promise((resolve, reject) =>
13+
exec('git log --format="%H %s"', (err, res) => {
14+
if (err) return reject(err)
15+
16+
const commits = res.split('\n').filter(commit => commit)
17+
resolve(commits)
18+
})
19+
)
20+
21+
export const getCommitDetails = commit => {
22+
if (!commit) return null
23+
24+
const {
25+
groups: { hash, title }
26+
} = commit.match(/(?<hash>.{40}) (?<title>.*)/)
27+
const {
28+
groups: { scope, message }
29+
} = title.match(/(\w*)(?:\((?<scope>.*)\))?: (?<message>.*)/)
30+
31+
return { hash, title, scope, message }
32+
}

0 commit comments

Comments
 (0)