@release-it/keep-a-changelog 2.0.0 → 2.2.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +6 -4
- package/index.js +42 -7
- package/package.json +9 -5
- package/test.js +97 -22
package/README.md
CHANGED
|
@@ -21,8 +21,10 @@ In [release-it](https://github.com/release-it/release-it) config:
|
|
|
21
21
|
|
|
22
22
|
## Options
|
|
23
23
|
|
|
24
|
-
| option | default value | description
|
|
25
|
-
| -------------- | -------------- |
|
|
26
|
-
| filename | `CHANGELOG.md` | File with changelogs.
|
|
24
|
+
| option | default value | description |
|
|
25
|
+
| -------------- | -------------- | ------------------------------------------------------------------------------------------------------------------------------------------------ |
|
|
26
|
+
| filename | `CHANGELOG.md` | File with changelogs. |
|
|
27
27
|
| strictLatest | `true` | Entry of latest version must be present in order to get correct changelog. Set this option to `false` if you expect latest version without logs. |
|
|
28
|
-
|
|
|
28
|
+
| addUnreleased | `false` | It leaves "Unreleased" title row if set to `true`. |
|
|
29
|
+
| keepUnreleased | `false` | It leaves "Unreleased" title row unchanged if set to `true`. |
|
|
30
|
+
| addVersionUrl | `false` | Links the version to the according changeset. |
|
package/index.js
CHANGED
|
@@ -11,18 +11,21 @@ const getFormattedDate = () => {
|
|
|
11
11
|
};
|
|
12
12
|
|
|
13
13
|
class KeepAChangelog extends Plugin {
|
|
14
|
-
init() {
|
|
15
|
-
|
|
14
|
+
async init() {
|
|
15
|
+
await super.init();
|
|
16
|
+
const { filename, strictLatest, addUnreleased, keepUnreleased, addVersionUrl } = this.options;
|
|
16
17
|
|
|
17
18
|
this.filename = filename || 'CHANGELOG.md';
|
|
18
19
|
this.strictLatest = strictLatest === undefined ? true : Boolean(strictLatest);
|
|
20
|
+
this.addUnreleased = addUnreleased === undefined ? false : Boolean(addUnreleased);
|
|
19
21
|
this.keepUnreleased = keepUnreleased === undefined ? false : Boolean(keepUnreleased);
|
|
22
|
+
this.addVersionUrl = addVersionUrl === undefined ? false : Boolean(addVersionUrl);
|
|
20
23
|
|
|
21
24
|
this.changelogPath = path.resolve(this.filename);
|
|
22
25
|
this.changelogContent = fs.readFileSync(this.changelogPath, 'utf-8');
|
|
23
26
|
this.EOL = detectNewline(this.changelogContent);
|
|
24
27
|
this.unreleasedTitleRaw = 'Unreleased';
|
|
25
|
-
this.unreleasedTitle =
|
|
28
|
+
this.unreleasedTitle = `## [${this.unreleasedTitleRaw}]`;
|
|
26
29
|
|
|
27
30
|
const hasUnreleasedSection = this.changelogContent.includes(this.unreleasedTitle);
|
|
28
31
|
if (!hasUnreleasedSection) {
|
|
@@ -62,15 +65,47 @@ class KeepAChangelog extends Plugin {
|
|
|
62
65
|
this.setContext({ version });
|
|
63
66
|
}
|
|
64
67
|
|
|
68
|
+
addVersionUrls(changelog) {
|
|
69
|
+
const { version, latestVersion, tagName, latestTag, repo } = this.config.getContext();
|
|
70
|
+
let updatedChangelog = changelog;
|
|
71
|
+
|
|
72
|
+
const repositoryUrl = `https://${repo.host}/${repo.repository}`;
|
|
73
|
+
|
|
74
|
+
// Add or update the Unreleased link
|
|
75
|
+
const unreleasedUrl = `${repositoryUrl}/compare/${tagName}...HEAD`;
|
|
76
|
+
const unreleasedLink = `[Unreleased]: ${unreleasedUrl}`;
|
|
77
|
+
if (updatedChangelog.includes('[Unreleased]:')) {
|
|
78
|
+
updatedChangelog = updatedChangelog.replace(/\[Unreleased\]\:.*HEAD/, unreleasedLink);
|
|
79
|
+
} else {
|
|
80
|
+
updatedChangelog = `${updatedChangelog}${this.EOL}${this.EOL}${unreleasedLink}`;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
// Add a link for the new version
|
|
84
|
+
const latestVersionLink = `[${latestVersion}]:`;
|
|
85
|
+
const releaseUrl = `${repositoryUrl}/compare/${latestTag}...${tagName}`;
|
|
86
|
+
const releaseLink = `[${version}]: ${releaseUrl}`;
|
|
87
|
+
if (updatedChangelog.includes(latestVersionLink)) {
|
|
88
|
+
return updatedChangelog.replace(latestVersionLink, `${releaseLink}${this.EOL}${latestVersionLink}`);
|
|
89
|
+
} else {
|
|
90
|
+
return `${updatedChangelog}${this.EOL}${releaseLink}`;
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
|
|
65
94
|
beforeRelease() {
|
|
66
|
-
const { keepUnreleased } = this;
|
|
95
|
+
const { addUnreleased, keepUnreleased, addVersionUrl } = this;
|
|
67
96
|
const { isDryRun } = this.config;
|
|
68
97
|
if (isDryRun || keepUnreleased) return;
|
|
69
98
|
const { version } = this.getContext();
|
|
70
99
|
const formattedDate = getFormattedDate();
|
|
71
|
-
const
|
|
72
|
-
const
|
|
73
|
-
|
|
100
|
+
const unreleasedTitle = addUnreleased ? this.unreleasedTitle + this.EOL + this.EOL : '';
|
|
101
|
+
const releaseTitle = `${unreleasedTitle}## [${version}] - ${formattedDate}`;
|
|
102
|
+
let changelog = this.changelogContent.replace(this.unreleasedTitle, releaseTitle);
|
|
103
|
+
|
|
104
|
+
if (addVersionUrl) {
|
|
105
|
+
changelog = this.addVersionUrls(changelog);
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
fs.writeFileSync(this.changelogPath, changelog.trim() + this.EOL);
|
|
74
109
|
}
|
|
75
110
|
}
|
|
76
111
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@release-it/keep-a-changelog",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.2.2",
|
|
4
4
|
"description": "Keep-a-changelog plugin for release-it",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"scripts": {
|
|
@@ -10,7 +10,11 @@
|
|
|
10
10
|
"keywords": [
|
|
11
11
|
"release",
|
|
12
12
|
"release-it",
|
|
13
|
-
"release-it-plugin"
|
|
13
|
+
"release-it-plugin",
|
|
14
|
+
"keep-a-changelog",
|
|
15
|
+
"changelog",
|
|
16
|
+
"changes",
|
|
17
|
+
"unreleased"
|
|
14
18
|
],
|
|
15
19
|
"license": "MIT",
|
|
16
20
|
"repository": {
|
|
@@ -30,11 +34,11 @@
|
|
|
30
34
|
"devDependencies": {
|
|
31
35
|
"bron": "^1.1.1",
|
|
32
36
|
"mock-fs": "^4.13.0",
|
|
33
|
-
"release-it": "^14.
|
|
34
|
-
"sinon": "^9.
|
|
37
|
+
"release-it": "^14.2.0",
|
|
38
|
+
"sinon": "^9.2.1"
|
|
35
39
|
},
|
|
36
40
|
"peerDependencies": {
|
|
37
|
-
"release-it": "^14.
|
|
41
|
+
"release-it": "^14.2.0"
|
|
38
42
|
},
|
|
39
43
|
"engines": {
|
|
40
44
|
"node": ">=10"
|
package/test.js
CHANGED
|
@@ -2,6 +2,7 @@ const fs = require('fs');
|
|
|
2
2
|
const test = require('bron');
|
|
3
3
|
const assert = require('assert').strict;
|
|
4
4
|
const mock = require('mock-fs');
|
|
5
|
+
const sinon = require('sinon');
|
|
5
6
|
const { factory, runTasks } = require('release-it/test/util');
|
|
6
7
|
const Plugin = require('.');
|
|
7
8
|
|
|
@@ -9,18 +10,25 @@ const initialDryRunFileContents =
|
|
|
9
10
|
'\n\n## [Unreleased]\n\n* Item A\n* Item B\n\n## [1.0.0] - 2020-05-02\n\n* Item C\n* Item D';
|
|
10
11
|
|
|
11
12
|
mock({
|
|
12
|
-
'./CHANGELOG-FOO.md': '
|
|
13
|
-
'./CHANGELOG-
|
|
14
|
-
'./CHANGELOG-EMPTY.md': '
|
|
15
|
-
'./CHANGELOG-FULL.md':
|
|
13
|
+
'./CHANGELOG-FOO.md': '## [FOO]\n\n* Item A\n* Item B',
|
|
14
|
+
'./CHANGELOG-MISSING.md': '## [Unreleased]\n\n* Item A\n* Item B',
|
|
15
|
+
'./CHANGELOG-EMPTY.md': '## [Unreleased]\n\n\n\n## [1.0.0]\n\n* Item A\n* Item B',
|
|
16
|
+
'./CHANGELOG-FULL.md':
|
|
17
|
+
'# Changelog\n\n## [Unreleased]\n\n* Item A\n* Item B\n\n## [1.0.0] - 2020-05-02\n\n* Item C\n* Item D',
|
|
18
|
+
'./CHANGELOG-NO-STRICT.md': '## [Unreleased]\n\n* Item A\n* Item B\n\n## [1.0.0] - 2020-05-02\n\n* Item C\n* Item D',
|
|
16
19
|
'./CHANGELOG-DRYRUN.md': initialDryRunFileContents,
|
|
17
|
-
'./CHANGELOG-LESS_NEW_LINES.md':
|
|
18
|
-
'\n\n## [Unreleased]\n* Item A\n* Item B\n## [1.0.0] - 2020-05-02\n* Item C\n* Item D',
|
|
20
|
+
'./CHANGELOG-LESS_NEW_LINES.md': '## [Unreleased]\n* Item A\n* Item B\n## [1.0.0] - 2020-05-02\n* Item C\n* Item D',
|
|
19
21
|
'./CHANGELOG-EOL.md':
|
|
20
|
-
'\r\n\r\n## [Unreleased]\r\n\r\n* Item A\r\n* Item B\r\n\r\n## [1.0.0] - 2020-05-02\r\n\r\n* Item C\r\n* Item D'
|
|
22
|
+
'\r\n\r\n## [Unreleased]\r\n\r\n* Item A\r\n* Item B\r\n\r\n## [1.0.0] - 2020-05-02\r\n\r\n* Item C\r\n* Item D',
|
|
23
|
+
'./CHANGELOG-UNRELEASED.md': '## [Unreleased]\n\n* Item A\n* Item B\n\n## [1.0.0] - 2020-05-02\n\n* Item C\n* Item D',
|
|
24
|
+
'./CHANGELOG-VERSION_URL.md':
|
|
25
|
+
'## [Unreleased]\n\n* Item A\n* Item B\n\n## [1.0.0] - 2020-05-02\n\n* Item C\n* Item D\n\n[Unreleased]: https://github.com/release-it/release-it/compare/1.0.0..HEAD\n[1.0.0]: https://github.com/release-it/release-it/compare/0.0.0...1.0.0',
|
|
26
|
+
'./CHANGELOG-VERSION_URL_UNRELEASED.md':
|
|
27
|
+
'## [Unreleased]\n\n* Item A\n* Item B\n\n## [1.0.0] - 2020-05-02\n\n* Item C\n* Item D\n\n[Unreleased]: https://github.com/user/project/compare/1.0.0..HEAD\n[1.0.0]: https://github.com/user/project/compare/0.0.0...1.0.0',
|
|
28
|
+
'./CHANGELOG-VERSION_URL_NEW.md': '## [Unreleased]\n\n* Item A\n* Item B'
|
|
21
29
|
});
|
|
22
30
|
|
|
23
|
-
const readFile = file => fs.readFileSync(file).toString()
|
|
31
|
+
const readFile = file => fs.readFileSync(file).toString();
|
|
24
32
|
|
|
25
33
|
const namespace = 'keep-a-changelog';
|
|
26
34
|
|
|
@@ -43,12 +51,9 @@ test('should throw for empty "unreleased" section', async t => {
|
|
|
43
51
|
});
|
|
44
52
|
|
|
45
53
|
test('should throw for missing section for previous release', async t => {
|
|
46
|
-
const options = { [namespace]: { filename: 'CHANGELOG-
|
|
54
|
+
const options = { [namespace]: { filename: 'CHANGELOG-MISSING.md' } };
|
|
47
55
|
const plugin = factory(Plugin, { namespace, options });
|
|
48
|
-
await assert.rejects(
|
|
49
|
-
runTasks(plugin),
|
|
50
|
-
/Missing section for previous release \("1\.0\.0"\) in CHANGELOG-UNRELEASED\.md/
|
|
51
|
-
);
|
|
56
|
+
await assert.rejects(runTasks(plugin), /Missing section for previous release \("1\.0\.0"\) in CHANGELOG-MISSING\.md/);
|
|
52
57
|
});
|
|
53
58
|
|
|
54
59
|
test('should find very first changelog with disabled strict latest option', async t => {
|
|
@@ -65,18 +70,18 @@ test('should write changelog', async t => {
|
|
|
65
70
|
assert.equal(plugin.getChangelog(), '* Item A\n* Item B');
|
|
66
71
|
assert.match(
|
|
67
72
|
readFile('./CHANGELOG-FULL.md'),
|
|
68
|
-
|
|
73
|
+
/^# Changelog\n\n## \[1\.0\.1] - [0-9]{4}-[0-9]{2}-[0-9]{2}\n\n\* Item A\n\* Item B\n\n## \[1\.0\.0] - 2020-05-02\n\n\* Item C\n*\* Item D\n$/
|
|
69
74
|
);
|
|
70
75
|
});
|
|
71
76
|
|
|
72
|
-
test('should write changelog even with
|
|
73
|
-
const options = { [namespace]: { filename: 'CHANGELOG-
|
|
77
|
+
test('should write changelog even with `strictLatest: false`', async t => {
|
|
78
|
+
const options = { [namespace]: { filename: 'CHANGELOG-NO-STRICT.md', strictLatest: false } };
|
|
74
79
|
const plugin = factory(Plugin, { namespace, options });
|
|
75
80
|
await runTasks(plugin);
|
|
76
81
|
assert.equal(plugin.getChangelog(), '* Item A\n* Item B');
|
|
77
82
|
assert.match(
|
|
78
|
-
readFile('./CHANGELOG-
|
|
79
|
-
/## \[1\.0\.1
|
|
83
|
+
readFile('./CHANGELOG-NO-STRICT.md'),
|
|
84
|
+
/## \[1\.0\.1] - [0-9]{4}-[0-9]{2}-[0-9]{2}\n\n\* Item A\n\* Item B\n\n## \[1\.0\.0] - 2020-05-02\n\n\* Item C\n*\* Item D/
|
|
80
85
|
);
|
|
81
86
|
});
|
|
82
87
|
|
|
@@ -84,14 +89,14 @@ test('should not write changelog in dry run', async t => {
|
|
|
84
89
|
const options = { 'dry-run': true, [namespace]: { filename: 'CHANGELOG-DRYRUN.md' } };
|
|
85
90
|
const plugin = factory(Plugin, { namespace, options });
|
|
86
91
|
await runTasks(plugin);
|
|
87
|
-
assert.equal(
|
|
92
|
+
assert.equal(readFile('./CHANGELOG-DRYRUN.md'), initialDryRunFileContents);
|
|
88
93
|
});
|
|
89
94
|
|
|
90
95
|
test('should not write changelog with keep unreleased option', async t => {
|
|
91
96
|
const options = { [namespace]: { filename: 'CHANGELOG-DRYRUN.md', keepUnreleased: true } };
|
|
92
97
|
const plugin = factory(Plugin, { namespace, options });
|
|
93
98
|
await runTasks(plugin);
|
|
94
|
-
assert.equal(
|
|
99
|
+
assert.equal(readFile('./CHANGELOG-DRYRUN.md'), initialDryRunFileContents);
|
|
95
100
|
});
|
|
96
101
|
|
|
97
102
|
test('should find changelog even if less new lines is used', async t => {
|
|
@@ -101,13 +106,83 @@ test('should find changelog even if less new lines is used', async t => {
|
|
|
101
106
|
assert.equal(plugin.getChangelog(), '* Item A\n* Item B');
|
|
102
107
|
});
|
|
103
108
|
|
|
104
|
-
test('should write changelog
|
|
109
|
+
test('should write changelog with different EOL', async t => {
|
|
105
110
|
const options = { [namespace]: { filename: 'CHANGELOG-EOL.md' } };
|
|
106
111
|
const plugin = factory(Plugin, { namespace, options });
|
|
107
112
|
await runTasks(plugin);
|
|
108
113
|
assert.equal(plugin.getChangelog(), '* Item A\r\n* Item B');
|
|
109
114
|
assert.match(
|
|
110
115
|
readFile('./CHANGELOG-EOL.md'),
|
|
111
|
-
|
|
116
|
+
/^## \[1\.0\.1] - [0-9]{4}-[0-9]{2}-[0-9]{2}\r\n\r\n\* Item A\r\n\* Item B\r\n\r\n## \[1\.0\.0] - 2020-05-02\r\n\r\n\* Item C\r\n*\* Item D\r\n/
|
|
117
|
+
);
|
|
118
|
+
});
|
|
119
|
+
|
|
120
|
+
test('should write changelog and add unreleased section', async t => {
|
|
121
|
+
const options = { [namespace]: { filename: 'CHANGELOG-UNRELEASED.md', addUnreleased: true } };
|
|
122
|
+
const plugin = factory(Plugin, { namespace, options });
|
|
123
|
+
await runTasks(plugin);
|
|
124
|
+
assert.equal(plugin.getChangelog(), '* Item A\n* Item B');
|
|
125
|
+
assert.match(
|
|
126
|
+
readFile('./CHANGELOG-UNRELEASED.md'),
|
|
127
|
+
/^## \[Unreleased]\n\n## \[1\.0\.1] - [0-9]{4}-[0-9]{2}-[0-9]{2}\n\n\* Item A\n\* Item B\n\n## \[1\.0\.0] - 2020-05-02\n\n\* Item C\n*\* Item D/
|
|
128
|
+
);
|
|
129
|
+
});
|
|
130
|
+
|
|
131
|
+
test('should add links to the end of the file', async t => {
|
|
132
|
+
const options = { [namespace]: { filename: 'CHANGELOG-VERSION_URL.md', addVersionUrl: true } };
|
|
133
|
+
const plugin = factory(Plugin, { namespace, options });
|
|
134
|
+
plugin.config.setContext({
|
|
135
|
+
latestTag: '1.0.0',
|
|
136
|
+
repo: {
|
|
137
|
+
host: 'github.com',
|
|
138
|
+
repository: 'release-it/release-it'
|
|
139
|
+
}
|
|
140
|
+
});
|
|
141
|
+
await runTasks(plugin);
|
|
142
|
+
assert.equal(plugin.getChangelog(), '* Item A\n* Item B');
|
|
143
|
+
assert.match(
|
|
144
|
+
readFile('./CHANGELOG-VERSION_URL.md'),
|
|
145
|
+
/^## \[1\.0\.1] - [0-9]{4}-[0-9]{2}-[0-9]{2}\n\n\* Item A\n\* Item B\n\n## \[1\.0\.0] - 2020-05-02\n\n\* Item C\n*\* Item D\n\n\[Unreleased]: https:\/\/github\.com\/release-it\/release-it\/compare\/1\.0\.1\.\.\.HEAD\n\[1\.0\.1]: https:\/\/github\.com\/release-it\/release-it\/compare\/1\.0\.0\.\.\.1\.0\.1\n\[1\.0\.0]: https:\/\/github\.com\/release-it\/release-it\/compare\/0\.0\.0\.\.\.1\.0\.0\n$/
|
|
146
|
+
);
|
|
147
|
+
});
|
|
148
|
+
|
|
149
|
+
test('should add unreleased section and links to the end of the file', async t => {
|
|
150
|
+
const options = {
|
|
151
|
+
[namespace]: { filename: 'CHANGELOG-VERSION_URL_UNRELEASED.md', addVersionUrl: true, addUnreleased: true }
|
|
152
|
+
};
|
|
153
|
+
const plugin = factory(Plugin, { namespace, options });
|
|
154
|
+
plugin.config.setContext({
|
|
155
|
+
latestTag: '1.0.0',
|
|
156
|
+
repo: {
|
|
157
|
+
host: 'github.com',
|
|
158
|
+
repository: 'user/project'
|
|
159
|
+
}
|
|
160
|
+
});
|
|
161
|
+
await runTasks(plugin);
|
|
162
|
+
assert.equal(plugin.getChangelog(), '* Item A\n* Item B');
|
|
163
|
+
assert.match(
|
|
164
|
+
readFile('./CHANGELOG-VERSION_URL_UNRELEASED.md'),
|
|
165
|
+
/^## \[Unreleased]\n\n## \[1\.0\.1] - [0-9]{4}-[0-9]{2}-[0-9]{2}\n\n\* Item A\n\* Item B\n\n## \[1\.0\.0] - 2020-05-02\n\n\* Item C\n*\* Item D\n\n\[Unreleased]: https:\/\/github\.com\/user\/project\/compare\/1\.0\.1\.\.\.HEAD\n\[1\.0\.1]: https:\/\/github\.com\/user\/project\/compare\/1\.0\.0\.\.\.1\.0\.1\n\[1\.0\.0]: https:\/\/github\.com\/user\/project\/compare\/0\.0\.0\.\.\.1\.0\.0\n/
|
|
166
|
+
);
|
|
167
|
+
});
|
|
168
|
+
|
|
169
|
+
test('should add link to the end of a new changelog', async t => {
|
|
170
|
+
const options = {
|
|
171
|
+
[namespace]: { filename: 'CHANGELOG-VERSION_URL_NEW.md', addVersionUrl: true, strictLatest: false }
|
|
172
|
+
};
|
|
173
|
+
const plugin = factory(Plugin, { namespace, options });
|
|
174
|
+
sinon.stub(plugin, 'getLatestVersion').returns('0.0.0');
|
|
175
|
+
plugin.config.setContext({
|
|
176
|
+
increment: 'major',
|
|
177
|
+
repo: {
|
|
178
|
+
host: 'github.com',
|
|
179
|
+
repository: 'user/project'
|
|
180
|
+
}
|
|
181
|
+
});
|
|
182
|
+
await runTasks(plugin);
|
|
183
|
+
assert.equal(plugin.getChangelog(), '* Item A\n* Item B');
|
|
184
|
+
assert.match(
|
|
185
|
+
readFile('./CHANGELOG-VERSION_URL_NEW.md'),
|
|
186
|
+
/^## \[1\.0\.0] - [0-9]{4}-[0-9]{2}-[0-9]{2}\n\n\* Item A\n\* Item B\n\n\[Unreleased]: https:\/\/github\.com\/user\/project\/compare\/1\.0\.0\.\.\.HEAD\n\[1.0.0]: https:\/\/github\.com\/user\/project\/compare\/0\.0\.0\.\.\.1\.0\.0\n$/
|
|
112
187
|
);
|
|
113
188
|
});
|