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,