-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
refactor: move util tests to separate files
- Loading branch information
1 parent
c5f11da
commit db810d5
Showing
9 changed files
with
574 additions
and
553 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,5 +1,9 @@ | ||
## Latest | ||
|
||
### BREAKING | ||
|
||
- group changelog entries by type c5f11dab | ||
|
||
### Features | ||
|
||
- add --root option b813606b | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,81 @@ | ||
import { readFile } from 'fs' | ||
import { getCommitDetails } from './git' | ||
|
||
export const generateReleased = previousVersion => | ||
new Promise((resolve, reject) => | ||
readFile('CHANGELOG.md', 'utf8', (err, data) => { | ||
if (err) return reject(err) | ||
|
||
let isLatest = false | ||
const released = data | ||
.split('\n') | ||
.filter(line => { | ||
if (line === '## Latest') { | ||
isLatest = true | ||
|
||
return false | ||
} | ||
|
||
if (isLatest && line === `## ${previousVersion}`) { | ||
isLatest = false | ||
|
||
return true | ||
} | ||
|
||
return !isLatest | ||
}) | ||
.join('\n') | ||
|
||
if (isLatest) { | ||
return reject(new Error('Previous release not found in CHANGELOG')) | ||
} | ||
|
||
return resolve(released) | ||
}) | ||
) | ||
|
||
export const generateChangelog = (version, groups) => { | ||
const changelog = groups.map(group => { | ||
const release = getCommitDetails(group.release) | ||
const title = version || 'Latest' | ||
let groupChangelog = `## ${release ? release.message : title}\n\n` | ||
|
||
const entries = Object.entries(group) | ||
|
||
entries.sort().forEach(([title, commits]) => { | ||
if (title === 'release') return | ||
|
||
switch (title) { | ||
case 'breaking': | ||
groupChangelog += '### BREAKING\n\n' | ||
break | ||
case 'feat': | ||
groupChangelog += '### Features\n\n' | ||
break | ||
case 'fix': | ||
groupChangelog += '### Fixes\n\n' | ||
break | ||
default: | ||
groupChangelog += '### Misc\n\n' | ||
break | ||
} | ||
|
||
return commits.forEach((commit, index) => { | ||
const { message, hash } = getCommitDetails(commit) | ||
|
||
const isLastLine = index + 1 === commits.length | ||
const space = isLastLine ? '\n\n' : '\n' | ||
const line = generateLine({ message, hash }) + space | ||
|
||
return (groupChangelog += line) | ||
}) | ||
}) | ||
|
||
return groupChangelog | ||
}) | ||
|
||
return changelog.join('') | ||
} | ||
|
||
export const generateLine = ({ message, hash }) => | ||
`- ${message} ${hash.slice(0, 8)}` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,122 @@ | ||
import { readFile } from 'fs' | ||
import { generateChangelog, generateLine, generateReleased } from './changelog' | ||
|
||
jest.mock('fs', () => ({ | ||
readFile: jest.fn() | ||
})) | ||
|
||
describe('changelog', () => { | ||
beforeEach(() => jest.resetAllMocks()) | ||
|
||
describe('generateReleased', () => { | ||
it('should reject if receives an error', async () => { | ||
const error = 'error' | ||
readFile.mockImplementation((_, __, cb) => cb(error)) | ||
|
||
expect(generateReleased()).rejects.toMatch(error) | ||
}) | ||
|
||
it('should reject if there is no released but tag provided', async () => { | ||
const error = 'Previous release not found in CHANGELOG' | ||
const mockedInput = | ||
'## Latest\n- feat: include changelog in the releases 2da21c56\n- test: add utils tests 217b25d0' | ||
readFile.mockImplementation((_, __, cb) => cb(null, mockedInput)) | ||
|
||
expect(generateReleased('2.2.2')).rejects.toThrow(error) | ||
}) | ||
|
||
it('should generate released', async () => { | ||
const mockedInput = | ||
'## Latest\n- feat: include changelog in the releases 2da21c56\n- test: add utils tests 217b25d0\n## 2.2.2\n- feat: add feature 2da21c56' | ||
const mockedOutput = '## 2.2.2\n- feat: add feature 2da21c56' | ||
readFile.mockImplementation((_, __, cb) => cb(null, mockedInput)) | ||
const released = await generateReleased('2.2.2') | ||
|
||
expect(released).toBe(mockedOutput) | ||
}) | ||
}) | ||
|
||
describe('generateChangelog', () => { | ||
it('should generate changelog', () => { | ||
const mockedInput = [ | ||
{ | ||
breaking: [ | ||
'b2f5901922505efbfb6dd684252e8df0cdffeeb2 feat!: add new api', | ||
'2ea04355c1e81c5088eeabc6e242fb1ade978524 feat!: deprecate function' | ||
], | ||
feat: [ | ||
'aa805ce71ee103965ce3db46d4f6ed2658efd08d feat: add option to write to local CHANGELOG file' | ||
], | ||
misc: [ | ||
'bffc2f9e8da1c7ac133689bc9cd14494f3be08e3 refactor: extract line generating logic to function and promisify exec' | ||
] | ||
}, | ||
{ | ||
release: | ||
'f2191200bf7b6e5eec3d61fcef9eb756e0129cfb chore(release): 0.1.0', | ||
fix: [ | ||
'b2f5901922505efbfb6dd684252e8df0cdffeeb2 fix: support other conventions' | ||
], | ||
feat: [ | ||
'4e02179cae1234d7083036024080a3f25fcb52c2 feat: add execute release feature' | ||
], | ||
misc: [ | ||
'4e02179cae1234d7083036024080a3f25fcb52c2 chore: update dependencies' | ||
] | ||
} | ||
] | ||
const mockedOutput = | ||
'## Latest\n\n### BREAKING\n\n- add new api b2f59019\n- deprecate function 2ea04355\n\n### Features\n\n- add option to write to local CHANGELOG file aa805ce7\n\n### Misc\n\n- extract line generating logic to function and promisify exec bffc2f9e\n\n## 0.1.0\n\n### Features\n\n- add execute release feature 4e02179c\n\n### Fixes\n\n- support other conventions b2f59019\n\n### Misc\n\n- update dependencies 4e02179c\n\n' | ||
|
||
expect(generateChangelog(null, mockedInput)).toBe(mockedOutput) | ||
}) | ||
|
||
it('should generate changelog with version', () => { | ||
const mockedInput = [ | ||
{ | ||
breaking: [ | ||
'b2f5901922505efbfb6dd684252e8df0cdffeeb2 feat!: add new api', | ||
'2ea04355c1e81c5088eeabc6e242fb1ade978524 feat!: deprecate function' | ||
], | ||
feat: [ | ||
'aa805ce71ee103965ce3db46d4f6ed2658efd08d feat: add option to write to local CHANGELOG file' | ||
], | ||
misc: [ | ||
'bffc2f9e8da1c7ac133689bc9cd14494f3be08e3 refactor: extract line generating logic to function and promisify exec' | ||
] | ||
}, | ||
{ | ||
release: | ||
'f2191200bf7b6e5eec3d61fcef9eb756e0129cfb chore(release): 0.1.0', | ||
fix: [ | ||
'b2f5901922505efbfb6dd684252e8df0cdffeeb2 fix: support other conventions' | ||
], | ||
feat: [ | ||
'4e02179cae1234d7083036024080a3f25fcb52c2 feat: add execute release feature' | ||
], | ||
misc: [ | ||
'4e02179cae1234d7083036024080a3f25fcb52c2 chore: update dependencies' | ||
] | ||
} | ||
] | ||
const mockedOutput = | ||
'## 2.0.0\n\n### BREAKING\n\n- add new api b2f59019\n- deprecate function 2ea04355\n\n### Features\n\n- add option to write to local CHANGELOG file aa805ce7\n\n### Misc\n\n- extract line generating logic to function and promisify exec bffc2f9e\n\n## 0.1.0\n\n### Features\n\n- add execute release feature 4e02179c\n\n### Fixes\n\n- support other conventions b2f59019\n\n### Misc\n\n- update dependencies 4e02179c\n\n' | ||
|
||
expect(generateChangelog('2.0.0', mockedInput)).toBe(mockedOutput) | ||
}) | ||
}) | ||
|
||
describe('generateLine', () => { | ||
it('should generate line', () => { | ||
const mockedInput = { | ||
message: 'generate changelog', | ||
hash: 'b2f5901922505efbfb6dd684252e8df0cdffeeb2' | ||
} | ||
const mockedOutput = '- generate changelog b2f59019' | ||
|
||
const line = generateLine(mockedInput) | ||
|
||
expect(line).toEqual(mockedOutput) | ||
}) | ||
}) | ||
}) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,42 @@ | ||
import { execAsync } from './misc' | ||
|
||
export const getCommits = async tag => { | ||
const query = tag | ||
? `git log --format="%H %s" ${tag}..` | ||
: 'git log --format="%H %s"' | ||
const commits = await execAsync(query) | ||
|
||
return commits.split('\n').filter(commit => commit) | ||
} | ||
|
||
export const getLatestTag = async () => { | ||
const latestTag = await execAsync('git tag | tail -n 1') | ||
|
||
return latestTag ? latestTag.replace('\n', '') : null | ||
} | ||
|
||
export const getCommitDetails = commit => { | ||
if (!commit) return null | ||
|
||
const { | ||
groups: { hash, title } | ||
} = commit.match(/(?<hash>.{40}) (?<title>.*)/) | ||
|
||
const commitDetails = title.match( | ||
/(?<type>[\w ]*)(?:\((?<scope>[\w ]*)\))?(?<breaking>!)?: (?<message>.*)/ | ||
) | ||
|
||
if (!commitDetails) return title | ||
|
||
const { | ||
groups: { type, scope, message, breaking } | ||
} = commitDetails | ||
|
||
return { hash, title, type, scope, message, breaking } | ||
} | ||
|
||
export const commitRelease = async version => { | ||
await execAsync('git add CHANGELOG.md package.json package-lock.json') | ||
await execAsync(`git commit -m 'chore(release): ${version}'`) | ||
await execAsync(`git tag ${version}`) | ||
} |
Oops, something went wrong.