Skip to content

Commit f304bb0

Browse files
stalniypvdlg
authored andcommitted
feat(options): adds changelogTitle option
1 parent 3a09b0f commit f304bb0

File tree

7 files changed

+86
-10
lines changed

7 files changed

+86
-10
lines changed

README.md

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,9 +21,11 @@ Create or update the changelog file in the local project repository.
2121

2222
### Options
2323

24-
| Options | Description | Default |
25-
|-----------------|-----------------------------|----------------|
26-
| `changelogFile` | File path of the changelog. | `CHANGELOG.md` |
24+
| Options | Description | Default |
25+
|------------------|-----------------------------|----------------|
26+
| `changelogFile` | File path of the changelog. | `CHANGELOG.md` |
27+
| `changelogTitle` | Title in the changelog. | None |
28+
2729

2830
### Usage
2931

lib/definitions/errors.js

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,4 +13,12 @@ module.exports = {
1313
1414
Your configuration for the \`changelogFile\` option is \`${changelogFile}\`.`,
1515
}),
16+
EINVALIDCHANGELOGTITLE: ({changelogTitle}) => ({
17+
message: 'Invalid `changelogTitle` option.',
18+
details: `The [changelogTitle option](${linkify(
19+
'README.md#options'
20+
)}) option, if defined, must be a non empty \`String\`.
21+
22+
Your configuration for the \`changelogTitle\` option is \`${changelogTitle}\`.`,
23+
}),
1624
};

lib/prepare.js

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ const {readFile, writeFile, ensureFile} = require('fs-extra');
22
const resolveConfig = require('./resolve-config');
33

44
module.exports = async (pluginConfig, notes, logger) => {
5-
const {changelogFile} = resolveConfig(pluginConfig);
5+
const {changelogFile, changelogTitle} = resolveConfig(pluginConfig);
66

77
if (notes) {
88
await ensureFile(changelogFile);
@@ -13,6 +13,13 @@ module.exports = async (pluginConfig, notes, logger) => {
1313
} else {
1414
logger.log('Create %s', changelogFile);
1515
}
16-
await writeFile(changelogFile, `${notes.trim()}\n${currentFile ? `\n${currentFile}\n` : ''}`);
16+
17+
const currentContent =
18+
changelogTitle && currentFile.startsWith(changelogTitle)
19+
? currentFile.slice(changelogTitle.length).trim()
20+
: currentFile;
21+
const content = `${notes.trim()}\n${currentContent ? `\n${currentContent}\n` : ''}`;
22+
23+
await writeFile(changelogFile, changelogTitle ? `${changelogTitle}\n\n${content}` : content);
1724
}
1825
};

lib/resolve-config.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
const {isUndefined} = require('lodash');
22

3-
module.exports = ({changelogFile}) => ({
3+
module.exports = ({changelogFile, changelogTitle}) => ({
44
changelogFile: isUndefined(changelogFile) ? 'CHANGELOG.md' : changelogFile,
5+
changelogTitle,
56
});

lib/verify.js

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,17 @@ const getError = require('./get-error');
44
const resolveConfig = require('./resolve-config');
55

66
module.exports = pluginConfig => {
7-
const {changelogFile} = resolveConfig(pluginConfig);
7+
const {changelogFile, changelogTitle} = resolveConfig(pluginConfig);
88
const errors = [];
99

1010
if (!isUndefined(changelogFile) && !(isString(changelogFile) && changelogFile.trim())) {
1111
errors.push(getError('EINVALIDCHANGELOGFILE', {changelogFile}));
1212
}
1313

14+
if (!isUndefined(changelogTitle) && !(isString(changelogTitle) && changelogTitle.trim())) {
15+
errors.push(getError('EINVALIDCHANGELOGTITLE', {changelogTitle}));
16+
}
17+
1418
if (errors.length > 0) {
1519
throw new AggregateError(errors);
1620
}

test/prepare.test.js

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,3 +53,33 @@ test.serial('Prepend the CHANGELOG.md if there is an existing one', async t => {
5353
t.is((await readFile('CHANGELOG.md')).toString(), `${notes}\n\nInitial CHANGELOG\n`);
5454
t.deepEqual(t.context.log.args[0], ['Update %s', 'CHANGELOG.md']);
5555
});
56+
57+
test.serial('Prepend title in the CHANGELOG.md if there is none', async t => {
58+
const notes = 'Test release note';
59+
await outputFile('CHANGELOG.md', 'Initial CHANGELOG');
60+
61+
const changelogTitle = '# My Changelog Title';
62+
await prepare({changelogTitle}, notes, t.context.logger);
63+
64+
t.is((await readFile('CHANGELOG.md')).toString(), `${changelogTitle}\n\n${notes}\n\nInitial CHANGELOG\n`);
65+
});
66+
67+
test.serial('Keep the title at the top of the CHANGELOG.md', async t => {
68+
const notes = 'Test release note';
69+
const changelogTitle = '# My Changelog Title';
70+
await outputFile('CHANGELOG.md', `${changelogTitle}\n\nInitial CHANGELOG`);
71+
72+
await prepare({changelogTitle}, notes, t.context.logger);
73+
74+
t.is((await readFile('CHANGELOG.md')).toString(), `${changelogTitle}\n\n${notes}\n\nInitial CHANGELOG\n`);
75+
});
76+
77+
test.serial('Create new changelog with title if specified', async t => {
78+
const notes = 'Test release note';
79+
const changelogTitle = '# My Changelog Title';
80+
const changelogFile = 'HISTORY.md';
81+
82+
await prepare({changelogTitle, changelogFile}, notes, t.context.logger);
83+
84+
t.is((await readFile(changelogFile)).toString(), `${changelogTitle}\n\n${notes}\n`);
85+
});

test/verify.test.js

Lines changed: 27 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,13 @@
11
import test from 'ava';
22
import verify from '../lib/verify';
33

4-
test.serial('Verify String "changelogFile"', t => {
4+
test.serial('Verify String "changelogFile" and "chagngelogTitle"', t => {
55
const changelogFile = 'docs/changelog.txt';
6-
t.notThrows(() => verify({changelogFile}));
6+
const changelogTitle = '# My title here';
7+
t.notThrows(() => verify({changelogFile, changelogTitle}));
78
});
89

9-
test.serial('Verify undefined "changelogFile"', t => {
10+
test.serial('Verify undefined "changelogFile" and "chagngelogTitle"', t => {
1011
t.notThrows(() => verify({}));
1112
});
1213

@@ -33,3 +34,26 @@ test('Throw SemanticReleaseError if "changelogFile" option is a whitespace Strin
3334
t.is(error.name, 'SemanticReleaseError');
3435
t.is(error.code, 'EINVALIDCHANGELOGFILE');
3536
});
37+
38+
test('Throw SemanticReleaseError if "changelogTitle" option is not a String', t => {
39+
const changelogTitle = 42;
40+
const [error] = t.throws(() => verify({changelogTitle}));
41+
42+
t.is(error.name, 'SemanticReleaseError');
43+
t.is(error.code, 'EINVALIDCHANGELOGTITLE');
44+
});
45+
46+
test('Throw SemanticReleaseError if "changelogTitle" option is an empty String', t => {
47+
const [error] = t.throws(() => verify({changelogTitle: ''}));
48+
49+
t.is(error.name, 'SemanticReleaseError');
50+
t.is(error.code, 'EINVALIDCHANGELOGTITLE');
51+
});
52+
53+
test('Throw SemanticReleaseError if "changelogTitle" option is a whitespace String', t => {
54+
const changelogTitle = ' \n \r ';
55+
const [error] = t.throws(() => verify({changelogTitle}));
56+
57+
t.is(error.name, 'SemanticReleaseError');
58+
t.is(error.code, 'EINVALIDCHANGELOGTITLE');
59+
});

0 commit comments

Comments
 (0)