@releasekit/version 0.2.0-next.1 → 0.2.0-next.10
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/{chunk-3JG7UWIT.js → chunk-DXDB5P7S.js} +117 -43
- package/dist/chunk-LMPZV35Z.js +20 -0
- package/dist/cli.cjs +146 -41
- package/dist/cli.js +2 -1
- package/dist/commandExecutor-E44ID5U4.js +8 -0
- package/dist/index.cjs +151 -43
- package/dist/index.d.cts +2 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +2 -1
- package/package.json +1 -1
|
@@ -1,6 +1,10 @@
|
|
|
1
1
|
import {
|
|
2
2
|
BaseVersionError
|
|
3
3
|
} from "./chunk-GQLJ7JQY.js";
|
|
4
|
+
import {
|
|
5
|
+
execAsync,
|
|
6
|
+
execSync
|
|
7
|
+
} from "./chunk-LMPZV35Z.js";
|
|
4
8
|
|
|
5
9
|
// src/config.ts
|
|
6
10
|
import { loadVersionConfig } from "@releasekit/config";
|
|
@@ -202,24 +206,6 @@ import semver3 from "semver";
|
|
|
202
206
|
// src/git/repository.ts
|
|
203
207
|
import { existsSync, statSync } from "fs";
|
|
204
208
|
import { join } from "path";
|
|
205
|
-
|
|
206
|
-
// src/git/commandExecutor.ts
|
|
207
|
-
import { execFile, execFileSync } from "child_process";
|
|
208
|
-
var execAsync = (file, args, options) => {
|
|
209
|
-
const defaultOptions = { maxBuffer: 1024 * 1024 * 10, ...options };
|
|
210
|
-
return new Promise((resolve2, reject) => {
|
|
211
|
-
execFile(file, args, defaultOptions, (error, stdout, stderr) => {
|
|
212
|
-
if (error) {
|
|
213
|
-
reject(error);
|
|
214
|
-
} else {
|
|
215
|
-
resolve2({ stdout: stdout.toString(), stderr: stderr.toString() });
|
|
216
|
-
}
|
|
217
|
-
});
|
|
218
|
-
});
|
|
219
|
-
};
|
|
220
|
-
var execSync = (file, args, options) => execFileSync(file, args, { maxBuffer: 1024 * 1024 * 10, ...options });
|
|
221
|
-
|
|
222
|
-
// src/git/repository.ts
|
|
223
209
|
function isGitRepository(directory) {
|
|
224
210
|
const gitDir = join(directory, ".git");
|
|
225
211
|
if (!existsSync(gitDir)) {
|
|
@@ -374,28 +360,37 @@ async function getLatestTagForPackage(packageName, versionPrefix, options) {
|
|
|
374
360
|
`Looking for tags for package ${packageName} with prefix ${versionPrefix || "none"}, packageSpecificTags: ${packageSpecificTags}`,
|
|
375
361
|
"debug"
|
|
376
362
|
);
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
363
|
+
let allTags = [];
|
|
364
|
+
try {
|
|
365
|
+
const { execSync: execSync2 } = await import("./commandExecutor-E44ID5U4.js");
|
|
366
|
+
const tagsOutput = execSync2("git", ["tag", "-l"], { cwd: process.cwd() });
|
|
367
|
+
allTags = tagsOutput.toString().trim().split("\n").filter((tag) => tag.length > 0);
|
|
368
|
+
} catch (err) {
|
|
369
|
+
log(`Error getting tags: ${err instanceof Error ? err.message : String(err)}`, "error");
|
|
370
|
+
}
|
|
371
|
+
log(`Retrieved ${allTags.length} tags`, "debug");
|
|
381
372
|
if (packageSpecificTags) {
|
|
382
373
|
const packageTagPattern = escapeRegExp(tagTemplate).replace(/\\\$\\\{packageName\\\}/g, `(?:${escapedPackageName})`).replace(/\\\$\\\{prefix\\\}/g, `(?:${escapedPrefix})`).replace(/\\\$\\\{version\\\}/g, "(?:[0-9]+\\.[0-9]+\\.[0-9]+(?:-[a-zA-Z0-9.-]+)?)");
|
|
383
374
|
log(`Using package tag pattern: ${packageTagPattern}`, "debug");
|
|
384
375
|
const packageTagRegex = new RegExp(`^${packageTagPattern}$`);
|
|
385
376
|
let packageTags = allTags.filter((tag) => packageTagRegex.test(tag));
|
|
377
|
+
log(`Found ${packageTags.length} matching tags for ${packageName}`, "debug");
|
|
386
378
|
if (packageTags.length > 0) {
|
|
387
379
|
const chronologicalFirst = packageTags[0];
|
|
380
|
+
void chronologicalFirst;
|
|
388
381
|
const sortedPackageTags2 = [...packageTags].sort((a, b) => {
|
|
389
382
|
let versionA = "";
|
|
390
383
|
let versionB = "";
|
|
391
384
|
if (a.includes("@")) {
|
|
392
|
-
const
|
|
385
|
+
const parts = a.split("@");
|
|
386
|
+
const afterAt = parts[parts.length - 1] || "";
|
|
393
387
|
versionA = afterAt.replace(new RegExp(`^${escapeRegExp(versionPrefix || "")}`), "");
|
|
394
388
|
} else {
|
|
395
389
|
versionA = a.replace(new RegExp(`^${escapeRegExp(packageName)}`), "").replace(new RegExp(`^${escapeRegExp(versionPrefix || "")}`), "");
|
|
396
390
|
}
|
|
397
391
|
if (b.includes("@")) {
|
|
398
|
-
const
|
|
392
|
+
const parts = b.split("@");
|
|
393
|
+
const afterAtB = parts[parts.length - 1] || "";
|
|
399
394
|
versionB = afterAtB.replace(new RegExp(`^${escapeRegExp(versionPrefix || "")}`), "");
|
|
400
395
|
} else {
|
|
401
396
|
versionB = b.replace(new RegExp(`^${escapeRegExp(packageName)}`), "").replace(new RegExp(`^${escapeRegExp(versionPrefix || "")}`), "");
|
|
@@ -406,12 +401,6 @@ async function getLatestTagForPackage(packageName, versionPrefix, options) {
|
|
|
406
401
|
});
|
|
407
402
|
log(`Found ${packageTags.length} package tags using configured pattern`, "debug");
|
|
408
403
|
log(`Using semantically latest tag: ${sortedPackageTags2[0]}`, "debug");
|
|
409
|
-
if (sortedPackageTags2[0] !== chronologicalFirst) {
|
|
410
|
-
log(
|
|
411
|
-
`Package tag ordering differs: chronological first is ${chronologicalFirst}, semantic latest is ${sortedPackageTags2[0]}`,
|
|
412
|
-
"debug"
|
|
413
|
-
);
|
|
414
|
-
}
|
|
415
404
|
return sortedPackageTags2[0];
|
|
416
405
|
}
|
|
417
406
|
if (versionPrefix) {
|
|
@@ -419,9 +408,11 @@ async function getLatestTagForPackage(packageName, versionPrefix, options) {
|
|
|
419
408
|
packageTags = allTags.filter((tag) => pattern1.test(tag));
|
|
420
409
|
if (packageTags.length > 0) {
|
|
421
410
|
const sortedPackageTags2 = [...packageTags].sort((a, b) => {
|
|
422
|
-
const
|
|
411
|
+
const aParts = a.split("@");
|
|
412
|
+
const afterAt = aParts[aParts.length - 1] || "";
|
|
423
413
|
const versionA = afterAt.replace(new RegExp(`^${escapeRegExp(versionPrefix || "")}`), "");
|
|
424
|
-
const
|
|
414
|
+
const bParts = b.split("@");
|
|
415
|
+
const afterAtB = bParts[bParts.length - 1] || "";
|
|
425
416
|
const versionB = afterAtB.replace(new RegExp(`^${escapeRegExp(versionPrefix || "")}`), "");
|
|
426
417
|
const cleanVersionA = semver.clean(versionA) || "0.0.0";
|
|
427
418
|
const cleanVersionB = semver.clean(versionB) || "0.0.0";
|
|
@@ -437,8 +428,10 @@ async function getLatestTagForPackage(packageName, versionPrefix, options) {
|
|
|
437
428
|
packageTags = allTags.filter((tag) => pattern2.test(tag));
|
|
438
429
|
if (packageTags.length > 0) {
|
|
439
430
|
const sortedPackageTags2 = [...packageTags].sort((a, b) => {
|
|
440
|
-
const
|
|
441
|
-
const
|
|
431
|
+
const aParts = a.split("@");
|
|
432
|
+
const versionA = semver.clean(aParts[aParts.length - 1] || "") || "0.0.0";
|
|
433
|
+
const bParts = b.split("@");
|
|
434
|
+
const versionB = semver.clean(bParts[bParts.length - 1] || "") || "0.0.0";
|
|
442
435
|
return semver.rcompare(versionA, versionB);
|
|
443
436
|
});
|
|
444
437
|
log(`Found ${packageTags.length} package tags using pattern: ${versionPrefix}packageName@...`, "debug");
|
|
@@ -458,8 +451,10 @@ async function getLatestTagForPackage(packageName, versionPrefix, options) {
|
|
|
458
451
|
return "";
|
|
459
452
|
}
|
|
460
453
|
const sortedPackageTags = [...packageTags].sort((a, b) => {
|
|
461
|
-
const
|
|
462
|
-
const
|
|
454
|
+
const aParts = a.split("@");
|
|
455
|
+
const versionA = semver.clean(aParts[aParts.length - 1] || "") || "0.0.0";
|
|
456
|
+
const bParts = b.split("@");
|
|
457
|
+
const versionB = semver.clean(bParts[bParts.length - 1] || "") || "0.0.0";
|
|
463
458
|
return semver.rcompare(versionA, versionB);
|
|
464
459
|
});
|
|
465
460
|
log(`Found ${packageTags.length} package tags for ${packageName}`, "debug");
|
|
@@ -698,12 +693,17 @@ var VersionMismatchError = class extends Error {
|
|
|
698
693
|
this.name = "VersionMismatchError";
|
|
699
694
|
}
|
|
700
695
|
};
|
|
701
|
-
async function getBestVersionSource(tagName, packageVersion, cwd4, mismatchStrategy = "error") {
|
|
696
|
+
async function getBestVersionSource(tagName, packageVersion, cwd4, mismatchStrategy = "error", strictReachable = false) {
|
|
702
697
|
if (!tagName?.trim()) {
|
|
703
698
|
return packageVersion ? { source: "package", version: packageVersion, reason: "No git tag provided" } : { source: "initial", version: "0.1.0", reason: "No git tag or package version available" };
|
|
704
699
|
}
|
|
705
700
|
const verification = verifyTag(tagName, cwd4);
|
|
706
701
|
if (!verification.exists || !verification.reachable) {
|
|
702
|
+
if (strictReachable) {
|
|
703
|
+
throw new Error(
|
|
704
|
+
`Git tag '${tagName}' is not reachable from the current commit. The tag exists but cannot be reached from HEAD, which usually means you're on a different branch or the tag is orphaned. To allow fallback to package version, set strictReachable to false in your configuration.`
|
|
705
|
+
);
|
|
706
|
+
}
|
|
707
707
|
if (packageVersion) {
|
|
708
708
|
log(
|
|
709
709
|
`Git tag '${tagName}' unreachable (${verification.error}), using package version: ${packageVersion}`,
|
|
@@ -809,7 +809,8 @@ async function calculateVersion(config, options) {
|
|
|
809
809
|
prereleaseIdentifier: configPrereleaseIdentifier,
|
|
810
810
|
branchPattern,
|
|
811
811
|
baseBranch,
|
|
812
|
-
mismatchStrategy
|
|
812
|
+
mismatchStrategy,
|
|
813
|
+
strictReachable
|
|
813
814
|
} = config;
|
|
814
815
|
const {
|
|
815
816
|
latestTag,
|
|
@@ -854,7 +855,13 @@ async function calculateVersion(config, options) {
|
|
|
854
855
|
const packageDir = pkgPath || cwd();
|
|
855
856
|
const manifestResult = getVersionFromManifests(packageDir);
|
|
856
857
|
const packageVersion = manifestResult.manifestFound && manifestResult.version ? manifestResult.version : void 0;
|
|
857
|
-
versionSource = await getBestVersionSource(
|
|
858
|
+
versionSource = await getBestVersionSource(
|
|
859
|
+
latestTag,
|
|
860
|
+
packageVersion,
|
|
861
|
+
packageDir,
|
|
862
|
+
mismatchStrategy,
|
|
863
|
+
strictReachable
|
|
864
|
+
);
|
|
858
865
|
log(`Using version source: ${versionSource.source} (${versionSource.reason})`, "info");
|
|
859
866
|
}
|
|
860
867
|
const specifiedType = type;
|
|
@@ -962,12 +969,56 @@ import { exit } from "process";
|
|
|
962
969
|
// src/changelog/commitParser.ts
|
|
963
970
|
var CONVENTIONAL_COMMIT_REGEX = /^(\w+)(?:\(([^)]+)\))?(!)?: (.+)(?:\n\n([\s\S]*))?/;
|
|
964
971
|
var BREAKING_CHANGE_REGEX = /BREAKING CHANGE: ([\s\S]+?)(?:\n\n|$)/;
|
|
972
|
+
function extractChangelogEntriesWithHash(projectDir, revisionRange) {
|
|
973
|
+
try {
|
|
974
|
+
const args = ["log", revisionRange, "--pretty=format:%H|||%B---COMMIT_DELIMITER---", "--no-merges", "--", "."];
|
|
975
|
+
const output = execSync("git", args, { cwd: projectDir, encoding: "utf8" }).toString();
|
|
976
|
+
const commits = output.split("---COMMIT_DELIMITER---").filter((commit) => commit.trim() !== "");
|
|
977
|
+
return commits.map((commit) => {
|
|
978
|
+
const [hash, ...messageParts] = commit.split("|||");
|
|
979
|
+
const message = messageParts.join("|||").trim();
|
|
980
|
+
const entry = parseCommitMessage(message);
|
|
981
|
+
if (entry && hash) {
|
|
982
|
+
return { hash: hash.trim(), entry };
|
|
983
|
+
}
|
|
984
|
+
return null;
|
|
985
|
+
}).filter((item) => item !== null);
|
|
986
|
+
} catch (error) {
|
|
987
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
988
|
+
log(`Error extracting commits with hash: ${errorMessage}`, "error");
|
|
989
|
+
return [];
|
|
990
|
+
}
|
|
991
|
+
}
|
|
992
|
+
function extractAllChangelogEntriesWithHash(projectDir, revisionRange) {
|
|
993
|
+
try {
|
|
994
|
+
const args = ["log", revisionRange, "--pretty=format:%H|||%B---COMMIT_DELIMITER---", "--no-merges"];
|
|
995
|
+
const output = execSync("git", args, { cwd: projectDir, encoding: "utf8" }).toString();
|
|
996
|
+
const commits = output.split("---COMMIT_DELIMITER---").filter((commit) => commit.trim() !== "");
|
|
997
|
+
return commits.map((commit) => {
|
|
998
|
+
const [hash, ...messageParts] = commit.split("|||");
|
|
999
|
+
const message = messageParts.join("|||").trim();
|
|
1000
|
+
const entry = parseCommitMessage(message);
|
|
1001
|
+
if (entry && hash) {
|
|
1002
|
+
return { hash: hash.trim(), entry };
|
|
1003
|
+
}
|
|
1004
|
+
return null;
|
|
1005
|
+
}).filter((item) => item !== null);
|
|
1006
|
+
} catch (error) {
|
|
1007
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
1008
|
+
log(`Error extracting all commits with hash: ${errorMessage}`, "error");
|
|
1009
|
+
return [];
|
|
1010
|
+
}
|
|
1011
|
+
}
|
|
965
1012
|
function extractChangelogEntriesFromCommits(projectDir, revisionRange) {
|
|
1013
|
+
return extractCommitsFromGitLog(projectDir, revisionRange, true);
|
|
1014
|
+
}
|
|
1015
|
+
function extractCommitsFromGitLog(projectDir, revisionRange, filterToPath) {
|
|
966
1016
|
try {
|
|
967
|
-
const
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
}
|
|
1017
|
+
const args = ["log", revisionRange, "--pretty=format:%B---COMMIT_DELIMITER---", "--no-merges"];
|
|
1018
|
+
if (filterToPath) {
|
|
1019
|
+
args.push("--", ".");
|
|
1020
|
+
}
|
|
1021
|
+
const output = execSync("git", args, { cwd: projectDir, encoding: "utf8" }).toString();
|
|
971
1022
|
const commits = output.split("---COMMIT_DELIMITER---").filter((commit) => commit.trim() !== "");
|
|
972
1023
|
return commits.map((commit) => parseCommitMessage(commit)).filter((entry) => entry !== null);
|
|
973
1024
|
} catch (error) {
|
|
@@ -1395,6 +1446,11 @@ var PackageProcessor = class {
|
|
|
1395
1446
|
if (verification.exists && verification.reachable) {
|
|
1396
1447
|
revisionRange = `${latestTag}..HEAD`;
|
|
1397
1448
|
} else {
|
|
1449
|
+
if (this.config.strictReachable) {
|
|
1450
|
+
throw new Error(
|
|
1451
|
+
`Cannot generate changelog: tag '${latestTag}' is not reachable from the current commit. When strictReachable is enabled, all tags must be reachable. To allow fallback to all commits, set strictReachable to false.`
|
|
1452
|
+
);
|
|
1453
|
+
}
|
|
1398
1454
|
log(`Tag ${latestTag} is unreachable (${verification.error}), using all commits for changelog`, "debug");
|
|
1399
1455
|
revisionRange = "HEAD";
|
|
1400
1456
|
}
|
|
@@ -1402,6 +1458,14 @@ var PackageProcessor = class {
|
|
|
1402
1458
|
revisionRange = "HEAD";
|
|
1403
1459
|
}
|
|
1404
1460
|
changelogEntries = extractChangelogEntriesFromCommits(pkgPath, revisionRange);
|
|
1461
|
+
const allCommitsWithHash = extractAllChangelogEntriesWithHash(pkgPath, revisionRange);
|
|
1462
|
+
const packageCommitsWithHash = extractChangelogEntriesWithHash(pkgPath, revisionRange);
|
|
1463
|
+
const packageCommitHashes = new Set(packageCommitsWithHash.map((c) => c.hash));
|
|
1464
|
+
const globalCommits = allCommitsWithHash.filter((c) => !packageCommitHashes.has(c.hash)).map((c) => c.entry);
|
|
1465
|
+
if (globalCommits.length > 0) {
|
|
1466
|
+
log(`Adding ${globalCommits.length} global commit(s) to ${name} changelog`, "debug");
|
|
1467
|
+
changelogEntries = [...globalCommits, ...changelogEntries];
|
|
1468
|
+
}
|
|
1405
1469
|
if (changelogEntries.length === 0) {
|
|
1406
1470
|
changelogEntries = [
|
|
1407
1471
|
{
|
|
@@ -1712,6 +1776,11 @@ function createSyncStrategy(config) {
|
|
|
1712
1776
|
});
|
|
1713
1777
|
revisionRange = `${latestTag}..HEAD`;
|
|
1714
1778
|
} catch {
|
|
1779
|
+
if (config.strictReachable) {
|
|
1780
|
+
throw new Error(
|
|
1781
|
+
`Cannot generate changelog: tag '${latestTag}' is not reachable from the current commit. When strictReachable is enabled, all tags must be reachable. To allow fallback to all commits, set strictReachable to false.`
|
|
1782
|
+
);
|
|
1783
|
+
}
|
|
1715
1784
|
log(`Tag ${latestTag} doesn't exist, using all commits for changelog`, "debug");
|
|
1716
1785
|
revisionRange = "HEAD";
|
|
1717
1786
|
}
|
|
@@ -1831,6 +1900,11 @@ function createSingleStrategy(config) {
|
|
|
1831
1900
|
});
|
|
1832
1901
|
revisionRange = `${latestTag}..HEAD`;
|
|
1833
1902
|
} catch {
|
|
1903
|
+
if (config.strictReachable) {
|
|
1904
|
+
throw new Error(
|
|
1905
|
+
`Cannot generate changelog: tag '${latestTag}' is not reachable from the current commit. When strictReachable is enabled, all tags must be reachable. To allow fallback to all commits, set strictReachable to false.`
|
|
1906
|
+
);
|
|
1907
|
+
}
|
|
1834
1908
|
log(`Tag ${latestTag} doesn't exist, using all commits for changelog`, "debug");
|
|
1835
1909
|
revisionRange = "HEAD";
|
|
1836
1910
|
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
// src/git/commandExecutor.ts
|
|
2
|
+
import { execFile, execFileSync } from "child_process";
|
|
3
|
+
var execAsync = (file, args, options) => {
|
|
4
|
+
const defaultOptions = { maxBuffer: 1024 * 1024 * 10, ...options };
|
|
5
|
+
return new Promise((resolve, reject) => {
|
|
6
|
+
execFile(file, args, defaultOptions, (error, stdout, stderr) => {
|
|
7
|
+
if (error) {
|
|
8
|
+
reject(error);
|
|
9
|
+
} else {
|
|
10
|
+
resolve({ stdout: stdout.toString(), stderr: stderr.toString() });
|
|
11
|
+
}
|
|
12
|
+
});
|
|
13
|
+
});
|
|
14
|
+
};
|
|
15
|
+
var execSync = (file, args, options) => execFileSync(file, args, { maxBuffer: 1024 * 1024 * 10, ...options });
|
|
16
|
+
|
|
17
|
+
export {
|
|
18
|
+
execAsync,
|
|
19
|
+
execSync
|
|
20
|
+
};
|
package/dist/cli.cjs
CHANGED
|
@@ -57,6 +57,33 @@ var init_baseError = __esm({
|
|
|
57
57
|
}
|
|
58
58
|
});
|
|
59
59
|
|
|
60
|
+
// src/git/commandExecutor.ts
|
|
61
|
+
var commandExecutor_exports = {};
|
|
62
|
+
__export(commandExecutor_exports, {
|
|
63
|
+
execAsync: () => execAsync,
|
|
64
|
+
execSync: () => execSync
|
|
65
|
+
});
|
|
66
|
+
var import_node_child_process, execAsync, execSync;
|
|
67
|
+
var init_commandExecutor = __esm({
|
|
68
|
+
"src/git/commandExecutor.ts"() {
|
|
69
|
+
"use strict";
|
|
70
|
+
import_node_child_process = require("child_process");
|
|
71
|
+
execAsync = (file, args, options) => {
|
|
72
|
+
const defaultOptions = { maxBuffer: 1024 * 1024 * 10, ...options };
|
|
73
|
+
return new Promise((resolve2, reject) => {
|
|
74
|
+
(0, import_node_child_process.execFile)(file, args, defaultOptions, (error, stdout, stderr) => {
|
|
75
|
+
if (error) {
|
|
76
|
+
reject(error);
|
|
77
|
+
} else {
|
|
78
|
+
resolve2({ stdout: stdout.toString(), stderr: stderr.toString() });
|
|
79
|
+
}
|
|
80
|
+
});
|
|
81
|
+
});
|
|
82
|
+
};
|
|
83
|
+
execSync = (file, args, options) => (0, import_node_child_process.execFileSync)(file, args, { maxBuffer: 1024 * 1024 * 10, ...options });
|
|
84
|
+
}
|
|
85
|
+
});
|
|
86
|
+
|
|
60
87
|
// src/cli.ts
|
|
61
88
|
var cli_exports = {};
|
|
62
89
|
__export(cli_exports, {
|
|
@@ -370,31 +397,60 @@ function matchesPackageNamePattern(packageName, pattern) {
|
|
|
370
397
|
var import_node_fs6 = __toESM(require("fs"), 1);
|
|
371
398
|
var path6 = __toESM(require("path"), 1);
|
|
372
399
|
|
|
373
|
-
// src/git/commandExecutor.ts
|
|
374
|
-
var import_node_child_process = require("child_process");
|
|
375
|
-
var execAsync = (file, args, options) => {
|
|
376
|
-
const defaultOptions = { maxBuffer: 1024 * 1024 * 10, ...options };
|
|
377
|
-
return new Promise((resolve2, reject) => {
|
|
378
|
-
(0, import_node_child_process.execFile)(file, args, defaultOptions, (error, stdout, stderr) => {
|
|
379
|
-
if (error) {
|
|
380
|
-
reject(error);
|
|
381
|
-
} else {
|
|
382
|
-
resolve2({ stdout: stdout.toString(), stderr: stderr.toString() });
|
|
383
|
-
}
|
|
384
|
-
});
|
|
385
|
-
});
|
|
386
|
-
};
|
|
387
|
-
var execSync = (file, args, options) => (0, import_node_child_process.execFileSync)(file, args, { maxBuffer: 1024 * 1024 * 10, ...options });
|
|
388
|
-
|
|
389
400
|
// src/changelog/commitParser.ts
|
|
401
|
+
init_commandExecutor();
|
|
390
402
|
var CONVENTIONAL_COMMIT_REGEX = /^(\w+)(?:\(([^)]+)\))?(!)?: (.+)(?:\n\n([\s\S]*))?/;
|
|
391
403
|
var BREAKING_CHANGE_REGEX = /BREAKING CHANGE: ([\s\S]+?)(?:\n\n|$)/;
|
|
404
|
+
function extractChangelogEntriesWithHash(projectDir, revisionRange) {
|
|
405
|
+
try {
|
|
406
|
+
const args = ["log", revisionRange, "--pretty=format:%H|||%B---COMMIT_DELIMITER---", "--no-merges", "--", "."];
|
|
407
|
+
const output = execSync("git", args, { cwd: projectDir, encoding: "utf8" }).toString();
|
|
408
|
+
const commits = output.split("---COMMIT_DELIMITER---").filter((commit) => commit.trim() !== "");
|
|
409
|
+
return commits.map((commit) => {
|
|
410
|
+
const [hash, ...messageParts] = commit.split("|||");
|
|
411
|
+
const message = messageParts.join("|||").trim();
|
|
412
|
+
const entry = parseCommitMessage(message);
|
|
413
|
+
if (entry && hash) {
|
|
414
|
+
return { hash: hash.trim(), entry };
|
|
415
|
+
}
|
|
416
|
+
return null;
|
|
417
|
+
}).filter((item) => item !== null);
|
|
418
|
+
} catch (error) {
|
|
419
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
420
|
+
log(`Error extracting commits with hash: ${errorMessage}`, "error");
|
|
421
|
+
return [];
|
|
422
|
+
}
|
|
423
|
+
}
|
|
424
|
+
function extractAllChangelogEntriesWithHash(projectDir, revisionRange) {
|
|
425
|
+
try {
|
|
426
|
+
const args = ["log", revisionRange, "--pretty=format:%H|||%B---COMMIT_DELIMITER---", "--no-merges"];
|
|
427
|
+
const output = execSync("git", args, { cwd: projectDir, encoding: "utf8" }).toString();
|
|
428
|
+
const commits = output.split("---COMMIT_DELIMITER---").filter((commit) => commit.trim() !== "");
|
|
429
|
+
return commits.map((commit) => {
|
|
430
|
+
const [hash, ...messageParts] = commit.split("|||");
|
|
431
|
+
const message = messageParts.join("|||").trim();
|
|
432
|
+
const entry = parseCommitMessage(message);
|
|
433
|
+
if (entry && hash) {
|
|
434
|
+
return { hash: hash.trim(), entry };
|
|
435
|
+
}
|
|
436
|
+
return null;
|
|
437
|
+
}).filter((item) => item !== null);
|
|
438
|
+
} catch (error) {
|
|
439
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
440
|
+
log(`Error extracting all commits with hash: ${errorMessage}`, "error");
|
|
441
|
+
return [];
|
|
442
|
+
}
|
|
443
|
+
}
|
|
392
444
|
function extractChangelogEntriesFromCommits(projectDir, revisionRange) {
|
|
445
|
+
return extractCommitsFromGitLog(projectDir, revisionRange, true);
|
|
446
|
+
}
|
|
447
|
+
function extractCommitsFromGitLog(projectDir, revisionRange, filterToPath) {
|
|
393
448
|
try {
|
|
394
|
-
const
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
}
|
|
449
|
+
const args = ["log", revisionRange, "--pretty=format:%B---COMMIT_DELIMITER---", "--no-merges"];
|
|
450
|
+
if (filterToPath) {
|
|
451
|
+
args.push("--", ".");
|
|
452
|
+
}
|
|
453
|
+
const output = execSync("git", args, { cwd: projectDir, encoding: "utf8" }).toString();
|
|
398
454
|
const commits = output.split("---COMMIT_DELIMITER---").filter((commit) => commit.trim() !== "");
|
|
399
455
|
return commits.map((commit) => parseCommitMessage(commit)).filter((entry) => entry !== null);
|
|
400
456
|
} catch (error) {
|
|
@@ -489,13 +545,16 @@ function extractIssueIds(body) {
|
|
|
489
545
|
|
|
490
546
|
// src/core/versionStrategies.ts
|
|
491
547
|
init_baseError();
|
|
548
|
+
init_commandExecutor();
|
|
492
549
|
|
|
493
550
|
// src/git/commands.ts
|
|
494
551
|
var import_node_process = require("process");
|
|
552
|
+
init_commandExecutor();
|
|
495
553
|
|
|
496
554
|
// src/git/repository.ts
|
|
497
555
|
var import_node_fs = require("fs");
|
|
498
556
|
var import_node_path2 = require("path");
|
|
557
|
+
init_commandExecutor();
|
|
499
558
|
function isGitRepository(directory) {
|
|
500
559
|
const gitDir = (0, import_node_path2.join)(directory, ".git");
|
|
501
560
|
if (!(0, import_node_fs.existsSync)(gitDir)) {
|
|
@@ -700,6 +759,7 @@ To fix this:
|
|
|
700
759
|
}
|
|
701
760
|
|
|
702
761
|
// src/git/tagsAndBranches.ts
|
|
762
|
+
init_commandExecutor();
|
|
703
763
|
function getCommitsLength(pkgRoot, sinceTag) {
|
|
704
764
|
try {
|
|
705
765
|
let amount;
|
|
@@ -777,28 +837,37 @@ async function getLatestTagForPackage(packageName, versionPrefix, options) {
|
|
|
777
837
|
`Looking for tags for package ${packageName} with prefix ${versionPrefix || "none"}, packageSpecificTags: ${packageSpecificTags}`,
|
|
778
838
|
"debug"
|
|
779
839
|
);
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
840
|
+
let allTags = [];
|
|
841
|
+
try {
|
|
842
|
+
const { execSync: execSync2 } = await Promise.resolve().then(() => (init_commandExecutor(), commandExecutor_exports));
|
|
843
|
+
const tagsOutput = execSync2("git", ["tag", "-l"], { cwd: process.cwd() });
|
|
844
|
+
allTags = tagsOutput.toString().trim().split("\n").filter((tag) => tag.length > 0);
|
|
845
|
+
} catch (err) {
|
|
846
|
+
log(`Error getting tags: ${err instanceof Error ? err.message : String(err)}`, "error");
|
|
847
|
+
}
|
|
848
|
+
log(`Retrieved ${allTags.length} tags`, "debug");
|
|
784
849
|
if (packageSpecificTags) {
|
|
785
850
|
const packageTagPattern = escapeRegExp(tagTemplate).replace(/\\\$\\\{packageName\\\}/g, `(?:${escapedPackageName})`).replace(/\\\$\\\{prefix\\\}/g, `(?:${escapedPrefix})`).replace(/\\\$\\\{version\\\}/g, "(?:[0-9]+\\.[0-9]+\\.[0-9]+(?:-[a-zA-Z0-9.-]+)?)");
|
|
786
851
|
log(`Using package tag pattern: ${packageTagPattern}`, "debug");
|
|
787
852
|
const packageTagRegex = new RegExp(`^${packageTagPattern}$`);
|
|
788
853
|
let packageTags = allTags.filter((tag) => packageTagRegex.test(tag));
|
|
854
|
+
log(`Found ${packageTags.length} matching tags for ${packageName}`, "debug");
|
|
789
855
|
if (packageTags.length > 0) {
|
|
790
856
|
const chronologicalFirst = packageTags[0];
|
|
857
|
+
void chronologicalFirst;
|
|
791
858
|
const sortedPackageTags2 = [...packageTags].sort((a, b) => {
|
|
792
859
|
let versionA = "";
|
|
793
860
|
let versionB = "";
|
|
794
861
|
if (a.includes("@")) {
|
|
795
|
-
const
|
|
862
|
+
const parts = a.split("@");
|
|
863
|
+
const afterAt = parts[parts.length - 1] || "";
|
|
796
864
|
versionA = afterAt.replace(new RegExp(`^${escapeRegExp(versionPrefix || "")}`), "");
|
|
797
865
|
} else {
|
|
798
866
|
versionA = a.replace(new RegExp(`^${escapeRegExp(packageName)}`), "").replace(new RegExp(`^${escapeRegExp(versionPrefix || "")}`), "");
|
|
799
867
|
}
|
|
800
868
|
if (b.includes("@")) {
|
|
801
|
-
const
|
|
869
|
+
const parts = b.split("@");
|
|
870
|
+
const afterAtB = parts[parts.length - 1] || "";
|
|
802
871
|
versionB = afterAtB.replace(new RegExp(`^${escapeRegExp(versionPrefix || "")}`), "");
|
|
803
872
|
} else {
|
|
804
873
|
versionB = b.replace(new RegExp(`^${escapeRegExp(packageName)}`), "").replace(new RegExp(`^${escapeRegExp(versionPrefix || "")}`), "");
|
|
@@ -809,12 +878,6 @@ async function getLatestTagForPackage(packageName, versionPrefix, options) {
|
|
|
809
878
|
});
|
|
810
879
|
log(`Found ${packageTags.length} package tags using configured pattern`, "debug");
|
|
811
880
|
log(`Using semantically latest tag: ${sortedPackageTags2[0]}`, "debug");
|
|
812
|
-
if (sortedPackageTags2[0] !== chronologicalFirst) {
|
|
813
|
-
log(
|
|
814
|
-
`Package tag ordering differs: chronological first is ${chronologicalFirst}, semantic latest is ${sortedPackageTags2[0]}`,
|
|
815
|
-
"debug"
|
|
816
|
-
);
|
|
817
|
-
}
|
|
818
881
|
return sortedPackageTags2[0];
|
|
819
882
|
}
|
|
820
883
|
if (versionPrefix) {
|
|
@@ -822,9 +885,11 @@ async function getLatestTagForPackage(packageName, versionPrefix, options) {
|
|
|
822
885
|
packageTags = allTags.filter((tag) => pattern1.test(tag));
|
|
823
886
|
if (packageTags.length > 0) {
|
|
824
887
|
const sortedPackageTags2 = [...packageTags].sort((a, b) => {
|
|
825
|
-
const
|
|
888
|
+
const aParts = a.split("@");
|
|
889
|
+
const afterAt = aParts[aParts.length - 1] || "";
|
|
826
890
|
const versionA = afterAt.replace(new RegExp(`^${escapeRegExp(versionPrefix || "")}`), "");
|
|
827
|
-
const
|
|
891
|
+
const bParts = b.split("@");
|
|
892
|
+
const afterAtB = bParts[bParts.length - 1] || "";
|
|
828
893
|
const versionB = afterAtB.replace(new RegExp(`^${escapeRegExp(versionPrefix || "")}`), "");
|
|
829
894
|
const cleanVersionA = import_semver.default.clean(versionA) || "0.0.0";
|
|
830
895
|
const cleanVersionB = import_semver.default.clean(versionB) || "0.0.0";
|
|
@@ -840,8 +905,10 @@ async function getLatestTagForPackage(packageName, versionPrefix, options) {
|
|
|
840
905
|
packageTags = allTags.filter((tag) => pattern2.test(tag));
|
|
841
906
|
if (packageTags.length > 0) {
|
|
842
907
|
const sortedPackageTags2 = [...packageTags].sort((a, b) => {
|
|
843
|
-
const
|
|
844
|
-
const
|
|
908
|
+
const aParts = a.split("@");
|
|
909
|
+
const versionA = import_semver.default.clean(aParts[aParts.length - 1] || "") || "0.0.0";
|
|
910
|
+
const bParts = b.split("@");
|
|
911
|
+
const versionB = import_semver.default.clean(bParts[bParts.length - 1] || "") || "0.0.0";
|
|
845
912
|
return import_semver.default.rcompare(versionA, versionB);
|
|
846
913
|
});
|
|
847
914
|
log(`Found ${packageTags.length} package tags using pattern: ${versionPrefix}packageName@...`, "debug");
|
|
@@ -861,8 +928,10 @@ async function getLatestTagForPackage(packageName, versionPrefix, options) {
|
|
|
861
928
|
return "";
|
|
862
929
|
}
|
|
863
930
|
const sortedPackageTags = [...packageTags].sort((a, b) => {
|
|
864
|
-
const
|
|
865
|
-
const
|
|
931
|
+
const aParts = a.split("@");
|
|
932
|
+
const versionA = import_semver.default.clean(aParts[aParts.length - 1] || "") || "0.0.0";
|
|
933
|
+
const bParts = b.split("@");
|
|
934
|
+
const versionB = import_semver.default.clean(bParts[bParts.length - 1] || "") || "0.0.0";
|
|
866
935
|
return import_semver.default.rcompare(versionA, versionB);
|
|
867
936
|
});
|
|
868
937
|
log(`Found ${packageTags.length} package tags for ${packageName}`, "debug");
|
|
@@ -1039,6 +1108,7 @@ var import_config3 = require("@releasekit/config");
|
|
|
1039
1108
|
var import_semver2 = __toESM(require("semver"), 1);
|
|
1040
1109
|
|
|
1041
1110
|
// src/git/tagVerification.ts
|
|
1111
|
+
init_commandExecutor();
|
|
1042
1112
|
function verifyTag(tagName, cwd4) {
|
|
1043
1113
|
if (!tagName || tagName.trim() === "") {
|
|
1044
1114
|
return { exists: false, reachable: false, error: "Empty tag name" };
|
|
@@ -1142,12 +1212,17 @@ var VersionMismatchError = class extends Error {
|
|
|
1142
1212
|
this.name = "VersionMismatchError";
|
|
1143
1213
|
}
|
|
1144
1214
|
};
|
|
1145
|
-
async function getBestVersionSource(tagName, packageVersion, cwd4, mismatchStrategy = "error") {
|
|
1215
|
+
async function getBestVersionSource(tagName, packageVersion, cwd4, mismatchStrategy = "error", strictReachable = false) {
|
|
1146
1216
|
if (!tagName?.trim()) {
|
|
1147
1217
|
return packageVersion ? { source: "package", version: packageVersion, reason: "No git tag provided" } : { source: "initial", version: "0.1.0", reason: "No git tag or package version available" };
|
|
1148
1218
|
}
|
|
1149
1219
|
const verification = verifyTag(tagName, cwd4);
|
|
1150
1220
|
if (!verification.exists || !verification.reachable) {
|
|
1221
|
+
if (strictReachable) {
|
|
1222
|
+
throw new Error(
|
|
1223
|
+
`Git tag '${tagName}' is not reachable from the current commit. The tag exists but cannot be reached from HEAD, which usually means you're on a different branch or the tag is orphaned. To allow fallback to package version, set strictReachable to false in your configuration.`
|
|
1224
|
+
);
|
|
1225
|
+
}
|
|
1151
1226
|
if (packageVersion) {
|
|
1152
1227
|
log(
|
|
1153
1228
|
`Git tag '${tagName}' unreachable (${verification.error}), using package version: ${packageVersion}`,
|
|
@@ -1253,7 +1328,8 @@ async function calculateVersion(config, options) {
|
|
|
1253
1328
|
prereleaseIdentifier: configPrereleaseIdentifier,
|
|
1254
1329
|
branchPattern,
|
|
1255
1330
|
baseBranch,
|
|
1256
|
-
mismatchStrategy
|
|
1331
|
+
mismatchStrategy,
|
|
1332
|
+
strictReachable
|
|
1257
1333
|
} = config;
|
|
1258
1334
|
const {
|
|
1259
1335
|
latestTag,
|
|
@@ -1298,7 +1374,13 @@ async function calculateVersion(config, options) {
|
|
|
1298
1374
|
const packageDir = pkgPath || (0, import_node_process2.cwd)();
|
|
1299
1375
|
const manifestResult = getVersionFromManifests(packageDir);
|
|
1300
1376
|
const packageVersion = manifestResult.manifestFound && manifestResult.version ? manifestResult.version : void 0;
|
|
1301
|
-
versionSource = await getBestVersionSource(
|
|
1377
|
+
versionSource = await getBestVersionSource(
|
|
1378
|
+
latestTag,
|
|
1379
|
+
packageVersion,
|
|
1380
|
+
packageDir,
|
|
1381
|
+
mismatchStrategy,
|
|
1382
|
+
strictReachable
|
|
1383
|
+
);
|
|
1302
1384
|
log(`Using version source: ${versionSource.source} (${versionSource.reason})`, "info");
|
|
1303
1385
|
}
|
|
1304
1386
|
const specifiedType = type;
|
|
@@ -1540,6 +1622,11 @@ var PackageProcessor = class {
|
|
|
1540
1622
|
if (verification.exists && verification.reachable) {
|
|
1541
1623
|
revisionRange = `${latestTag}..HEAD`;
|
|
1542
1624
|
} else {
|
|
1625
|
+
if (this.config.strictReachable) {
|
|
1626
|
+
throw new Error(
|
|
1627
|
+
`Cannot generate changelog: tag '${latestTag}' is not reachable from the current commit. When strictReachable is enabled, all tags must be reachable. To allow fallback to all commits, set strictReachable to false.`
|
|
1628
|
+
);
|
|
1629
|
+
}
|
|
1543
1630
|
log(`Tag ${latestTag} is unreachable (${verification.error}), using all commits for changelog`, "debug");
|
|
1544
1631
|
revisionRange = "HEAD";
|
|
1545
1632
|
}
|
|
@@ -1547,6 +1634,14 @@ var PackageProcessor = class {
|
|
|
1547
1634
|
revisionRange = "HEAD";
|
|
1548
1635
|
}
|
|
1549
1636
|
changelogEntries = extractChangelogEntriesFromCommits(pkgPath, revisionRange);
|
|
1637
|
+
const allCommitsWithHash = extractAllChangelogEntriesWithHash(pkgPath, revisionRange);
|
|
1638
|
+
const packageCommitsWithHash = extractChangelogEntriesWithHash(pkgPath, revisionRange);
|
|
1639
|
+
const packageCommitHashes = new Set(packageCommitsWithHash.map((c) => c.hash));
|
|
1640
|
+
const globalCommits = allCommitsWithHash.filter((c) => !packageCommitHashes.has(c.hash)).map((c) => c.entry);
|
|
1641
|
+
if (globalCommits.length > 0) {
|
|
1642
|
+
log(`Adding ${globalCommits.length} global commit(s) to ${name} changelog`, "debug");
|
|
1643
|
+
changelogEntries = [...globalCommits, ...changelogEntries];
|
|
1644
|
+
}
|
|
1550
1645
|
if (changelogEntries.length === 0) {
|
|
1551
1646
|
changelogEntries = [
|
|
1552
1647
|
{
|
|
@@ -1855,6 +1950,11 @@ function createSyncStrategy(config) {
|
|
|
1855
1950
|
});
|
|
1856
1951
|
revisionRange = `${latestTag}..HEAD`;
|
|
1857
1952
|
} catch {
|
|
1953
|
+
if (config.strictReachable) {
|
|
1954
|
+
throw new Error(
|
|
1955
|
+
`Cannot generate changelog: tag '${latestTag}' is not reachable from the current commit. When strictReachable is enabled, all tags must be reachable. To allow fallback to all commits, set strictReachable to false.`
|
|
1956
|
+
);
|
|
1957
|
+
}
|
|
1858
1958
|
log(`Tag ${latestTag} doesn't exist, using all commits for changelog`, "debug");
|
|
1859
1959
|
revisionRange = "HEAD";
|
|
1860
1960
|
}
|
|
@@ -1974,6 +2074,11 @@ function createSingleStrategy(config) {
|
|
|
1974
2074
|
});
|
|
1975
2075
|
revisionRange = `${latestTag}..HEAD`;
|
|
1976
2076
|
} catch {
|
|
2077
|
+
if (config.strictReachable) {
|
|
2078
|
+
throw new Error(
|
|
2079
|
+
`Cannot generate changelog: tag '${latestTag}' is not reachable from the current commit. When strictReachable is enabled, all tags must be reachable. To allow fallback to all commits, set strictReachable to false.`
|
|
2080
|
+
);
|
|
2081
|
+
}
|
|
1977
2082
|
log(`Tag ${latestTag} doesn't exist, using all commits for changelog`, "debug");
|
|
1978
2083
|
revisionRange = "HEAD";
|
|
1979
2084
|
}
|
package/dist/cli.js
CHANGED
package/dist/index.cjs
CHANGED
|
@@ -5,6 +5,9 @@ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
|
5
5
|
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
6
|
var __getProtoOf = Object.getPrototypeOf;
|
|
7
7
|
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
+
var __esm = (fn, res) => function __init() {
|
|
9
|
+
return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
|
|
10
|
+
};
|
|
8
11
|
var __export = (target, all) => {
|
|
9
12
|
for (var name in all)
|
|
10
13
|
__defProp(target, name, { get: all[name], enumerable: true });
|
|
@@ -27,6 +30,33 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
|
|
|
27
30
|
));
|
|
28
31
|
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
29
32
|
|
|
33
|
+
// src/git/commandExecutor.ts
|
|
34
|
+
var commandExecutor_exports = {};
|
|
35
|
+
__export(commandExecutor_exports, {
|
|
36
|
+
execAsync: () => execAsync,
|
|
37
|
+
execSync: () => execSync
|
|
38
|
+
});
|
|
39
|
+
var import_node_child_process, execAsync, execSync;
|
|
40
|
+
var init_commandExecutor = __esm({
|
|
41
|
+
"src/git/commandExecutor.ts"() {
|
|
42
|
+
"use strict";
|
|
43
|
+
import_node_child_process = require("child_process");
|
|
44
|
+
execAsync = (file, args, options) => {
|
|
45
|
+
const defaultOptions = { maxBuffer: 1024 * 1024 * 10, ...options };
|
|
46
|
+
return new Promise((resolve2, reject) => {
|
|
47
|
+
(0, import_node_child_process.execFile)(file, args, defaultOptions, (error, stdout, stderr) => {
|
|
48
|
+
if (error) {
|
|
49
|
+
reject(error);
|
|
50
|
+
} else {
|
|
51
|
+
resolve2({ stdout: stdout.toString(), stderr: stderr.toString() });
|
|
52
|
+
}
|
|
53
|
+
});
|
|
54
|
+
});
|
|
55
|
+
};
|
|
56
|
+
execSync = (file, args, options) => (0, import_node_child_process.execFileSync)(file, args, { maxBuffer: 1024 * 1024 * 10, ...options });
|
|
57
|
+
}
|
|
58
|
+
});
|
|
59
|
+
|
|
30
60
|
// src/index.ts
|
|
31
61
|
var index_exports = {};
|
|
32
62
|
__export(index_exports, {
|
|
@@ -100,24 +130,7 @@ var import_semver3 = __toESM(require("semver"), 1);
|
|
|
100
130
|
// src/git/repository.ts
|
|
101
131
|
var import_node_fs = require("fs");
|
|
102
132
|
var import_node_path = require("path");
|
|
103
|
-
|
|
104
|
-
// src/git/commandExecutor.ts
|
|
105
|
-
var import_node_child_process = require("child_process");
|
|
106
|
-
var execAsync = (file, args, options) => {
|
|
107
|
-
const defaultOptions = { maxBuffer: 1024 * 1024 * 10, ...options };
|
|
108
|
-
return new Promise((resolve2, reject) => {
|
|
109
|
-
(0, import_node_child_process.execFile)(file, args, defaultOptions, (error, stdout, stderr) => {
|
|
110
|
-
if (error) {
|
|
111
|
-
reject(error);
|
|
112
|
-
} else {
|
|
113
|
-
resolve2({ stdout: stdout.toString(), stderr: stderr.toString() });
|
|
114
|
-
}
|
|
115
|
-
});
|
|
116
|
-
});
|
|
117
|
-
};
|
|
118
|
-
var execSync = (file, args, options) => (0, import_node_child_process.execFileSync)(file, args, { maxBuffer: 1024 * 1024 * 10, ...options });
|
|
119
|
-
|
|
120
|
-
// src/git/repository.ts
|
|
133
|
+
init_commandExecutor();
|
|
121
134
|
function isGitRepository(directory) {
|
|
122
135
|
const gitDir = (0, import_node_path.join)(directory, ".git");
|
|
123
136
|
if (!(0, import_node_fs.existsSync)(gitDir)) {
|
|
@@ -280,6 +293,7 @@ To fix this:
|
|
|
280
293
|
}
|
|
281
294
|
|
|
282
295
|
// src/git/tagsAndBranches.ts
|
|
296
|
+
init_commandExecutor();
|
|
283
297
|
function getCommitsLength(pkgRoot, sinceTag) {
|
|
284
298
|
try {
|
|
285
299
|
let amount;
|
|
@@ -357,28 +371,37 @@ async function getLatestTagForPackage(packageName, versionPrefix, options) {
|
|
|
357
371
|
`Looking for tags for package ${packageName} with prefix ${versionPrefix || "none"}, packageSpecificTags: ${packageSpecificTags}`,
|
|
358
372
|
"debug"
|
|
359
373
|
);
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
374
|
+
let allTags = [];
|
|
375
|
+
try {
|
|
376
|
+
const { execSync: execSync2 } = await Promise.resolve().then(() => (init_commandExecutor(), commandExecutor_exports));
|
|
377
|
+
const tagsOutput = execSync2("git", ["tag", "-l"], { cwd: process.cwd() });
|
|
378
|
+
allTags = tagsOutput.toString().trim().split("\n").filter((tag) => tag.length > 0);
|
|
379
|
+
} catch (err) {
|
|
380
|
+
log(`Error getting tags: ${err instanceof Error ? err.message : String(err)}`, "error");
|
|
381
|
+
}
|
|
382
|
+
log(`Retrieved ${allTags.length} tags`, "debug");
|
|
364
383
|
if (packageSpecificTags) {
|
|
365
384
|
const packageTagPattern = escapeRegExp(tagTemplate).replace(/\\\$\\\{packageName\\\}/g, `(?:${escapedPackageName})`).replace(/\\\$\\\{prefix\\\}/g, `(?:${escapedPrefix})`).replace(/\\\$\\\{version\\\}/g, "(?:[0-9]+\\.[0-9]+\\.[0-9]+(?:-[a-zA-Z0-9.-]+)?)");
|
|
366
385
|
log(`Using package tag pattern: ${packageTagPattern}`, "debug");
|
|
367
386
|
const packageTagRegex = new RegExp(`^${packageTagPattern}$`);
|
|
368
387
|
let packageTags = allTags.filter((tag) => packageTagRegex.test(tag));
|
|
388
|
+
log(`Found ${packageTags.length} matching tags for ${packageName}`, "debug");
|
|
369
389
|
if (packageTags.length > 0) {
|
|
370
390
|
const chronologicalFirst = packageTags[0];
|
|
391
|
+
void chronologicalFirst;
|
|
371
392
|
const sortedPackageTags2 = [...packageTags].sort((a, b) => {
|
|
372
393
|
let versionA = "";
|
|
373
394
|
let versionB = "";
|
|
374
395
|
if (a.includes("@")) {
|
|
375
|
-
const
|
|
396
|
+
const parts = a.split("@");
|
|
397
|
+
const afterAt = parts[parts.length - 1] || "";
|
|
376
398
|
versionA = afterAt.replace(new RegExp(`^${escapeRegExp(versionPrefix || "")}`), "");
|
|
377
399
|
} else {
|
|
378
400
|
versionA = a.replace(new RegExp(`^${escapeRegExp(packageName)}`), "").replace(new RegExp(`^${escapeRegExp(versionPrefix || "")}`), "");
|
|
379
401
|
}
|
|
380
402
|
if (b.includes("@")) {
|
|
381
|
-
const
|
|
403
|
+
const parts = b.split("@");
|
|
404
|
+
const afterAtB = parts[parts.length - 1] || "";
|
|
382
405
|
versionB = afterAtB.replace(new RegExp(`^${escapeRegExp(versionPrefix || "")}`), "");
|
|
383
406
|
} else {
|
|
384
407
|
versionB = b.replace(new RegExp(`^${escapeRegExp(packageName)}`), "").replace(new RegExp(`^${escapeRegExp(versionPrefix || "")}`), "");
|
|
@@ -389,12 +412,6 @@ async function getLatestTagForPackage(packageName, versionPrefix, options) {
|
|
|
389
412
|
});
|
|
390
413
|
log(`Found ${packageTags.length} package tags using configured pattern`, "debug");
|
|
391
414
|
log(`Using semantically latest tag: ${sortedPackageTags2[0]}`, "debug");
|
|
392
|
-
if (sortedPackageTags2[0] !== chronologicalFirst) {
|
|
393
|
-
log(
|
|
394
|
-
`Package tag ordering differs: chronological first is ${chronologicalFirst}, semantic latest is ${sortedPackageTags2[0]}`,
|
|
395
|
-
"debug"
|
|
396
|
-
);
|
|
397
|
-
}
|
|
398
415
|
return sortedPackageTags2[0];
|
|
399
416
|
}
|
|
400
417
|
if (versionPrefix) {
|
|
@@ -402,9 +419,11 @@ async function getLatestTagForPackage(packageName, versionPrefix, options) {
|
|
|
402
419
|
packageTags = allTags.filter((tag) => pattern1.test(tag));
|
|
403
420
|
if (packageTags.length > 0) {
|
|
404
421
|
const sortedPackageTags2 = [...packageTags].sort((a, b) => {
|
|
405
|
-
const
|
|
422
|
+
const aParts = a.split("@");
|
|
423
|
+
const afterAt = aParts[aParts.length - 1] || "";
|
|
406
424
|
const versionA = afterAt.replace(new RegExp(`^${escapeRegExp(versionPrefix || "")}`), "");
|
|
407
|
-
const
|
|
425
|
+
const bParts = b.split("@");
|
|
426
|
+
const afterAtB = bParts[bParts.length - 1] || "";
|
|
408
427
|
const versionB = afterAtB.replace(new RegExp(`^${escapeRegExp(versionPrefix || "")}`), "");
|
|
409
428
|
const cleanVersionA = import_semver.default.clean(versionA) || "0.0.0";
|
|
410
429
|
const cleanVersionB = import_semver.default.clean(versionB) || "0.0.0";
|
|
@@ -420,8 +439,10 @@ async function getLatestTagForPackage(packageName, versionPrefix, options) {
|
|
|
420
439
|
packageTags = allTags.filter((tag) => pattern2.test(tag));
|
|
421
440
|
if (packageTags.length > 0) {
|
|
422
441
|
const sortedPackageTags2 = [...packageTags].sort((a, b) => {
|
|
423
|
-
const
|
|
424
|
-
const
|
|
442
|
+
const aParts = a.split("@");
|
|
443
|
+
const versionA = import_semver.default.clean(aParts[aParts.length - 1] || "") || "0.0.0";
|
|
444
|
+
const bParts = b.split("@");
|
|
445
|
+
const versionB = import_semver.default.clean(bParts[bParts.length - 1] || "") || "0.0.0";
|
|
425
446
|
return import_semver.default.rcompare(versionA, versionB);
|
|
426
447
|
});
|
|
427
448
|
log(`Found ${packageTags.length} package tags using pattern: ${versionPrefix}packageName@...`, "debug");
|
|
@@ -441,8 +462,10 @@ async function getLatestTagForPackage(packageName, versionPrefix, options) {
|
|
|
441
462
|
return "";
|
|
442
463
|
}
|
|
443
464
|
const sortedPackageTags = [...packageTags].sort((a, b) => {
|
|
444
|
-
const
|
|
445
|
-
const
|
|
465
|
+
const aParts = a.split("@");
|
|
466
|
+
const versionA = import_semver.default.clean(aParts[aParts.length - 1] || "") || "0.0.0";
|
|
467
|
+
const bParts = b.split("@");
|
|
468
|
+
const versionB = import_semver.default.clean(bParts[bParts.length - 1] || "") || "0.0.0";
|
|
446
469
|
return import_semver.default.rcompare(versionA, versionB);
|
|
447
470
|
});
|
|
448
471
|
log(`Found ${packageTags.length} package tags for ${packageName}`, "debug");
|
|
@@ -578,6 +601,7 @@ var import_config3 = require("@releasekit/config");
|
|
|
578
601
|
var import_semver2 = __toESM(require("semver"), 1);
|
|
579
602
|
|
|
580
603
|
// src/git/tagVerification.ts
|
|
604
|
+
init_commandExecutor();
|
|
581
605
|
function verifyTag(tagName, cwd4) {
|
|
582
606
|
if (!tagName || tagName.trim() === "") {
|
|
583
607
|
return { exists: false, reachable: false, error: "Empty tag name" };
|
|
@@ -681,12 +705,17 @@ var VersionMismatchError = class extends Error {
|
|
|
681
705
|
this.name = "VersionMismatchError";
|
|
682
706
|
}
|
|
683
707
|
};
|
|
684
|
-
async function getBestVersionSource(tagName, packageVersion, cwd4, mismatchStrategy = "error") {
|
|
708
|
+
async function getBestVersionSource(tagName, packageVersion, cwd4, mismatchStrategy = "error", strictReachable = false) {
|
|
685
709
|
if (!tagName?.trim()) {
|
|
686
710
|
return packageVersion ? { source: "package", version: packageVersion, reason: "No git tag provided" } : { source: "initial", version: "0.1.0", reason: "No git tag or package version available" };
|
|
687
711
|
}
|
|
688
712
|
const verification = verifyTag(tagName, cwd4);
|
|
689
713
|
if (!verification.exists || !verification.reachable) {
|
|
714
|
+
if (strictReachable) {
|
|
715
|
+
throw new Error(
|
|
716
|
+
`Git tag '${tagName}' is not reachable from the current commit. The tag exists but cannot be reached from HEAD, which usually means you're on a different branch or the tag is orphaned. To allow fallback to package version, set strictReachable to false in your configuration.`
|
|
717
|
+
);
|
|
718
|
+
}
|
|
690
719
|
if (packageVersion) {
|
|
691
720
|
log(
|
|
692
721
|
`Git tag '${tagName}' unreachable (${verification.error}), using package version: ${packageVersion}`,
|
|
@@ -792,7 +821,8 @@ async function calculateVersion(config, options) {
|
|
|
792
821
|
prereleaseIdentifier: configPrereleaseIdentifier,
|
|
793
822
|
branchPattern,
|
|
794
823
|
baseBranch,
|
|
795
|
-
mismatchStrategy
|
|
824
|
+
mismatchStrategy,
|
|
825
|
+
strictReachable
|
|
796
826
|
} = config;
|
|
797
827
|
const {
|
|
798
828
|
latestTag,
|
|
@@ -837,7 +867,13 @@ async function calculateVersion(config, options) {
|
|
|
837
867
|
const packageDir = pkgPath || (0, import_node_process.cwd)();
|
|
838
868
|
const manifestResult = getVersionFromManifests(packageDir);
|
|
839
869
|
const packageVersion = manifestResult.manifestFound && manifestResult.version ? manifestResult.version : void 0;
|
|
840
|
-
versionSource = await getBestVersionSource(
|
|
870
|
+
versionSource = await getBestVersionSource(
|
|
871
|
+
latestTag,
|
|
872
|
+
packageVersion,
|
|
873
|
+
packageDir,
|
|
874
|
+
mismatchStrategy,
|
|
875
|
+
strictReachable
|
|
876
|
+
);
|
|
841
877
|
log(`Using version source: ${versionSource.source} (${versionSource.reason})`, "info");
|
|
842
878
|
}
|
|
843
879
|
const specifiedType = type;
|
|
@@ -1129,14 +1165,59 @@ var import_node_fs6 = __toESM(require("fs"), 1);
|
|
|
1129
1165
|
var path6 = __toESM(require("path"), 1);
|
|
1130
1166
|
|
|
1131
1167
|
// src/changelog/commitParser.ts
|
|
1168
|
+
init_commandExecutor();
|
|
1132
1169
|
var CONVENTIONAL_COMMIT_REGEX = /^(\w+)(?:\(([^)]+)\))?(!)?: (.+)(?:\n\n([\s\S]*))?/;
|
|
1133
1170
|
var BREAKING_CHANGE_REGEX = /BREAKING CHANGE: ([\s\S]+?)(?:\n\n|$)/;
|
|
1171
|
+
function extractChangelogEntriesWithHash(projectDir, revisionRange) {
|
|
1172
|
+
try {
|
|
1173
|
+
const args = ["log", revisionRange, "--pretty=format:%H|||%B---COMMIT_DELIMITER---", "--no-merges", "--", "."];
|
|
1174
|
+
const output = execSync("git", args, { cwd: projectDir, encoding: "utf8" }).toString();
|
|
1175
|
+
const commits = output.split("---COMMIT_DELIMITER---").filter((commit) => commit.trim() !== "");
|
|
1176
|
+
return commits.map((commit) => {
|
|
1177
|
+
const [hash, ...messageParts] = commit.split("|||");
|
|
1178
|
+
const message = messageParts.join("|||").trim();
|
|
1179
|
+
const entry = parseCommitMessage(message);
|
|
1180
|
+
if (entry && hash) {
|
|
1181
|
+
return { hash: hash.trim(), entry };
|
|
1182
|
+
}
|
|
1183
|
+
return null;
|
|
1184
|
+
}).filter((item) => item !== null);
|
|
1185
|
+
} catch (error) {
|
|
1186
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
1187
|
+
log(`Error extracting commits with hash: ${errorMessage}`, "error");
|
|
1188
|
+
return [];
|
|
1189
|
+
}
|
|
1190
|
+
}
|
|
1191
|
+
function extractAllChangelogEntriesWithHash(projectDir, revisionRange) {
|
|
1192
|
+
try {
|
|
1193
|
+
const args = ["log", revisionRange, "--pretty=format:%H|||%B---COMMIT_DELIMITER---", "--no-merges"];
|
|
1194
|
+
const output = execSync("git", args, { cwd: projectDir, encoding: "utf8" }).toString();
|
|
1195
|
+
const commits = output.split("---COMMIT_DELIMITER---").filter((commit) => commit.trim() !== "");
|
|
1196
|
+
return commits.map((commit) => {
|
|
1197
|
+
const [hash, ...messageParts] = commit.split("|||");
|
|
1198
|
+
const message = messageParts.join("|||").trim();
|
|
1199
|
+
const entry = parseCommitMessage(message);
|
|
1200
|
+
if (entry && hash) {
|
|
1201
|
+
return { hash: hash.trim(), entry };
|
|
1202
|
+
}
|
|
1203
|
+
return null;
|
|
1204
|
+
}).filter((item) => item !== null);
|
|
1205
|
+
} catch (error) {
|
|
1206
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
1207
|
+
log(`Error extracting all commits with hash: ${errorMessage}`, "error");
|
|
1208
|
+
return [];
|
|
1209
|
+
}
|
|
1210
|
+
}
|
|
1134
1211
|
function extractChangelogEntriesFromCommits(projectDir, revisionRange) {
|
|
1212
|
+
return extractCommitsFromGitLog(projectDir, revisionRange, true);
|
|
1213
|
+
}
|
|
1214
|
+
function extractCommitsFromGitLog(projectDir, revisionRange, filterToPath) {
|
|
1135
1215
|
try {
|
|
1136
|
-
const
|
|
1137
|
-
|
|
1138
|
-
|
|
1139
|
-
}
|
|
1216
|
+
const args = ["log", revisionRange, "--pretty=format:%B---COMMIT_DELIMITER---", "--no-merges"];
|
|
1217
|
+
if (filterToPath) {
|
|
1218
|
+
args.push("--", ".");
|
|
1219
|
+
}
|
|
1220
|
+
const output = execSync("git", args, { cwd: projectDir, encoding: "utf8" }).toString();
|
|
1140
1221
|
const commits = output.split("---COMMIT_DELIMITER---").filter((commit) => commit.trim() !== "");
|
|
1141
1222
|
return commits.map((commit) => parseCommitMessage(commit)).filter((entry) => entry !== null);
|
|
1142
1223
|
} catch (error) {
|
|
@@ -1229,8 +1310,12 @@ function extractIssueIds(body) {
|
|
|
1229
1310
|
return issueIds;
|
|
1230
1311
|
}
|
|
1231
1312
|
|
|
1313
|
+
// src/core/versionStrategies.ts
|
|
1314
|
+
init_commandExecutor();
|
|
1315
|
+
|
|
1232
1316
|
// src/git/commands.ts
|
|
1233
1317
|
var import_node_process2 = require("process");
|
|
1318
|
+
init_commandExecutor();
|
|
1234
1319
|
async function gitAdd(files) {
|
|
1235
1320
|
return execAsync("git", ["add", ...files]);
|
|
1236
1321
|
}
|
|
@@ -1535,6 +1620,11 @@ var PackageProcessor = class {
|
|
|
1535
1620
|
if (verification.exists && verification.reachable) {
|
|
1536
1621
|
revisionRange = `${latestTag}..HEAD`;
|
|
1537
1622
|
} else {
|
|
1623
|
+
if (this.config.strictReachable) {
|
|
1624
|
+
throw new Error(
|
|
1625
|
+
`Cannot generate changelog: tag '${latestTag}' is not reachable from the current commit. When strictReachable is enabled, all tags must be reachable. To allow fallback to all commits, set strictReachable to false.`
|
|
1626
|
+
);
|
|
1627
|
+
}
|
|
1538
1628
|
log(`Tag ${latestTag} is unreachable (${verification.error}), using all commits for changelog`, "debug");
|
|
1539
1629
|
revisionRange = "HEAD";
|
|
1540
1630
|
}
|
|
@@ -1542,6 +1632,14 @@ var PackageProcessor = class {
|
|
|
1542
1632
|
revisionRange = "HEAD";
|
|
1543
1633
|
}
|
|
1544
1634
|
changelogEntries = extractChangelogEntriesFromCommits(pkgPath, revisionRange);
|
|
1635
|
+
const allCommitsWithHash = extractAllChangelogEntriesWithHash(pkgPath, revisionRange);
|
|
1636
|
+
const packageCommitsWithHash = extractChangelogEntriesWithHash(pkgPath, revisionRange);
|
|
1637
|
+
const packageCommitHashes = new Set(packageCommitsWithHash.map((c) => c.hash));
|
|
1638
|
+
const globalCommits = allCommitsWithHash.filter((c) => !packageCommitHashes.has(c.hash)).map((c) => c.entry);
|
|
1639
|
+
if (globalCommits.length > 0) {
|
|
1640
|
+
log(`Adding ${globalCommits.length} global commit(s) to ${name} changelog`, "debug");
|
|
1641
|
+
changelogEntries = [...globalCommits, ...changelogEntries];
|
|
1642
|
+
}
|
|
1545
1643
|
if (changelogEntries.length === 0) {
|
|
1546
1644
|
changelogEntries = [
|
|
1547
1645
|
{
|
|
@@ -1850,6 +1948,11 @@ function createSyncStrategy(config) {
|
|
|
1850
1948
|
});
|
|
1851
1949
|
revisionRange = `${latestTag}..HEAD`;
|
|
1852
1950
|
} catch {
|
|
1951
|
+
if (config.strictReachable) {
|
|
1952
|
+
throw new Error(
|
|
1953
|
+
`Cannot generate changelog: tag '${latestTag}' is not reachable from the current commit. When strictReachable is enabled, all tags must be reachable. To allow fallback to all commits, set strictReachable to false.`
|
|
1954
|
+
);
|
|
1955
|
+
}
|
|
1853
1956
|
log(`Tag ${latestTag} doesn't exist, using all commits for changelog`, "debug");
|
|
1854
1957
|
revisionRange = "HEAD";
|
|
1855
1958
|
}
|
|
@@ -1969,6 +2072,11 @@ function createSingleStrategy(config) {
|
|
|
1969
2072
|
});
|
|
1970
2073
|
revisionRange = `${latestTag}..HEAD`;
|
|
1971
2074
|
} catch {
|
|
2075
|
+
if (config.strictReachable) {
|
|
2076
|
+
throw new Error(
|
|
2077
|
+
`Cannot generate changelog: tag '${latestTag}' is not reachable from the current commit. When strictReachable is enabled, all tags must be reachable. To allow fallback to all commits, set strictReachable to false.`
|
|
2078
|
+
);
|
|
2079
|
+
}
|
|
1972
2080
|
log(`Tag ${latestTag} doesn't exist, using all commits for changelog`, "debug");
|
|
1973
2081
|
revisionRange = "HEAD";
|
|
1974
2082
|
}
|
package/dist/index.d.cts
CHANGED
|
@@ -11,6 +11,7 @@ interface VersionConfigBase {
|
|
|
11
11
|
baseBranch?: string;
|
|
12
12
|
path?: string;
|
|
13
13
|
name?: string;
|
|
14
|
+
strictReachable?: boolean;
|
|
14
15
|
}
|
|
15
16
|
interface Config extends VersionConfigBase {
|
|
16
17
|
tagTemplate: string;
|
|
@@ -30,6 +31,7 @@ interface Config extends VersionConfigBase {
|
|
|
30
31
|
latestTag?: string;
|
|
31
32
|
isPrerelease?: boolean;
|
|
32
33
|
mismatchStrategy?: 'error' | 'warn' | 'ignore' | 'prefer-package' | 'prefer-git';
|
|
34
|
+
strictReachable?: boolean;
|
|
33
35
|
cargo?: {
|
|
34
36
|
enabled?: boolean;
|
|
35
37
|
paths?: string[];
|
package/dist/index.d.ts
CHANGED
|
@@ -11,6 +11,7 @@ interface VersionConfigBase {
|
|
|
11
11
|
baseBranch?: string;
|
|
12
12
|
path?: string;
|
|
13
13
|
name?: string;
|
|
14
|
+
strictReachable?: boolean;
|
|
14
15
|
}
|
|
15
16
|
interface Config extends VersionConfigBase {
|
|
16
17
|
tagTemplate: string;
|
|
@@ -30,6 +31,7 @@ interface Config extends VersionConfigBase {
|
|
|
30
31
|
latestTag?: string;
|
|
31
32
|
isPrerelease?: boolean;
|
|
32
33
|
mismatchStrategy?: 'error' | 'warn' | 'ignore' | 'prefer-package' | 'prefer-git';
|
|
34
|
+
strictReachable?: boolean;
|
|
33
35
|
cargo?: {
|
|
34
36
|
enabled?: boolean;
|
|
35
37
|
paths?: string[];
|
package/dist/index.js
CHANGED
|
@@ -10,10 +10,11 @@ import {
|
|
|
10
10
|
enableJsonOutput,
|
|
11
11
|
getJsonData,
|
|
12
12
|
loadConfig
|
|
13
|
-
} from "./chunk-
|
|
13
|
+
} from "./chunk-DXDB5P7S.js";
|
|
14
14
|
import {
|
|
15
15
|
BaseVersionError
|
|
16
16
|
} from "./chunk-GQLJ7JQY.js";
|
|
17
|
+
import "./chunk-LMPZV35Z.js";
|
|
17
18
|
export {
|
|
18
19
|
BaseVersionError,
|
|
19
20
|
PackageProcessor,
|