From 91b2478e19733341bce693bee179cd50094e4e0d Mon Sep 17 00:00:00 2001
From: Dmitry Dobrynin
Date: Sun, 6 Apr 2025 00:54:09 +0200
Subject: [PATCH 1/2] =?UTF-8?q?=E2=9C=A8=20Add=20--skip-merge=20option=20t?=
=?UTF-8?q?o=20exclude=20merge=20commits=20from=20changelog?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
packages/gitmoji-changelog-cli/src/index.js | 1 +
packages/gitmoji-changelog-core/src/index.js | 19 +++--
.../gitmoji-changelog-core/src/index.spec.js | 80 +++++++++++++++++++
.../gitmoji-changelog-documentation/README.md | 1 +
4 files changed, 96 insertions(+), 5 deletions(-)
diff --git a/packages/gitmoji-changelog-cli/src/index.js b/packages/gitmoji-changelog-cli/src/index.js
index a51b5d8..7e25e0a 100755
--- a/packages/gitmoji-changelog-cli/src/index.js
+++ b/packages/gitmoji-changelog-cli/src/index.js
@@ -50,6 +50,7 @@ yargs
.option('preset', { default: 'node', desc: 'define preset mode', choices: ['node', 'generic', 'maven', 'cargo', 'helm', 'python'] })
.option('output', { desc: 'output changelog file' })
.option('group-similar-commits', { desc: '[⚗️ - beta] try to group similar commits', default: false })
+ .option('skip-merge', { desc: 'Skip merge commits when generating the changelog', default: false, type: 'boolean' })
.option('author', { default: false, desc: 'add the author in changelog lines' })
.option('interactive', { default: false, desc: 'select commits manually', alias: 'i' })
diff --git a/packages/gitmoji-changelog-core/src/index.js b/packages/gitmoji-changelog-core/src/index.js
index 8143a40..080183a 100644
--- a/packages/gitmoji-changelog-core/src/index.js
+++ b/packages/gitmoji-changelog-core/src/index.js
@@ -45,9 +45,15 @@ function sanitizeVersion(version) {
}
}
-function filterCommits(commits) {
+function filterCommits(commits, skipMerge) {
return commits
- .filter(commit => commit.group !== 'useless')
+ .filter(commit => {
+ if (skipMerge && /^Merge (pull request|branch|tag)/i.test(commit.subject)) {
+ return false
+ }
+
+ return commit.group !== 'useless'
+ })
}
async function generateVersion(options) {
@@ -56,12 +62,13 @@ async function generateVersion(options) {
to,
version,
groupSimilarCommits,
+ skipMerge,
client,
} = options
const rawCommits = await client.getCommits(from, to)
- let commits = filterCommits(rawCommits.map(parseCommit))
+ let commits = filterCommits(rawCommits.map(parseCommit), skipMerge)
if (groupSimilarCommits) {
commits = groupSentencesByDistance(commits.map(commit => commit.message))
@@ -107,6 +114,7 @@ async function generateVersions({
hasNext,
release,
groupSimilarCommits,
+ skipMerge,
client,
}) {
let nextTag = HEAD
@@ -117,7 +125,7 @@ async function generateVersions({
const to = nextTag
nextTag = tag
return generateVersion({
- from, to, version, groupSimilarCommits, client,
+ from, to, version, groupSimilarCommits, skipMerge, client,
})
}))
.then(versions => versions.sort(sortVersions))
@@ -126,7 +134,7 @@ async function generateVersions({
}
async function generateChangelog(from, to, {
- groupSimilarCommits, client = fromGitFileClient,
+ groupSimilarCommits, skipMerge, client = fromGitFileClient,
} = {}) {
const gitTags = await client.getTags()
let tagsToProcess = [...gitTags]
@@ -155,6 +163,7 @@ async function generateChangelog(from, to, {
hasNext,
release: to,
groupSimilarCommits,
+ skipMerge,
client,
})
diff --git a/packages/gitmoji-changelog-core/src/index.spec.js b/packages/gitmoji-changelog-core/src/index.spec.js
index d71b6cb..c6ffe66 100644
--- a/packages/gitmoji-changelog-core/src/index.spec.js
+++ b/packages/gitmoji-changelog-core/src/index.spec.js
@@ -19,6 +19,45 @@ const uselessCommit = {
message: 'Bump version to 1.9.2',
}
+const mergePRCommit = {
+ hash: 'b334c1c381cf9863edc83e8a549b8b712fd16e81',
+ author: 'Dmitry Dobrynin',
+ date: '2024-04-09T23:33:45+02:00',
+ subject: 'Merge pull request #123 from space',
+ body: '#123\n',
+ emoji: undefined,
+ emojiCode: undefined,
+ group: 'misc',
+ message: 'Merge pull request #123 from space',
+ siblings: [],
+}
+
+const mergeTagCommit = {
+ hash: 'b334c1c381cf9863edc83e8a549b8b712fd16e82',
+ author: 'Dmitry Dobrynin',
+ date: '2024-04-08T23:33:45+02:00',
+ subject: 'Merge tag \'tag\' into space',
+ body: 'tag\n',
+ emoji: undefined,
+ emojiCode: undefined,
+ group: 'misc',
+ message: 'Merge tag \'tag\' into space',
+ siblings: [],
+}
+
+const mergeBranchCommit = {
+ hash: 'b334c1c381cf9863edc83e8a549b8b712fd16e83',
+ author: 'Dmitry Dobrynin',
+ date: '2024-04-07T23:33:45+02:00',
+ subject: 'Merge branch \'feature\'',
+ body: 'feature\n',
+ emoji: undefined,
+ emojiCode: undefined,
+ group: 'misc',
+ message: 'Merge branch \'feature\'',
+ siblings: [],
+}
+
const lockCommit = {
hash: '460b79497ae7e791bc8ba8475bda8f0b93630dd9',
author: 'John Doe',
@@ -287,6 +326,47 @@ describe('changelog', () => {
])
})
+ it('should not filter merge request', async () => {
+ gitRawCommits.mockReset()
+ mockGroup([lipstickCommit, mergePRCommit, mergeTagCommit, mergeBranchCommit])
+
+ gitSemverTags.mockImplementation(cb => cb(null, []))
+
+ const { changes } = await generateChangelog(TAIL, HEAD, { skipMerge: false })
+
+ expect(changes).toEqual([
+ expect.objectContaining({
+ groups: [
+ expect.objectContaining({
+ commits: [lipstickCommit],
+ }),
+ expect.objectContaining({
+ commits: [mergePRCommit, mergeTagCommit, mergeBranchCommit],
+ }),
+ ],
+ }),
+ ])
+ })
+
+ it('should filter merge request', async () => {
+ gitRawCommits.mockReset()
+ mockGroup([lipstickCommit, mergePRCommit, mergeTagCommit, mergeBranchCommit])
+
+ gitSemverTags.mockImplementation(cb => cb(null, []))
+
+ const { changes } = await generateChangelog(TAIL, HEAD, { skipMerge: true })
+
+ expect(changes).toEqual([
+ expect.objectContaining({
+ groups: [
+ expect.objectContaining({
+ commits: [lipstickCommit],
+ }),
+ ],
+ }),
+ ])
+ })
+
it('should throw an error if no commits', async () => {
mockNoCommits()
diff --git a/packages/gitmoji-changelog-documentation/README.md b/packages/gitmoji-changelog-documentation/README.md
index 39f035e..4b36e48 100644
--- a/packages/gitmoji-changelog-documentation/README.md
+++ b/packages/gitmoji-changelog-documentation/README.md
@@ -60,6 +60,7 @@ The first command listed above is the idiomatic usage of `gitmoji-changelog` (re
| --preset | define preset mode | node |
| --output | output file path | ./CHANGELOG.md or ./CHANGELOG.json |
| --group-similar-commits | [⚗️,- beta] try to group similar commits | false |
+| --skip-merge | Skip merge commits when generating the changelog | false |
| --author | add the author in changelog lines | false |
| --interactive -i | select commits manually | false |
| --help | display help | |
From 3c6efc743540db3c0dea4eb01e51a8d38a928690 Mon Sep 17 00:00:00 2001
From: Dmitry Dobrynin
Date: Sun, 6 Apr 2025 17:57:12 +0200
Subject: [PATCH 2/2] =?UTF-8?q?=E2=9A=A1=EF=B8=8F=20Improve=20merge=20comm?=
=?UTF-8?q?it=20detection=20using=20parent=20commits?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
packages/gitmoji-changelog-core/src/fromGitFile.js | 6 +++---
packages/gitmoji-changelog-core/src/index.js | 2 +-
packages/gitmoji-changelog-core/src/index.spec.js | 14 ++++++++++++--
packages/gitmoji-changelog-core/src/parser.js | 3 ++-
4 files changed, 18 insertions(+), 7 deletions(-)
diff --git a/packages/gitmoji-changelog-core/src/fromGitFile.js b/packages/gitmoji-changelog-core/src/fromGitFile.js
index fc32e3a..0371578 100644
--- a/packages/gitmoji-changelog-core/src/fromGitFile.js
+++ b/packages/gitmoji-changelog-core/src/fromGitFile.js
@@ -5,16 +5,16 @@ const gitSemverTags = require('git-semver-tags')
const through = require('through2')
const concat = require('concat-stream')
-const COMMIT_FORMAT = '%n%H%n%an%n%cI%n%s%n%b'
+const COMMIT_FORMAT = '%n%H%n%p%n%an%n%cI%n%s%n%b'
function parseCommit(commit) {
const lines = splitLines(commit)
- const [hash, author, date, subject, ...body] = lines.splice(
+ const [hash, parents, author, date, subject, ...body] = lines.splice(
1,
lines.length - 2
)
return {
- hash, author, date, subject, body,
+ hash, parents: parents.split(' '), author, date, subject, body,
}
}
diff --git a/packages/gitmoji-changelog-core/src/index.js b/packages/gitmoji-changelog-core/src/index.js
index 080183a..76383fc 100644
--- a/packages/gitmoji-changelog-core/src/index.js
+++ b/packages/gitmoji-changelog-core/src/index.js
@@ -48,7 +48,7 @@ function sanitizeVersion(version) {
function filterCommits(commits, skipMerge) {
return commits
.filter(commit => {
- if (skipMerge && /^Merge (pull request|branch|tag)/i.test(commit.subject)) {
+ if (skipMerge && commit.parents.length > 1) {
return false
}
diff --git a/packages/gitmoji-changelog-core/src/index.spec.js b/packages/gitmoji-changelog-core/src/index.spec.js
index c6ffe66..7a071da 100644
--- a/packages/gitmoji-changelog-core/src/index.spec.js
+++ b/packages/gitmoji-changelog-core/src/index.spec.js
@@ -10,6 +10,7 @@ const HEAD = ''
const uselessCommit = {
hash: '460b79497ae7e791bc8ba8475bda8f0b93630dd3',
+ parents: ['9665162'],
date: '2018-09-14T21:00:18+02:00',
subject: ':bookmark: Bump version to 1.9.2',
body: 'Yes!',
@@ -21,6 +22,7 @@ const uselessCommit = {
const mergePRCommit = {
hash: 'b334c1c381cf9863edc83e8a549b8b712fd16e81',
+ parents: ['9665162', '73bc24c', '3ce8c20'],
author: 'Dmitry Dobrynin',
date: '2024-04-09T23:33:45+02:00',
subject: 'Merge pull request #123 from space',
@@ -34,6 +36,7 @@ const mergePRCommit = {
const mergeTagCommit = {
hash: 'b334c1c381cf9863edc83e8a549b8b712fd16e82',
+ parents: ['9665162', '73bc24c'],
author: 'Dmitry Dobrynin',
date: '2024-04-08T23:33:45+02:00',
subject: 'Merge tag \'tag\' into space',
@@ -47,6 +50,7 @@ const mergeTagCommit = {
const mergeBranchCommit = {
hash: 'b334c1c381cf9863edc83e8a549b8b712fd16e83',
+ parents: ['9665162', '73bc24c'],
author: 'Dmitry Dobrynin',
date: '2024-04-07T23:33:45+02:00',
subject: 'Merge branch \'feature\'',
@@ -60,6 +64,7 @@ const mergeBranchCommit = {
const lockCommit = {
hash: '460b79497ae7e791bc8ba8475bda8f0b93630dd9',
+ parents: ['9665162'],
author: 'John Doe',
date: '2018-09-14T22:00:18+02:00',
subject: ':lock: Improve security',
@@ -73,6 +78,7 @@ const lockCommit = {
const sparklesCommit = {
hash: 'c40ee8669ba7ea5151adc2942fa8a7fc98d9e23a',
+ parents: ['9665162'],
author: 'John Doe',
date: '2018-08-28T10:06:00+02:00',
subject: ':sparkles: Add a brand new feature',
@@ -86,6 +92,7 @@ const sparklesCommit = {
const recycleCommit = {
hash: 'c40ee8669ba7ea5151adc2942fa8a7fc98d9e23c',
+ parents: ['9665162'],
author: 'John Doe',
date: '2018-08-01T10:07:00+02:00',
subject: ':recycle: Make some reworking on code',
@@ -99,6 +106,7 @@ const recycleCommit = {
const secondRecycleCommit = {
hash: 'c40ee8669ba7ea5151adc2942fa8a7fc98d9e23d',
+ parents: ['9665162'],
author: 'John Doe',
date: '2018-08-30T10:07:00+02:00',
subject: ':recycle: Upgrade another brand new feature',
@@ -112,6 +120,7 @@ const secondRecycleCommit = {
const lipstickCommit = {
hash: 'c40ee8669ba7ea5151adc2942fa8a7fc98d9e23e',
+ parents: ['9665162'],
author: 'John Doe',
date: '2018-08-10T10:07:00+02:00',
subject: ':lipstick: Change graphics for a feature',
@@ -125,6 +134,7 @@ const lipstickCommit = {
const secondLipstickCommit = {
hash: 'c40ee8669ba7ea5151adc2942fa8a7fc98d9e23f',
+ parents: ['9665162'],
author: 'John Doe',
date: '2018-08-18T10:07:00+02:00',
subject: ':lipstick: Change more graphics for a feature',
@@ -454,9 +464,9 @@ function mockGroup(commits) {
const readable = new stream.Readable()
commits.forEach(commit => {
const {
- hash, author, date, subject, body,
+ hash, parents, author, date, subject, body,
} = commit
- readable.push(`\n${hash}\n${author}\n${date}\n${subject}\n${body}\n`)
+ readable.push(`\n${hash}\n${parents ? parents.join(' ') : ''}\n${author}\n${date}\n${subject}\n${body}\n`)
})
readable.push(null)
readable.emit('close')
diff --git a/packages/gitmoji-changelog-core/src/parser.js b/packages/gitmoji-changelog-core/src/parser.js
index 48b3971..7739a1c 100644
--- a/packages/gitmoji-changelog-core/src/parser.js
+++ b/packages/gitmoji-changelog-core/src/parser.js
@@ -57,13 +57,14 @@ function getCommitGroup(emojiCode) {
}
function parseCommit({
- hash, author, date, subject = '', body = '',
+ hash, parents, author, date, subject = '', body = '',
}) {
const { emoji, emojiCode, message } = parseSubject(subject)
const group = getCommitGroup(emojiCode)
return {
hash,
+ parents,
author,
date,
subject,