Skip to content

Commit d3c49d0

Browse files
kefranabgfrinyvonnick
authored andcommitted
🐛 Use last version from changelog file instead of previous git tag (#82)
1 parent f814f35 commit d3c49d0

File tree

7 files changed

+183
-23
lines changed

7 files changed

+183
-23
lines changed

misc/package.sample.json

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
{
2+
"name": "gitmoji-changelog",
3+
"version": "0.0.1",
4+
"description": "Some description",
5+
"main": "index.js",
6+
"scripts": {
7+
"test": "echo \"Error: no test specified\" && exit 1"
8+
},
9+
"author": "",
10+
"license": "MIT"
11+
}

packages/gitmoji-changelog-cli/package.json

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,10 +35,14 @@
3535
"@gitmoji-changelog/markdown": "^1.1.0",
3636
"libnpm": "^1.0.0",
3737
"semver-compare": "^1.0.0",
38+
"simple-git": "^1.113.0",
3839
"yargs": "^12.0.1"
3940
},
4041
"publishConfig": {
4142
"access": "public",
4243
"registry": "https://registry.npmjs.org/"
44+
},
45+
"devDependencies": {
46+
"fs-extra": "^8.0.1"
4347
}
4448
}
Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
const os = require('os')
2+
const fs = require('fs')
3+
const { removeSync } = require('fs-extra')
4+
const path = require('path')
5+
const simpleGit = require('simple-git/promise')
6+
const util = require('util')
7+
const execFile = util.promisify(require('child_process').execFile)
8+
9+
expect.extend({
10+
includes(str, items) {
11+
const pass = items.every(item => str.includes(item))
12+
return {
13+
pass,
14+
message: () => pass ? '' : '',
15+
}
16+
},
17+
})
18+
19+
describe('generate changelog', () => {
20+
let testDir
21+
let repo
22+
23+
beforeAll(async () => {
24+
testDir = path.join(os.tmpdir(), 'gitmoji-changelog')
25+
if (fs.existsSync(testDir)) removeSync(testDir)
26+
fs.mkdirSync(testDir)
27+
repo = simpleGit(testDir)
28+
await repo.init()
29+
fs.copyFileSync(
30+
path.join(__dirname, '..', '..', '..', 'misc', 'package.sample.json'),
31+
path.join(testDir, 'package.json'),
32+
)
33+
})
34+
35+
afterAll(() => {
36+
removeSync(testDir)
37+
})
38+
39+
it('should generate changelog even if user doesn\'t call cli at each tag', async () => {
40+
await newVersion('1.0.0')
41+
await gitmojiChangelog()
42+
43+
expect(getChangelog()).toMatch(/1.0.0/)
44+
45+
await newVersion('1.0.1')
46+
await newVersion('1.0.2')
47+
await gitmojiChangelog()
48+
49+
expect(getChangelog()).includes(['1.0.0', '1.0.1', '1.0.2'])
50+
})
51+
52+
async function newVersion(version) {
53+
fs.writeFileSync(path.join(testDir, version))
54+
bumpVersion(version)
55+
await repo.add('.')
56+
await repo.commit(`Commit ${version}`)
57+
await repo.addTag(`v${version}`)
58+
}
59+
60+
function gitmojiChangelog() {
61+
return execFile('node', [path.join(__dirname, 'index.js')], { cwd: testDir })
62+
}
63+
64+
function getChangelog() {
65+
return fs.readFileSync(path.join(testDir, 'CHANGELOG.md')).toString('utf8')
66+
}
67+
68+
function bumpVersion(to) {
69+
const pkg = path.join(testDir, 'package.json')
70+
// eslint-disable-next-line global-require
71+
const { version } = require(pkg)
72+
const content = fs.readFileSync(pkg).toString('utf8')
73+
const updatedContent = content.replace(version, to)
74+
fs.writeFileSync(pkg, updatedContent)
75+
}
76+
})
Lines changed: 30 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,14 @@
11
const fs = require('fs')
2-
2+
const { set } = require('immutadot')
33
const libnpm = require('libnpm')
44
const semverCompare = require('semver-compare')
55
const { generateChangelog, logger } = require('@gitmoji-changelog/core')
6-
const { buildMarkdownFile } = require('@gitmoji-changelog/markdown')
6+
const { buildMarkdownFile, getLatestVersion } = require('@gitmoji-changelog/markdown')
7+
78

89
const pkg = require('../package.json')
910

10-
async function getLatestVersion() {
11+
async function getGitmojiChangelogLatestVersion() {
1112
const watchdog = new Promise(resolve => setTimeout(resolve, 500, { version: pkg.version }))
1213
const request = libnpm.manifest('gitmoji-changelog@latest')
1314

@@ -21,7 +22,7 @@ async function main(options = {}) {
2122
logger.info(`${options.mode} ${options.output}`)
2223

2324
try {
24-
const latestVersion = await getLatestVersion()
25+
const latestVersion = await getGitmojiChangelogLatestVersion()
2526
if (semverCompare(latestVersion, pkg.version) > 0) {
2627
logger.warn(`You got an outdated version of gitmoji-changelog, please update! (yours: ${pkg.version}, latest: ${latestVersion})`)
2728
logger.warn('Just do the following npm command to update it:')
@@ -36,22 +37,25 @@ async function main(options = {}) {
3637
}
3738

3839
try {
39-
const changelog = await generateChangelog(options)
40+
switch (options.format) {
41+
case 'json': {
42+
const changelog = await generateChangelog(options)
4043

41-
if (changelog.meta.package) {
42-
const { name, version } = changelog.meta.package
43-
logger.info(`${name} v${version}`)
44-
}
45-
if (changelog.meta.repository) {
46-
logger.info(changelog.meta.repository.url)
47-
}
44+
logMetaData(changelog)
4845

49-
switch (options.format) {
50-
case 'json':
5146
fs.writeFileSync(options.output, JSON.stringify(changelog))
5247
break
53-
default:
54-
await buildMarkdownFile(changelog, options)
48+
}
49+
default: {
50+
const lastVersion = getLatestVersion(options.output)
51+
const newOptions = set(options, 'meta.lastVersion', lastVersion)
52+
53+
const changelog = await generateChangelog(newOptions)
54+
55+
logMetaData(changelog)
56+
57+
await buildMarkdownFile(changelog, newOptions)
58+
}
5559
}
5660
logger.success(`changelog updated into ${options.output}`)
5761
} catch (e) {
@@ -62,4 +66,14 @@ async function main(options = {}) {
6266
process.exit(0)
6367
}
6468

69+
function logMetaData(changelog) {
70+
if (changelog.meta.package) {
71+
const { name, version } = changelog.meta.package
72+
logger.info(`${name} v${version}`)
73+
}
74+
if (changelog.meta.repository) {
75+
logger.info(changelog.meta.repository.url)
76+
}
77+
}
78+
6579
module.exports = { main }

packages/gitmoji-changelog-core/src/index.js

Lines changed: 21 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ const gitSemverTags = require('git-semver-tags')
44
const semverCompare = require('semver-compare')
55
const through = require('through2')
66
const concat = require('concat-stream')
7-
const { head, isEmpty } = require('lodash')
7+
const { head, isEmpty, get } = require('lodash')
88
const { promisify } = require('util')
99

1010
const { parseCommit } = require('./parser')
@@ -82,11 +82,12 @@ async function generateVersion(options) {
8282
}
8383
}
8484

85-
async function generateVersions({ tags, groupSimilarCommits }) {
85+
async function generateVersions({ tags, groupSimilarCommits, meta }) {
8686
let nextTag = ''
8787

88+
const initialFrom = meta && meta.lastVersion ? meta.lastVersion : ''
8889
return Promise.all(
89-
[...tags, '']
90+
[...tags, initialFrom]
9091
.map(tag => {
9192
const params = {
9293
groupSimilarCommits,
@@ -107,7 +108,12 @@ async function generateVersions({ tags, groupSimilarCommits }) {
107108
}
108109

109110
async function generateChangelog(options = {}) {
110-
const { mode, release, groupSimilarCommits } = options
111+
const {
112+
mode,
113+
release,
114+
groupSimilarCommits,
115+
meta,
116+
} = options
111117

112118
const packageInfo = await getPackageInfo()
113119

@@ -123,11 +129,11 @@ async function generateChangelog(options = {}) {
123129
let changes = []
124130

125131
const tags = await gitSemverTagsAsync()
126-
const lastTag = head(tags)
132+
const lastTag = get(options, 'meta.lastVersion', head(tags))
127133

128134
if (mode === 'init') {
129135
changes = await generateVersions({ tags, groupSimilarCommits })
130-
} else {
136+
} else if (lastTag === head(tags)) {
131137
const lastChanges = await generateVersion({
132138
groupSimilarCommits,
133139
from: lastTag,
@@ -139,6 +145,15 @@ async function generateChangelog(options = {}) {
139145
}
140146

141147
changes.push(lastChanges)
148+
} else {
149+
const lastTagIndex = tags.findIndex(tag => tag === lastTag)
150+
const missingTags = tags.splice(0, lastTagIndex)
151+
152+
const lastChanges = await generateVersions({ tags: missingTags, groupSimilarCommits, meta })
153+
changes = [
154+
...changes,
155+
...lastChanges,
156+
]
142157
}
143158

144159
const repository = await getRepoInfo(packageInfo)

packages/gitmoji-changelog-markdown/src/index.js

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,22 @@ function matchVersionBreakpoint(tested, version = '.*') {
103103
return regex.test(tested)
104104
}
105105

106+
function getLatestVersion(markdownFile) {
107+
let markdownContent
108+
109+
try {
110+
markdownContent = fs.readFileSync(markdownFile, 'utf-8')
111+
} catch (err) {
112+
return null
113+
}
114+
115+
const result = markdownContent.match(/<a name="([\w.]+?)"><\/a>/)
116+
117+
if (!result) return null
118+
119+
return `v${result[1]}`
120+
}
121+
106122
function getShortHash(hash, repository) {
107123
if (!hash) return null
108124

@@ -131,4 +147,5 @@ module.exports = {
131147
matchVersionBreakpoint,
132148
getShortHash,
133149
autolink,
150+
getLatestVersion,
134151
}

yarn.lock

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1182,6 +1182,13 @@ debug@^2.1.2, debug@^2.2.0, debug@^2.3.3, debug@^2.6.8, debug@^2.6.9:
11821182
dependencies:
11831183
ms "2.0.0"
11841184

1185+
debug@^4.0.1:
1186+
version "4.1.1"
1187+
resolved "https://registry.yarnpkg.com/debug/-/debug-4.1.1.tgz#3b72260255109c6b589cee050f1d516139664791"
1188+
integrity sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==
1189+
dependencies:
1190+
ms "^2.1.1"
1191+
11851192
decamelize-keys@^1.0.0:
11861193
version "1.1.0"
11871194
resolved "https://registry.yarnpkg.com/decamelize-keys/-/decamelize-keys-1.1.0.tgz#d171a87933252807eb3cb61dc1c1445d078df2d9"
@@ -1905,6 +1912,15 @@ fs-extra@^4.0.1:
19051912
jsonfile "^4.0.0"
19061913
universalify "^0.1.0"
19071914

1915+
fs-extra@^8.0.1:
1916+
version "8.0.1"
1917+
resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-8.0.1.tgz#90294081f978b1f182f347a440a209154344285b"
1918+
integrity sha512-W+XLrggcDzlle47X/XnS7FXrXu9sDo+Ze9zpndeBxdgv88FHLm1HtmkhEwavruS6koanBjp098rUpHs65EmG7A==
1919+
dependencies:
1920+
graceful-fs "^4.1.2"
1921+
jsonfile "^4.0.0"
1922+
universalify "^0.1.0"
1923+
19081924
fs-minipass@^1.2.5:
19091925
version "1.2.5"
19101926
resolved "https://registry.yarnpkg.com/fs-minipass/-/fs-minipass-1.2.5.tgz#06c277218454ec288df77ada54a03b8702aacb9d"
@@ -3882,7 +3898,7 @@ ms@2.0.0:
38823898
resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8"
38833899
integrity sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=
38843900

3885-
ms@^2.0.0:
3901+
ms@^2.0.0, ms@^2.1.1:
38863902
version "2.1.1"
38873903
resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.1.tgz#30a5864eb3ebb0a66f2ebe6d727af06a09d86e0a"
38883904
integrity sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==
@@ -5122,6 +5138,13 @@ signale@^1.3.0:
51225138
figures "^2.0.0"
51235139
pkg-conf "^2.1.0"
51245140

5141+
simple-git@^1.113.0:
5142+
version "1.113.0"
5143+
resolved "https://registry.yarnpkg.com/simple-git/-/simple-git-1.113.0.tgz#668989728a1e9cf4ec6c72b69ea2eecc93489bea"
5144+
integrity sha512-i9WVsrK2u0G/cASI9nh7voxOk9mhanWY9eGtWBDSYql6m49Yk5/Fan6uZsDr/xmzv8n+eQ8ahKCoEr8cvU3h+g==
5145+
dependencies:
5146+
debug "^4.0.1"
5147+
51255148
sisteransi@^0.1.1:
51265149
version "0.1.1"
51275150
resolved "https://registry.yarnpkg.com/sisteransi/-/sisteransi-0.1.1.tgz#5431447d5f7d1675aac667ccd0b865a4994cb3ce"

0 commit comments

Comments
 (0)