@eclipse-docks/cli 0.7.114 → 0.7.118
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 +7 -3
- package/package.json +1 -1
- package/src/commands/release.js +41 -11
package/README.md
CHANGED
|
@@ -9,6 +9,7 @@ npx @eclipse-docks/cli release # bump patch, prompt for re
|
|
|
9
9
|
npx @eclipse-docks/cli release minor # bump minor
|
|
10
10
|
npx @eclipse-docks/cli release major -m "notes" # bump major with inline release notes
|
|
11
11
|
npx @eclipse-docks/cli release v1.2.3 # explicit version
|
|
12
|
+
npx @eclipse-docks/cli release --since v1.2.0 # notes from that version (bump still from latest)
|
|
12
13
|
npx @eclipse-docks/cli release --dry-run # print what would be committed
|
|
13
14
|
npx @eclipse-docks/cli release --no-push # commit locally without pushing
|
|
14
15
|
```
|
|
@@ -20,7 +21,10 @@ Pair this with a CI workflow that tags/releases on that commit subject (see
|
|
|
20
21
|
[`.github/workflows/app-release.yml`](../../.github/workflows/app-release.yml) for a
|
|
21
22
|
reusable one) — the commit body becomes the release notes.
|
|
22
23
|
|
|
24
|
+
The last version is taken from the most recent commit whose subject is exactly `vX.Y.Z`
|
|
25
|
+
or the legacy form `Release: vX.Y.Z`. That drives the default bump.
|
|
26
|
+
|
|
23
27
|
If no release notes are given via `-m`, an end-user-facing summary is generated from the
|
|
24
|
-
commits since
|
|
25
|
-
**Chore/Refactor**, and offered as the default
|
|
26
|
-
accept it).
|
|
28
|
+
commits since that version (or since `--since vX.Y.Z` when set), grouped under
|
|
29
|
+
**Features**, **Fixes**, **Docs**, and **Chore/Refactor**, and offered as the default
|
|
30
|
+
(press Enter on an empty first line to accept it).
|
package/package.json
CHANGED
package/src/commands/release.js
CHANGED
|
@@ -1,7 +1,10 @@
|
|
|
1
1
|
import { spawnSync } from 'node:child_process';
|
|
2
2
|
import { createInterface } from 'node:readline/promises';
|
|
3
3
|
|
|
4
|
+
/** CLI arg / new release commit subject: exact `vX.Y.Z`. */
|
|
4
5
|
const VERSION_RE = /^v\d+\.\d+\.\d+$/;
|
|
6
|
+
/** Discover last release from exact `vX.Y.Z` or legacy `Release: vX.Y.Z`. */
|
|
7
|
+
const VERSION_IN_SUBJECT_RE = /^(?:Release:\s*)?(v\d+\.\d+\.\d+)$/i;
|
|
5
8
|
|
|
6
9
|
function git(args, cwd) {
|
|
7
10
|
const result = spawnSync('git', args, { cwd, encoding: 'utf8' });
|
|
@@ -16,8 +19,18 @@ function gitOrNull(args, cwd) {
|
|
|
16
19
|
return result.status === 0 ? result.stdout.trim() : null;
|
|
17
20
|
}
|
|
18
21
|
|
|
22
|
+
function parseVersionSubject(subject) {
|
|
23
|
+
const m = subject.trim().match(VERSION_IN_SUBJECT_RE);
|
|
24
|
+
if (!m) return null;
|
|
25
|
+
return `v${m[1].slice(1)}`;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
function usage() {
|
|
29
|
+
return 'Usage: docks release [major|minor|patch|vX.Y.Z] [-m "release notes"] [--since vX.Y.Z] [--dry-run] [--no-push]';
|
|
30
|
+
}
|
|
31
|
+
|
|
19
32
|
function parseArgs(argv) {
|
|
20
|
-
const opts = { bump: 'patch', version: '', notes: '', dryRun: false, push: true };
|
|
33
|
+
const opts = { bump: 'patch', version: '', since: '', notes: '', dryRun: false, push: true };
|
|
21
34
|
|
|
22
35
|
for (let i = 0; i < argv.length; i++) {
|
|
23
36
|
const arg = argv[i];
|
|
@@ -25,6 +38,12 @@ function parseArgs(argv) {
|
|
|
25
38
|
opts.bump = arg;
|
|
26
39
|
} else if (VERSION_RE.test(arg)) {
|
|
27
40
|
opts.version = arg;
|
|
41
|
+
} else if (arg === '--since') {
|
|
42
|
+
const value = argv[++i] ?? '';
|
|
43
|
+
if (!VERSION_RE.test(value)) {
|
|
44
|
+
throw new Error(`--since requires a version like v1.2.3\n${usage()}`);
|
|
45
|
+
}
|
|
46
|
+
opts.since = value;
|
|
28
47
|
} else if (arg === '-m' || arg === '--message') {
|
|
29
48
|
opts.notes = argv[++i] ?? '';
|
|
30
49
|
} else if (arg === '-n' || arg === '--dry-run') {
|
|
@@ -34,9 +53,7 @@ function parseArgs(argv) {
|
|
|
34
53
|
} else if (arg === '--no-push') {
|
|
35
54
|
opts.push = false;
|
|
36
55
|
} else {
|
|
37
|
-
throw new Error(
|
|
38
|
-
`Unknown argument: ${arg}\nUsage: docks release [major|minor|patch|vX.Y.Z] [-m "release notes"] [--dry-run] [--no-push]`,
|
|
39
|
-
);
|
|
56
|
+
throw new Error(`Unknown argument: ${arg}\n${usage()}`);
|
|
40
57
|
}
|
|
41
58
|
}
|
|
42
59
|
|
|
@@ -47,11 +64,20 @@ function findLastVersion(cwd) {
|
|
|
47
64
|
const log = gitOrNull(['log', '--pretty=%s'], cwd);
|
|
48
65
|
if (!log) return null;
|
|
49
66
|
for (const subject of log.split('\n')) {
|
|
50
|
-
|
|
67
|
+
const version = parseVersionSubject(subject);
|
|
68
|
+
if (version) return version;
|
|
51
69
|
}
|
|
52
70
|
return null;
|
|
53
71
|
}
|
|
54
72
|
|
|
73
|
+
function findVersionCommit(cwd, version) {
|
|
74
|
+
const escaped = version.replace(/\./g, '\\.');
|
|
75
|
+
return gitOrNull(
|
|
76
|
+
['log', '-E', '-i', '--pretty=%H', '-1', `--grep=^(Release:[[:space:]]*)?${escaped}$`],
|
|
77
|
+
cwd,
|
|
78
|
+
);
|
|
79
|
+
}
|
|
80
|
+
|
|
55
81
|
function bumpVersion(last, bump) {
|
|
56
82
|
const [major, minor, patch] = last.slice(1).split('.').map(Number);
|
|
57
83
|
switch (bump) {
|
|
@@ -64,16 +90,18 @@ function bumpVersion(last, bump) {
|
|
|
64
90
|
}
|
|
65
91
|
}
|
|
66
92
|
|
|
67
|
-
function generateSummary(cwd,
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
93
|
+
function generateSummary(cwd, since) {
|
|
94
|
+
const sinceCommit = since ? findVersionCommit(cwd, since) : null;
|
|
95
|
+
if (since && !sinceCommit) {
|
|
96
|
+
throw new Error(`No commit found for --since ${since} (expected subject "${since}" or "Release: ${since}").`);
|
|
97
|
+
}
|
|
98
|
+
const range = sinceCommit ? `${sinceCommit}..HEAD` : 'HEAD';
|
|
71
99
|
|
|
72
100
|
const log = gitOrNull(['log', range, '--no-merges', '--pretty=%s'], cwd) ?? '';
|
|
73
101
|
const buckets = { features: [], fixes: [], docs: [], chores: [] };
|
|
74
102
|
|
|
75
103
|
for (const subject of log.split('\n')) {
|
|
76
|
-
if (!subject ||
|
|
104
|
+
if (!subject || parseVersionSubject(subject)) continue;
|
|
77
105
|
|
|
78
106
|
const stripped = subject.includes(': ') ? subject.slice(subject.indexOf(': ') + 2) : subject;
|
|
79
107
|
const text = stripped.charAt(0).toUpperCase() + stripped.slice(1);
|
|
@@ -135,7 +163,9 @@ export async function release(argv, cwd = process.cwd()) {
|
|
|
135
163
|
|
|
136
164
|
let notes = opts.notes;
|
|
137
165
|
if (!notes) {
|
|
138
|
-
const
|
|
166
|
+
const since = opts.since || last;
|
|
167
|
+
if (opts.since) console.log(`Summarizing commits since ${opts.since}`);
|
|
168
|
+
const summary = generateSummary(cwd, since);
|
|
139
169
|
notes = await promptNotes(version, summary);
|
|
140
170
|
}
|
|
141
171
|
|