@virmator/publish 14.23.1 → 14.25.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.
- package/dist/publish.d.ts +23 -0
- package/dist/publish.js +81 -28
- package/package.json +9 -9
package/dist/publish.d.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { type SemVer } from 'semver';
|
|
1
2
|
import { type PackageJson } from 'type-fest';
|
|
2
3
|
/** A virmator plugin for publishing a package to npm. */
|
|
3
4
|
export declare const virmatorPublishPlugin: Readonly<Readonly<{
|
|
@@ -43,3 +44,25 @@ export declare function assertValidLicense({ license, isPrivate, displayName, }:
|
|
|
43
44
|
isPrivate: PackageJson['private'];
|
|
44
45
|
displayName: string;
|
|
45
46
|
}): void;
|
|
47
|
+
/** Commit message version tags that bump the published version. */
|
|
48
|
+
export declare enum ChangeMarker {
|
|
49
|
+
Patch = "patch",
|
|
50
|
+
Minor = "minor",
|
|
51
|
+
Major = "major"
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Parses the leading `[tag]` version marker from a commit message. Returns the matching
|
|
55
|
+
* {@link ChangeMarker}, or `undefined` when there is no tag or the tag is an allowed non-bumping one
|
|
56
|
+
* (e.g. `dev`). Throws a `VirmatorNoTraceError` for any tag outside the allowed set so the publish
|
|
57
|
+
* aborts.
|
|
58
|
+
*/
|
|
59
|
+
export declare function parseCommitChangeMarker(commitMessage: string): ChangeMarker | undefined;
|
|
60
|
+
/**
|
|
61
|
+
* The next semver version to publish, derived from the highest-priority bump marker found since the
|
|
62
|
+
* last version (major > minor > patch). Returns `undefined` when no version was found or no bump
|
|
63
|
+
* marker is present, in which case the caller asks for a version manually.
|
|
64
|
+
*/
|
|
65
|
+
export declare function determineNextVersion({ latestVersion, changeMarkers, }: {
|
|
66
|
+
latestVersion: SemVer | undefined;
|
|
67
|
+
changeMarkers: Readonly<Record<ChangeMarker, number>>;
|
|
68
|
+
}): string | undefined;
|
package/dist/publish.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { assert, check } from '@augment-vir/assert';
|
|
2
|
-
import { awaitedBlockingMap,
|
|
2
|
+
import { awaitedBlockingMap, getObjectTypedValues, safeMatch, wrapInTry, } from '@augment-vir/common';
|
|
3
3
|
import { askQuestionUntilConditionMet, readPackageJson, runShellCommand as runHiddenShellCommand, runShellCommand, } from '@augment-vir/node';
|
|
4
4
|
import { defineVirmatorPlugin, parseTsConfig, VirmatorNoTraceError, } from '@virmator/core';
|
|
5
5
|
import mri from 'mri';
|
|
@@ -80,23 +80,26 @@ export const virmatorPublishPlugin = defineVirmatorPlugin(import.meta.dirname, {
|
|
|
80
80
|
return packageJson;
|
|
81
81
|
}));
|
|
82
82
|
const git = simpleGit(monoRepoRootPath);
|
|
83
|
+
/**
|
|
84
|
+
* Always read the version tags on commits since the last release so a disallowed tag (e.g.
|
|
85
|
+
* `[wip]`) aborts the publish, even when the current version needs no bump.
|
|
86
|
+
*/
|
|
87
|
+
const { latestVersion, changeMarkers } = await findChangeMarkersSinceVersion(git);
|
|
83
88
|
if (await isVersionPublished(version, [
|
|
84
89
|
cwdValidPackageJson,
|
|
85
90
|
...monoRepoPackageJsonFiles,
|
|
86
91
|
])) {
|
|
87
|
-
let nextVersion;
|
|
88
|
-
try {
|
|
89
|
-
nextVersion = await determineNextVersion(git);
|
|
90
|
-
}
|
|
91
|
-
catch (error) {
|
|
92
|
-
log.faint(extractErrorMessage(error));
|
|
93
|
-
}
|
|
94
92
|
const allPackageJsonFiles = [
|
|
95
93
|
cwdValidPackageJson,
|
|
96
94
|
...monoRepoPackageJsonFiles,
|
|
97
95
|
];
|
|
98
|
-
|
|
99
|
-
|
|
96
|
+
const autoNextVersion = determineNextVersion({
|
|
97
|
+
latestVersion,
|
|
98
|
+
changeMarkers,
|
|
99
|
+
});
|
|
100
|
+
const nextVersion = autoNextVersion && !(await isVersionPublished(autoNextVersion, allPackageJsonFiles))
|
|
101
|
+
? autoNextVersion
|
|
102
|
+
: await askQuestionUntilConditionMet({
|
|
100
103
|
async verifyResponseCallback(response) {
|
|
101
104
|
const version = semver.coerce(response)?.raw;
|
|
102
105
|
if (!version) {
|
|
@@ -107,7 +110,6 @@ export const virmatorPublishPlugin = defineVirmatorPlugin(import.meta.dirname, {
|
|
|
107
110
|
invalidInputMessage: 'Invalid semver version.',
|
|
108
111
|
questionToAsk: 'Failed to automatically determine next publish version. Please enter one:',
|
|
109
112
|
});
|
|
110
|
-
}
|
|
111
113
|
log.info(`Publishing version ${nextVersion}...`);
|
|
112
114
|
await updateVersions(nextVersion, monoRepoRootPath, monoRepoPackages, log);
|
|
113
115
|
await runHiddenShellCommand('npm i');
|
|
@@ -248,12 +250,38 @@ async function isPublished({ name, version }) {
|
|
|
248
250
|
return output.exitCode === 0;
|
|
249
251
|
}
|
|
250
252
|
const gitCommitFormatDelimiter = '<**..**>';
|
|
251
|
-
|
|
253
|
+
/** Commit message version tags that bump the published version. */
|
|
254
|
+
export var ChangeMarker;
|
|
252
255
|
(function (ChangeMarker) {
|
|
253
256
|
ChangeMarker["Patch"] = "patch";
|
|
254
257
|
ChangeMarker["Minor"] = "minor";
|
|
255
258
|
ChangeMarker["Major"] = "major";
|
|
256
259
|
})(ChangeMarker || (ChangeMarker = {}));
|
|
260
|
+
/**
|
|
261
|
+
* Every commit-message version tag `virmator publish` accepts. The {@link ChangeMarker} values each
|
|
262
|
+
* bump their respective semver part; `dev` is allowed but does not bump the version. Any other tag
|
|
263
|
+
* (e.g. `wip`) aborts the publish.
|
|
264
|
+
*/
|
|
265
|
+
const allowedVersionTags = [
|
|
266
|
+
...getObjectTypedValues(ChangeMarker),
|
|
267
|
+
'dev',
|
|
268
|
+
];
|
|
269
|
+
/**
|
|
270
|
+
* Parses the leading `[tag]` version marker from a commit message. Returns the matching
|
|
271
|
+
* {@link ChangeMarker}, or `undefined` when there is no tag or the tag is an allowed non-bumping one
|
|
272
|
+
* (e.g. `dev`). Throws a `VirmatorNoTraceError` for any tag outside the allowed set so the publish
|
|
273
|
+
* aborts.
|
|
274
|
+
*/
|
|
275
|
+
export function parseCommitChangeMarker(commitMessage) {
|
|
276
|
+
const [, rawChangeMarker,] = safeMatch(commitMessage.trim(), /^\[([^\]]+)]/);
|
|
277
|
+
if (!rawChangeMarker) {
|
|
278
|
+
return undefined;
|
|
279
|
+
}
|
|
280
|
+
else if (!allowedVersionTags.includes(rawChangeMarker)) {
|
|
281
|
+
throw new VirmatorNoTraceError(`${rawChangeMarker} version tag not allowed`);
|
|
282
|
+
}
|
|
283
|
+
return check.isEnumValue(rawChangeMarker, ChangeMarker) ? rawChangeMarker : undefined;
|
|
284
|
+
}
|
|
257
285
|
async function getGitCommitVersion(decrement, git) {
|
|
258
286
|
const output = await git.raw(`show HEAD~${decrement} --pretty='%d${gitCommitFormatDelimiter}%s' -s`.split(' '));
|
|
259
287
|
const [maybeTag, message,] = output.split(gitCommitFormatDelimiter);
|
|
@@ -269,16 +297,19 @@ async function getGitCommitVersion(decrement, git) {
|
|
|
269
297
|
.filter(check.isTruthy);
|
|
270
298
|
const sortedVersionTags = semver.sort(versionTags);
|
|
271
299
|
const latestVersionTag = sortedVersionTags.slice(-1)[0];
|
|
272
|
-
const [, rawChangeMarker,] = message ? safeMatch(message.trim(), /^\[([^\]]+)]/) : [];
|
|
273
|
-
const changeMarker = rawChangeMarker && check.isEnumValue(rawChangeMarker, ChangeMarker)
|
|
274
|
-
? rawChangeMarker
|
|
275
|
-
: undefined;
|
|
276
300
|
return {
|
|
277
301
|
version: latestVersionTag,
|
|
278
|
-
changeMarker,
|
|
302
|
+
changeMarker: message ? parseCommitChangeMarker(message) : undefined,
|
|
279
303
|
};
|
|
280
304
|
}
|
|
281
|
-
|
|
305
|
+
const maxCommitLookBack = 100;
|
|
306
|
+
/**
|
|
307
|
+
* Walks backward from HEAD until the most recent version git-tag (or `maxCommitLookBack` commits /
|
|
308
|
+
* the start of history), tallying the bump markers found on commits since that version. Reading
|
|
309
|
+
* each commit validates its version tag, so a disallowed tag (e.g. `[wip]`) aborts here — even when
|
|
310
|
+
* the current version needs no bump.
|
|
311
|
+
*/
|
|
312
|
+
async function findChangeMarkersSinceVersion(git) {
|
|
282
313
|
const changeMarkers = {
|
|
283
314
|
[ChangeMarker.Patch]: 0,
|
|
284
315
|
[ChangeMarker.Minor]: 0,
|
|
@@ -286,20 +317,42 @@ async function determineNextVersion(git) {
|
|
|
286
317
|
};
|
|
287
318
|
let decrement = 0;
|
|
288
319
|
let latestVersion = undefined;
|
|
289
|
-
while (!latestVersion) {
|
|
290
|
-
|
|
291
|
-
|
|
320
|
+
while (!latestVersion && decrement <= maxCommitLookBack) {
|
|
321
|
+
const commitVersion = await wrapInTry(() => getGitCommitVersion(decrement, git), {
|
|
322
|
+
handleError(error) {
|
|
323
|
+
/** A disallowed version tag must abort; any other git error just ends the walk. */
|
|
324
|
+
if (error instanceof VirmatorNoTraceError) {
|
|
325
|
+
throw error;
|
|
326
|
+
}
|
|
327
|
+
return undefined;
|
|
328
|
+
},
|
|
329
|
+
});
|
|
330
|
+
if (!commitVersion) {
|
|
331
|
+
break;
|
|
292
332
|
}
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
latestVersion = version;
|
|
333
|
+
else if (commitVersion.version) {
|
|
334
|
+
latestVersion = commitVersion.version;
|
|
296
335
|
}
|
|
297
|
-
else if (changeMarker) {
|
|
298
|
-
changeMarkers[changeMarker]++;
|
|
336
|
+
else if (commitVersion.changeMarker) {
|
|
337
|
+
changeMarkers[commitVersion.changeMarker]++;
|
|
299
338
|
}
|
|
300
339
|
decrement++;
|
|
301
340
|
}
|
|
302
|
-
|
|
341
|
+
return {
|
|
342
|
+
latestVersion,
|
|
343
|
+
changeMarkers,
|
|
344
|
+
};
|
|
345
|
+
}
|
|
346
|
+
/**
|
|
347
|
+
* The next semver version to publish, derived from the highest-priority bump marker found since the
|
|
348
|
+
* last version (major > minor > patch). Returns `undefined` when no version was found or no bump
|
|
349
|
+
* marker is present, in which case the caller asks for a version manually.
|
|
350
|
+
*/
|
|
351
|
+
export function determineNextVersion({ latestVersion, changeMarkers, }) {
|
|
352
|
+
if (!latestVersion) {
|
|
353
|
+
return undefined;
|
|
354
|
+
}
|
|
355
|
+
else if (changeMarkers[ChangeMarker.Major]) {
|
|
303
356
|
return latestVersion.inc('major').raw;
|
|
304
357
|
}
|
|
305
358
|
else if (changeMarkers[ChangeMarker.Minor]) {
|
|
@@ -309,7 +362,7 @@ async function determineNextVersion(git) {
|
|
|
309
362
|
return latestVersion.inc('patch').raw;
|
|
310
363
|
}
|
|
311
364
|
else {
|
|
312
|
-
|
|
365
|
+
return undefined;
|
|
313
366
|
}
|
|
314
367
|
}
|
|
315
368
|
async function updateVersions(version, monoRepoRootPath, monoPackages, log) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@virmator/publish",
|
|
3
|
-
"version": "14.
|
|
3
|
+
"version": "14.25.0",
|
|
4
4
|
"description": "Default publish plugin for virmator.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"virmator",
|
|
@@ -34,22 +34,22 @@
|
|
|
34
34
|
"test:update": "npm test"
|
|
35
35
|
},
|
|
36
36
|
"dependencies": {
|
|
37
|
-
"@augment-vir/assert": "^31.
|
|
38
|
-
"@augment-vir/common": "^31.
|
|
39
|
-
"@augment-vir/node": "^31.
|
|
40
|
-
"@virmator/core": "^14.
|
|
37
|
+
"@augment-vir/assert": "^31.72.1",
|
|
38
|
+
"@augment-vir/common": "^31.72.1",
|
|
39
|
+
"@augment-vir/node": "^31.72.1",
|
|
40
|
+
"@virmator/core": "^14.25.0",
|
|
41
41
|
"mri": "^1.2.0",
|
|
42
|
-
"semver": "^7.8.
|
|
42
|
+
"semver": "^7.8.3",
|
|
43
43
|
"simple-git": "^3.36.0",
|
|
44
44
|
"spdx-vir": "^0.0.1",
|
|
45
45
|
"url-vir": "^2.1.9"
|
|
46
46
|
},
|
|
47
47
|
"devDependencies": {
|
|
48
|
-
"@augment-vir/test": "^31.
|
|
49
|
-
"@types/node": "^25.9.
|
|
48
|
+
"@augment-vir/test": "^31.72.1",
|
|
49
|
+
"@types/node": "^25.9.2",
|
|
50
50
|
"@types/semver": "^7.7.1",
|
|
51
51
|
"markdown-code-example-inserter": "^3.0.5",
|
|
52
|
-
"type-fest": "^5.
|
|
52
|
+
"type-fest": "^5.7.0",
|
|
53
53
|
"typedoc": "^0.28.19"
|
|
54
54
|
},
|
|
55
55
|
"engines": {
|