From 4094bb9abe01a731b0c20e0dcd006c8e08a66dc6 Mon Sep 17 00:00:00 2001 From: Benjamin Petetot Date: Tue, 21 Jan 2020 14:42:58 +0100 Subject: [PATCH] :recycle: Make core independent from the git client. (#171) --- .../gitmoji-changelog-core/src/fromGitFile.js | 46 +++++++++++++ packages/gitmoji-changelog-core/src/index.js | 40 ++++-------- packages/gitmoji-changelog-core/src/parser.js | 9 ++- .../gitmoji-changelog-core/src/parser.spec.js | 65 +++++-------------- 4 files changed, 81 insertions(+), 79 deletions(-) create mode 100644 packages/gitmoji-changelog-core/src/fromGitFile.js diff --git a/packages/gitmoji-changelog-core/src/fromGitFile.js b/packages/gitmoji-changelog-core/src/fromGitFile.js new file mode 100644 index 0000000..fc32e3a --- /dev/null +++ b/packages/gitmoji-changelog-core/src/fromGitFile.js @@ -0,0 +1,46 @@ +const gitRawCommits = require('git-raw-commits') +const splitLines = require('split-lines') +const { promisify } = require('util') +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' + +function parseCommit(commit) { + const lines = splitLines(commit) + const [hash, author, date, subject, ...body] = lines.splice( + 1, + lines.length - 2 + ) + return { + hash, author, date, subject, body, + } +} + +function getCommits(from, to) { + return new Promise(resolve => { + gitRawCommits({ + format: COMMIT_FORMAT, + from, + to, + }) + .pipe( + through.obj((data, enc, next) => { + next(null, parseCommit(data.toString())) + }) + ) + .pipe( + concat(data => { + resolve(data) + }) + ) + }) +} + +const getTags = promisify(gitSemverTags) + +module.exports = { + getTags, + getCommits, +} diff --git a/packages/gitmoji-changelog-core/src/index.js b/packages/gitmoji-changelog-core/src/index.js index 01ed8a0..4b68da4 100644 --- a/packages/gitmoji-changelog-core/src/index.js +++ b/packages/gitmoji-changelog-core/src/index.js @@ -1,36 +1,16 @@ const semver = require('semver') -const gitRawCommits = require('git-raw-commits') -const gitSemverTags = require('git-semver-tags') const semverCompare = require('semver-compare') -const through = require('through2') -const concat = require('concat-stream') + const { isEmpty } = require('lodash') -const { promisify } = require('util') const { parseCommit, getMergedGroupMapping } = require('./parser') const logger = require('./logger') const { groupSentencesByDistance } = require('./utils') +const fromGitFileClient = require('./fromGitFile') -const gitSemverTagsAsync = promisify(gitSemverTags) - -const COMMIT_FORMAT = '%n%H%n%an%n%cI%n%s%n%b' const HEAD = '' const TAIL = '' -function getCommits(from, to) { - return new Promise((resolve) => { - gitRawCommits({ - format: COMMIT_FORMAT, - from, - to, - }).pipe(through.obj((data, enc, next) => { - next(null, parseCommit(data.toString())) - })).pipe(concat(data => { - resolve(data) - })) - }) -} - function makeGroups(commits) { if (isEmpty(commits)) return [] @@ -68,8 +48,12 @@ async function generateVersion(options) { to, version, groupSimilarCommits, + client, } = options - let commits = filterCommits(await getCommits(from, to)) + + const rawCommits = await client.getCommits(from, to) + + let commits = filterCommits(rawCommits.map(parseCommit)) if (groupSimilarCommits) { commits = groupSentencesByDistance(commits.map(commit => commit.message)) @@ -108,6 +92,7 @@ async function generateVersions({ hasNext, release, groupSimilarCommits, + client, }) { let nextTag = HEAD const targetVersion = hasNext ? 'next' : sanitizeVersion(release) @@ -117,7 +102,7 @@ async function generateVersions({ const to = nextTag nextTag = tag return generateVersion({ - from, to, version, groupSimilarCommits, + from, to, version, groupSimilarCommits, client, }) })) .then(versions => versions.sort(sortVersions)) @@ -125,8 +110,10 @@ async function generateVersions({ return changes } -async function generateChangelog(from, to, { groupSimilarCommits } = {}) { - const gitTags = await gitSemverTagsAsync() +async function generateChangelog(from, to, { + groupSimilarCommits, client = fromGitFileClient, +} = {}) { + const gitTags = await client.getTags() let tagsToProcess = [...gitTags] const hasNext = hasNextVersion(gitTags, to) @@ -146,6 +133,7 @@ async function generateChangelog(from, to, { groupSimilarCommits } = {}) { hasNext, release: to, groupSimilarCommits, + client, }) if (from !== TAIL && changes.length === 1 && isEmpty(changes[0].groups)) { diff --git a/packages/gitmoji-changelog-core/src/parser.js b/packages/gitmoji-changelog-core/src/parser.js index 1fe3dee..48b3971 100644 --- a/packages/gitmoji-changelog-core/src/parser.js +++ b/packages/gitmoji-changelog-core/src/parser.js @@ -1,4 +1,3 @@ -const splitLines = require('split-lines') const nodeEmoji = require('node-emoji') const groupMapping = require('./groupMapping') const rc = require('rc') @@ -57,9 +56,9 @@ function getCommitGroup(emojiCode) { return group.group } -function parseCommit(commit) { - const lines = splitLines(commit) - const [hash, author, date, subject, ...body] = lines.splice(1, lines.length - 2) +function parseCommit({ + hash, author, date, subject = '', body = '', +}) { const { emoji, emojiCode, message } = parseSubject(subject) const group = getCommitGroup(emojiCode) @@ -73,7 +72,7 @@ function parseCommit(commit) { message, group, siblings: [], - body: body.join('\n'), + body: Array.isArray(body) ? body.join('\n') : body, } } diff --git a/packages/gitmoji-changelog-core/src/parser.spec.js b/packages/gitmoji-changelog-core/src/parser.spec.js index 4c08d77..ec7d4af 100644 --- a/packages/gitmoji-changelog-core/src/parser.spec.js +++ b/packages/gitmoji-changelog-core/src/parser.spec.js @@ -22,42 +22,26 @@ describe('group mapping', () => { describe('commits parser', () => { it('should parse a single commit', () => { - const { - hash, - author, - date, - subject, - body, - } = sparklesCommit - const commit = `\n${hash}\n${author}\n${date}\n${subject}\n${body}\n` - - expect(parseCommit(commit)).toEqual(expect.objectContaining(sparklesCommit)) + expect(parseCommit(sparklesCommit)).toEqual(expect.objectContaining(sparklesCommit)) }) it('should parse a unicode emoji', () => { - const { - hash, - author, - date, - body, - } = sparklesCommit - const commit = `\n${hash}\n${author}\n${date}\n✨ Upgrade brand new feature\n${body}\n` - const parsed = parseCommit(commit) + const parsed = parseCommit({ + ...sparklesCommit, + subject: '✨ Upgrade brand new feature', + }) expect(parsed.emoji).toEqual('✨') expect(parsed.emojiCode).toEqual('sparkles') expect(parsed.message).toEqual('Upgrade brand new feature') }) it('should parse a single commit without a body', () => { - const { - hash, - author, - date, - subject, - } = sparklesCommit - const commit = `\n${hash}\n${author}\n${date}\n${subject}\n\n` + const parsed = parseCommit({ + ...sparklesCommit, + body: '', + }) - expect(parseCommit(commit)).toEqual(expect.objectContaining({ + expect(parseCommit(parsed)).toEqual(expect.objectContaining({ ...sparklesCommit, body: '', })) @@ -69,9 +53,11 @@ describe('commits parser', () => { author, date, } = sparklesCommit - const commit = `\n${hash}\n${author}\n${date}\n\n` - - expect(parseCommit(commit)).toEqual(expect.objectContaining({ + expect(parseCommit({ + hash, + author, + date, + })).toEqual(expect.objectContaining({ ...sparklesCommit, subject: '', body: '', @@ -79,16 +65,7 @@ describe('commits parser', () => { }) it('should add the group to a commit', () => { - const { - hash, - author, - date, - subject, - body, - } = sparklesCommit - const commit = `\n${hash}\n${author}\n${date}\n${subject}\n${body}\n` - - expect(parseCommit(commit)).toEqual(expect.objectContaining({ group: 'added' })) + expect(parseCommit(sparklesCommit)).toEqual(expect.objectContaining({ group: 'added' })) }) it('should handle custom commit mapping', () => { @@ -99,16 +76,8 @@ describe('commits parser', () => { ], } rc.mockImplementation(() => customConfiguration) - const { - hash, - author, - date, - subject, - body, - } = sparklesCommit - const commit = `\n${hash}\n${author}\n${date}\n${subject}\n${body}\n` - expect(parseCommit(commit)).toEqual(expect.objectContaining({ group: 'custom' })) + expect(parseCommit(sparklesCommit)).toEqual(expect.objectContaining({ group: 'custom' })) }) })