Skip to content

Commit

Permalink
✨ Add interactive option to manually select commits (#81)
Browse files Browse the repository at this point in the history
  • Loading branch information
kefranabg authored and frinyvonnick committed Jun 6, 2019
1 parent 1c4c422 commit d13ca2e
Show file tree
Hide file tree
Showing 6 changed files with 363 additions and 4 deletions.
3 changes: 3 additions & 0 deletions packages/gitmoji-changelog-cli/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,10 @@
"dependencies": {
"@gitmoji-changelog/core": "^1.1.0",
"@gitmoji-changelog/markdown": "^1.1.0",
"immutadot": "^1.0.0",
"inquirer": "^6.3.1",
"libnpm": "^1.0.0",
"lodash": "^4.17.11",
"semver-compare": "^1.0.0",
"simple-git": "^1.113.0",
"yargs": "^12.0.1"
Expand Down
16 changes: 13 additions & 3 deletions packages/gitmoji-changelog-cli/src/cli.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ const libnpm = require('libnpm')
const semverCompare = require('semver-compare')
const { generateChangelog, logger } = require('@gitmoji-changelog/core')
const { buildMarkdownFile, getLatestVersion } = require('@gitmoji-changelog/markdown')

const { executeInteractiveMode } = require('./interactiveMode')

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

Expand Down Expand Up @@ -39,7 +39,7 @@ async function main(options = {}) {
try {
switch (options.format) {
case 'json': {
const changelog = await generateChangelog(options)
const changelog = await getChangelog(options)

logMetaData(changelog)

Expand All @@ -50,7 +50,7 @@ async function main(options = {}) {
const lastVersion = getLatestVersion(options.output)
const newOptions = set(options, 'meta.lastVersion', lastVersion)

const changelog = await generateChangelog(newOptions)
const changelog = await getChangelog(newOptions)

logMetaData(changelog)

Expand All @@ -66,6 +66,16 @@ async function main(options = {}) {
process.exit(0)
}

async function getChangelog(options) {
let changelog = await generateChangelog(options)

if (options.interactive) {
changelog = await executeInteractiveMode(changelog)
}

return changelog
}

function logMetaData(changelog) {
if (changelog.meta.package) {
const { name, version } = changelog.meta.package
Expand Down
1 change: 1 addition & 0 deletions packages/gitmoji-changelog-cli/src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ yargs
.option('output', { desc: 'output changelog file' })
.option('group-similar-commits', { desc: '[⚗️ - beta] try to group similar commits', default: false })
.option('author', { default: false, desc: 'add the author in changelog lines' })
.option('interactive', { default: false, desc: 'select commits manually', alias: 'i' })

.help('help')
.epilog(`For more information visit: ${homepage}`)
Expand Down
69 changes: 69 additions & 0 deletions packages/gitmoji-changelog-cli/src/interactiveMode.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
const { get, isEmpty, cloneDeep } = require('lodash')
const inquirer = require('inquirer')
const { set } = require('immutadot')

const interactiveMode = {
buildFormattedChoices,
getFilteredChangelog,
executeInteractiveMode,
}

function buildFormattedChoices(changelog) {
const formattedChoices = []

changelog.changes
.forEach(change => {
change.groups
.forEach(group => {
formattedChoices.push(new inquirer.Separator(`${group.label} (version ${change.version})`))

group.commits.forEach(commit => {
formattedChoices.push({
name: `${get(commit, 'emoji', '')} ${commit.message}`,
value: commit.hash,
checked: true,
})
})
})
})

return formattedChoices
}

function getFilteredChangelog(changelog, selectedCommitsHashes) {
const changes = changelog.changes.map(change => {
const groups = change.groups.map(group => {
const filteredCommits = group.commits.filter(commit => {
return selectedCommitsHashes.find(hash => commit.hash === hash)
})

return set(group, 'commits', filteredCommits)
}).filter(group => !isEmpty(group.commits))

return set(change, 'groups', groups)
}).filter(change => !isEmpty(change.groups))

return {
...changelog,
changes,
}
}

async function executeInteractiveMode(initialChangelog) {
const initialChangelogCopy = cloneDeep(initialChangelog)
const formattedChoices = interactiveMode.buildFormattedChoices(initialChangelogCopy)
const prompt = inquirer.createPromptModule()
const question = {
type: 'checkbox',
name: 'selectedCommitsHashes',
message: 'Select commits',
choices: formattedChoices,
pageSize: 10,
}

const { selectedCommitsHashes } = await prompt(question)

return interactiveMode.getFilteredChangelog(initialChangelogCopy, selectedCommitsHashes)
}

module.exports = interactiveMode
205 changes: 205 additions & 0 deletions packages/gitmoji-changelog-cli/src/interactiveMode.spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,205 @@
const inquirer = require('inquirer')
const interactiveMode = require('./interactiveMode')

describe('interactiveMode', () => {
const commitAddProcess = {
hash: '00c90b7844c3d030e967721eafea1b436ee51a6b',
author: 'Franck',
date: '2019-05-19T10:57:22+02:00',
subject: ':sparkles: Add interactive process',
emojiCode: 'sparkles',
emoji: '✨',
message: 'Add interactive process',
group: 'added',
siblings: [],
body: '',
}

const commitAddOption = {
hash: '3092ffd56e35fff7e35e8a9fcb7fff53005eac8a',
author: 'Franck',
date: '2019-05-18T18:39:44+02:00',
subject: ':sparkles: Add interactive option',
emojiCode: 'sparkles',
emoji: '✨',
message: 'Add interactive option',
group: 'added',
siblings: [],
body: '',
}

const commitUpgradeDeps = {
hash: 'b77199f96c8570b827dfcb11907d6f4edac98823',
author: 's n',
date: '2019-04-23T15:55:19+02:00',
subject: ':arrow_up: Update handlebar to 4.0.14 (#78)',
emojiCode: 'arrow_up',
emoji: '⬆️',
message: 'Update handlebar to 4.0.14 (#78)',
group: 'changed',
siblings: [],
body: '',
}

const commitAddAuthor = {
hash: '979da30f5e52385b99bd4a58e1a946793bd1196d',
author: 'Benjamin Petetot',
date: '2018-10-30T09:33:52+01:00',
subject: ':sparkles: Add the author in changelog lines (#56)',
emojiCode: 'sparkles',
emoji: '✨',
message: 'Add the author in changelog lines (#56)',
group: 'added',
siblings: [],
body: '',
}

const groupAddedVersionNext = {
group: 'added',
label: 'Added',
commits: [
commitAddProcess,
commitAddOption,
],
}

const groupChangedVersionNext = {
group: 'changed',
label: 'Changed',
commits: [
commitUpgradeDeps,
],
}

const groupAddedVersionOne = {
group: 'added',
label: 'Added',
commits: [
commitAddAuthor,
],
}

const versionNext = {
version: 'next',
groups: [
groupAddedVersionNext,
groupChangedVersionNext,
],
}

const versionOne = {
version: '1.1.0',
date: '2018-11-15',
groups: [
groupAddedVersionOne,
],
}

const initialChangelog = {
changes: [
versionNext,
versionOne,
],
}

beforeEach(() => {
jest.clearAllMocks()
})

describe('buildFormattedChoices', () => {
it('should return a list of formatted choices from the given changelog', () => {
const result = interactiveMode.buildFormattedChoices(initialChangelog)

const expectedResult = [
new inquirer.Separator(`${groupAddedVersionNext.label} (version ${versionNext.version})`),
{
name: `${commitAddProcess.emoji} ${commitAddProcess.message}`,
value: commitAddProcess.hash,
checked: true,
},
{
name: `${commitAddOption.emoji} ${commitAddOption.message}`,
value: commitAddOption.hash,
checked: true,
},
new inquirer.Separator(`${groupChangedVersionNext.label} (version ${versionNext.version})`),
{
name: `${commitUpgradeDeps.emoji} ${commitUpgradeDeps.message}`,
value: commitUpgradeDeps.hash,
checked: true,
},
new inquirer.Separator(`${groupAddedVersionOne.label} (version ${versionOne.version})`),
{
name: `${commitAddAuthor.emoji} ${commitAddAuthor.message}`,
value: commitAddAuthor.hash,
checked: true,
},
]

expect(result).toEqual(expectedResult)
})
})

describe('getFilteredChangelog', () => {
it('should return a new filtered changelog from the given inital changelog and selected commits', () => {
const selectedCommitsHashes = [commitAddProcess.hash, commitAddAuthor.hash]

const result = interactiveMode.getFilteredChangelog(initialChangelog, selectedCommitsHashes)

const expectedResult = {
changes: [
{
version: 'next',
groups: [{
group: 'added',
label: 'Added',
commits: [
commitAddProcess,
],
}],
},
{
version: '1.1.0',
date: '2018-11-15',
groups: [
groupAddedVersionOne,
],
},
],
}

expect(result).toEqual(expectedResult)
})
})

describe('executeInteractiveMode', () => {
it('should call buildFormattedChoices, createPromptModule and getFilteredChangelog with correct parameters', async () => {
const formattedChoices = [{
name: `${commitAddProcess.emoji} ${commitAddProcess.message}`,
value: commitAddProcess.hash,
checked: true,
}]
const selectedCommitsHashes = [commitAddProcess.hash, commitAddOption.hash]
const prompt = jest.fn(() => Promise.resolve({ selectedCommitsHashes }))

interactiveMode.buildFormattedChoices = jest.fn(() => formattedChoices)
interactiveMode.getFilteredChangelog = jest.fn()
inquirer.createPromptModule = jest.fn()
inquirer.createPromptModule.mockReturnValueOnce(prompt)

await interactiveMode.executeInteractiveMode(initialChangelog)

expect(interactiveMode.buildFormattedChoices).toHaveBeenNthCalledWith(1, initialChangelog)
expect(inquirer.createPromptModule).toHaveBeenCalledTimes(1)
expect(prompt).toHaveBeenNthCalledWith(1, {
type: 'checkbox',
name: 'selectedCommitsHashes',
message: 'Select commits',
choices: formattedChoices,
pageSize: 10,
})
expect(interactiveMode.getFilteredChangelog)
.toHaveBeenNthCalledWith(1, initialChangelog, selectedCommitsHashes)
})
})
})
Loading

0 comments on commit d13ca2e

Please sign in to comment.