@releasekit/version 0.2.0-next.1 → 0.2.0-next.11
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-25A2IEAC.js} +148 -42
- package/dist/chunk-LMPZV35Z.js +20 -0
- package/dist/cli.cjs +177 -40
- package/dist/cli.js +2 -1
- package/dist/commandExecutor-E44ID5U4.js +8 -0
- package/dist/index.cjs +182 -42
- 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,83 @@ 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|$)/;
|
|
965
|
-
function
|
|
972
|
+
function extractAllChangelogEntriesWithHash(projectDir, revisionRange) {
|
|
966
973
|
try {
|
|
967
|
-
const
|
|
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 all commits with hash: ${errorMessage}`, "error");
|
|
989
|
+
return [];
|
|
990
|
+
}
|
|
991
|
+
}
|
|
992
|
+
function commitTouchesAnyPackage(projectDir, commitHash, packageDirs, sharedPackageDirs = []) {
|
|
993
|
+
try {
|
|
994
|
+
const output = execSync("git", ["diff-tree", "--no-commit-id", "--name-only", "-r", commitHash], {
|
|
968
995
|
cwd: projectDir,
|
|
969
996
|
encoding: "utf8"
|
|
970
|
-
}).toString();
|
|
997
|
+
}).toString().trim();
|
|
998
|
+
if (!output) {
|
|
999
|
+
return false;
|
|
1000
|
+
}
|
|
1001
|
+
const changedFiles = output.split("\n");
|
|
1002
|
+
return changedFiles.some((file) => {
|
|
1003
|
+
return packageDirs.some((pkgDir) => {
|
|
1004
|
+
if (sharedPackageDirs.some((sharedDir) => pkgDir.includes(sharedDir))) {
|
|
1005
|
+
return false;
|
|
1006
|
+
}
|
|
1007
|
+
const normalizedFile = file.replace(/\\/g, "/");
|
|
1008
|
+
const normalizedPkgDir = pkgDir.replace(/\\/g, "/").replace(/^\.\//, "");
|
|
1009
|
+
return normalizedFile.startsWith(normalizedPkgDir);
|
|
1010
|
+
});
|
|
1011
|
+
});
|
|
1012
|
+
} catch (error) {
|
|
1013
|
+
log(
|
|
1014
|
+
`Error checking if commit ${commitHash} touches packages: ${error instanceof Error ? error.message : String(error)}`,
|
|
1015
|
+
"debug"
|
|
1016
|
+
);
|
|
1017
|
+
return false;
|
|
1018
|
+
}
|
|
1019
|
+
}
|
|
1020
|
+
function extractRepoLevelChangelogEntries(projectDir, revisionRange, packageDirs, sharedPackageDirs = []) {
|
|
1021
|
+
try {
|
|
1022
|
+
const allCommits = extractAllChangelogEntriesWithHash(projectDir, revisionRange);
|
|
1023
|
+
const repoLevelCommits = allCommits.filter((commit) => {
|
|
1024
|
+
const touchesPackage = commitTouchesAnyPackage(projectDir, commit.hash, packageDirs, sharedPackageDirs);
|
|
1025
|
+
return !touchesPackage;
|
|
1026
|
+
});
|
|
1027
|
+
if (repoLevelCommits.length > 0) {
|
|
1028
|
+
log(
|
|
1029
|
+
`Found ${repoLevelCommits.length} repo-level commit(s) (including shared packages: ${sharedPackageDirs.join(", ")})`,
|
|
1030
|
+
"debug"
|
|
1031
|
+
);
|
|
1032
|
+
}
|
|
1033
|
+
return repoLevelCommits.map((c) => c.entry);
|
|
1034
|
+
} catch (error) {
|
|
1035
|
+
log(`Error extracting repo-level commits: ${error instanceof Error ? error.message : String(error)}`, "warning");
|
|
1036
|
+
return [];
|
|
1037
|
+
}
|
|
1038
|
+
}
|
|
1039
|
+
function extractChangelogEntriesFromCommits(projectDir, revisionRange) {
|
|
1040
|
+
return extractCommitsFromGitLog(projectDir, revisionRange, true);
|
|
1041
|
+
}
|
|
1042
|
+
function extractCommitsFromGitLog(projectDir, revisionRange, filterToPath) {
|
|
1043
|
+
try {
|
|
1044
|
+
const args = ["log", revisionRange, "--pretty=format:%B---COMMIT_DELIMITER---", "--no-merges"];
|
|
1045
|
+
if (filterToPath) {
|
|
1046
|
+
args.push("--", ".");
|
|
1047
|
+
}
|
|
1048
|
+
const output = execSync("git", args, { cwd: projectDir, encoding: "utf8" }).toString();
|
|
971
1049
|
const commits = output.split("---COMMIT_DELIMITER---").filter((commit) => commit.trim() !== "");
|
|
972
1050
|
return commits.map((commit) => parseCommitMessage(commit)).filter((entry) => entry !== null);
|
|
973
1051
|
} catch (error) {
|
|
@@ -1395,6 +1473,11 @@ var PackageProcessor = class {
|
|
|
1395
1473
|
if (verification.exists && verification.reachable) {
|
|
1396
1474
|
revisionRange = `${latestTag}..HEAD`;
|
|
1397
1475
|
} else {
|
|
1476
|
+
if (this.config.strictReachable) {
|
|
1477
|
+
throw new Error(
|
|
1478
|
+
`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.`
|
|
1479
|
+
);
|
|
1480
|
+
}
|
|
1398
1481
|
log(`Tag ${latestTag} is unreachable (${verification.error}), using all commits for changelog`, "debug");
|
|
1399
1482
|
revisionRange = "HEAD";
|
|
1400
1483
|
}
|
|
@@ -1402,6 +1485,19 @@ var PackageProcessor = class {
|
|
|
1402
1485
|
revisionRange = "HEAD";
|
|
1403
1486
|
}
|
|
1404
1487
|
changelogEntries = extractChangelogEntriesFromCommits(pkgPath, revisionRange);
|
|
1488
|
+
const allPackageDirs = packages.map((p) => p.dir);
|
|
1489
|
+
const sharedPackageNames = ["config", "core", "@releasekit/config", "@releasekit/core"];
|
|
1490
|
+
const sharedPackageDirs = packages.filter((p) => sharedPackageNames.includes(p.packageJson.name)).map((p) => p.dir);
|
|
1491
|
+
const repoLevelEntries = extractRepoLevelChangelogEntries(
|
|
1492
|
+
pkgPath,
|
|
1493
|
+
revisionRange,
|
|
1494
|
+
allPackageDirs,
|
|
1495
|
+
sharedPackageDirs
|
|
1496
|
+
);
|
|
1497
|
+
if (repoLevelEntries.length > 0) {
|
|
1498
|
+
log(`Adding ${repoLevelEntries.length} repo-level commit(s) to ${name} changelog`, "debug");
|
|
1499
|
+
changelogEntries = [...repoLevelEntries, ...changelogEntries];
|
|
1500
|
+
}
|
|
1405
1501
|
if (changelogEntries.length === 0) {
|
|
1406
1502
|
changelogEntries = [
|
|
1407
1503
|
{
|
|
@@ -1712,6 +1808,11 @@ function createSyncStrategy(config) {
|
|
|
1712
1808
|
});
|
|
1713
1809
|
revisionRange = `${latestTag}..HEAD`;
|
|
1714
1810
|
} catch {
|
|
1811
|
+
if (config.strictReachable) {
|
|
1812
|
+
throw new Error(
|
|
1813
|
+
`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.`
|
|
1814
|
+
);
|
|
1815
|
+
}
|
|
1715
1816
|
log(`Tag ${latestTag} doesn't exist, using all commits for changelog`, "debug");
|
|
1716
1817
|
revisionRange = "HEAD";
|
|
1717
1818
|
}
|
|
@@ -1831,6 +1932,11 @@ function createSingleStrategy(config) {
|
|
|
1831
1932
|
});
|
|
1832
1933
|
revisionRange = `${latestTag}..HEAD`;
|
|
1833
1934
|
} catch {
|
|
1935
|
+
if (config.strictReachable) {
|
|
1936
|
+
throw new Error(
|
|
1937
|
+
`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.`
|
|
1938
|
+
);
|
|
1939
|
+
}
|
|
1834
1940
|
log(`Tag ${latestTag} doesn't exist, using all commits for changelog`, "debug");
|
|
1835
1941
|
revisionRange = "HEAD";
|
|
1836
1942
|
}
|
|
@@ -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,87 @@ 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|$)/;
|
|
392
|
-
function
|
|
404
|
+
function extractAllChangelogEntriesWithHash(projectDir, revisionRange) {
|
|
393
405
|
try {
|
|
394
|
-
const
|
|
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 all commits with hash: ${errorMessage}`, "error");
|
|
421
|
+
return [];
|
|
422
|
+
}
|
|
423
|
+
}
|
|
424
|
+
function commitTouchesAnyPackage(projectDir, commitHash, packageDirs, sharedPackageDirs = []) {
|
|
425
|
+
try {
|
|
426
|
+
const output = execSync("git", ["diff-tree", "--no-commit-id", "--name-only", "-r", commitHash], {
|
|
395
427
|
cwd: projectDir,
|
|
396
428
|
encoding: "utf8"
|
|
397
|
-
}).toString();
|
|
429
|
+
}).toString().trim();
|
|
430
|
+
if (!output) {
|
|
431
|
+
return false;
|
|
432
|
+
}
|
|
433
|
+
const changedFiles = output.split("\n");
|
|
434
|
+
return changedFiles.some((file) => {
|
|
435
|
+
return packageDirs.some((pkgDir) => {
|
|
436
|
+
if (sharedPackageDirs.some((sharedDir) => pkgDir.includes(sharedDir))) {
|
|
437
|
+
return false;
|
|
438
|
+
}
|
|
439
|
+
const normalizedFile = file.replace(/\\/g, "/");
|
|
440
|
+
const normalizedPkgDir = pkgDir.replace(/\\/g, "/").replace(/^\.\//, "");
|
|
441
|
+
return normalizedFile.startsWith(normalizedPkgDir);
|
|
442
|
+
});
|
|
443
|
+
});
|
|
444
|
+
} catch (error) {
|
|
445
|
+
log(
|
|
446
|
+
`Error checking if commit ${commitHash} touches packages: ${error instanceof Error ? error.message : String(error)}`,
|
|
447
|
+
"debug"
|
|
448
|
+
);
|
|
449
|
+
return false;
|
|
450
|
+
}
|
|
451
|
+
}
|
|
452
|
+
function extractRepoLevelChangelogEntries(projectDir, revisionRange, packageDirs, sharedPackageDirs = []) {
|
|
453
|
+
try {
|
|
454
|
+
const allCommits = extractAllChangelogEntriesWithHash(projectDir, revisionRange);
|
|
455
|
+
const repoLevelCommits = allCommits.filter((commit) => {
|
|
456
|
+
const touchesPackage = commitTouchesAnyPackage(projectDir, commit.hash, packageDirs, sharedPackageDirs);
|
|
457
|
+
return !touchesPackage;
|
|
458
|
+
});
|
|
459
|
+
if (repoLevelCommits.length > 0) {
|
|
460
|
+
log(
|
|
461
|
+
`Found ${repoLevelCommits.length} repo-level commit(s) (including shared packages: ${sharedPackageDirs.join(", ")})`,
|
|
462
|
+
"debug"
|
|
463
|
+
);
|
|
464
|
+
}
|
|
465
|
+
return repoLevelCommits.map((c) => c.entry);
|
|
466
|
+
} catch (error) {
|
|
467
|
+
log(`Error extracting repo-level commits: ${error instanceof Error ? error.message : String(error)}`, "warning");
|
|
468
|
+
return [];
|
|
469
|
+
}
|
|
470
|
+
}
|
|
471
|
+
function extractChangelogEntriesFromCommits(projectDir, revisionRange) {
|
|
472
|
+
return extractCommitsFromGitLog(projectDir, revisionRange, true);
|
|
473
|
+
}
|
|
474
|
+
function extractCommitsFromGitLog(projectDir, revisionRange, filterToPath) {
|
|
475
|
+
try {
|
|
476
|
+
const args = ["log", revisionRange, "--pretty=format:%B---COMMIT_DELIMITER---", "--no-merges"];
|
|
477
|
+
if (filterToPath) {
|
|
478
|
+
args.push("--", ".");
|
|
479
|
+
}
|
|
480
|
+
const output = execSync("git", args, { cwd: projectDir, encoding: "utf8" }).toString();
|
|
398
481
|
const commits = output.split("---COMMIT_DELIMITER---").filter((commit) => commit.trim() !== "");
|
|
399
482
|
return commits.map((commit) => parseCommitMessage(commit)).filter((entry) => entry !== null);
|
|
400
483
|
} catch (error) {
|
|
@@ -489,13 +572,16 @@ function extractIssueIds(body) {
|
|
|
489
572
|
|
|
490
573
|
// src/core/versionStrategies.ts
|
|
491
574
|
init_baseError();
|
|
575
|
+
init_commandExecutor();
|
|
492
576
|
|
|
493
577
|
// src/git/commands.ts
|
|
494
578
|
var import_node_process = require("process");
|
|
579
|
+
init_commandExecutor();
|
|
495
580
|
|
|
496
581
|
// src/git/repository.ts
|
|
497
582
|
var import_node_fs = require("fs");
|
|
498
583
|
var import_node_path2 = require("path");
|
|
584
|
+
init_commandExecutor();
|
|
499
585
|
function isGitRepository(directory) {
|
|
500
586
|
const gitDir = (0, import_node_path2.join)(directory, ".git");
|
|
501
587
|
if (!(0, import_node_fs.existsSync)(gitDir)) {
|
|
@@ -700,6 +786,7 @@ To fix this:
|
|
|
700
786
|
}
|
|
701
787
|
|
|
702
788
|
// src/git/tagsAndBranches.ts
|
|
789
|
+
init_commandExecutor();
|
|
703
790
|
function getCommitsLength(pkgRoot, sinceTag) {
|
|
704
791
|
try {
|
|
705
792
|
let amount;
|
|
@@ -777,28 +864,37 @@ async function getLatestTagForPackage(packageName, versionPrefix, options) {
|
|
|
777
864
|
`Looking for tags for package ${packageName} with prefix ${versionPrefix || "none"}, packageSpecificTags: ${packageSpecificTags}`,
|
|
778
865
|
"debug"
|
|
779
866
|
);
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
867
|
+
let allTags = [];
|
|
868
|
+
try {
|
|
869
|
+
const { execSync: execSync2 } = await Promise.resolve().then(() => (init_commandExecutor(), commandExecutor_exports));
|
|
870
|
+
const tagsOutput = execSync2("git", ["tag", "-l"], { cwd: process.cwd() });
|
|
871
|
+
allTags = tagsOutput.toString().trim().split("\n").filter((tag) => tag.length > 0);
|
|
872
|
+
} catch (err) {
|
|
873
|
+
log(`Error getting tags: ${err instanceof Error ? err.message : String(err)}`, "error");
|
|
874
|
+
}
|
|
875
|
+
log(`Retrieved ${allTags.length} tags`, "debug");
|
|
784
876
|
if (packageSpecificTags) {
|
|
785
877
|
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
878
|
log(`Using package tag pattern: ${packageTagPattern}`, "debug");
|
|
787
879
|
const packageTagRegex = new RegExp(`^${packageTagPattern}$`);
|
|
788
880
|
let packageTags = allTags.filter((tag) => packageTagRegex.test(tag));
|
|
881
|
+
log(`Found ${packageTags.length} matching tags for ${packageName}`, "debug");
|
|
789
882
|
if (packageTags.length > 0) {
|
|
790
883
|
const chronologicalFirst = packageTags[0];
|
|
884
|
+
void chronologicalFirst;
|
|
791
885
|
const sortedPackageTags2 = [...packageTags].sort((a, b) => {
|
|
792
886
|
let versionA = "";
|
|
793
887
|
let versionB = "";
|
|
794
888
|
if (a.includes("@")) {
|
|
795
|
-
const
|
|
889
|
+
const parts = a.split("@");
|
|
890
|
+
const afterAt = parts[parts.length - 1] || "";
|
|
796
891
|
versionA = afterAt.replace(new RegExp(`^${escapeRegExp(versionPrefix || "")}`), "");
|
|
797
892
|
} else {
|
|
798
893
|
versionA = a.replace(new RegExp(`^${escapeRegExp(packageName)}`), "").replace(new RegExp(`^${escapeRegExp(versionPrefix || "")}`), "");
|
|
799
894
|
}
|
|
800
895
|
if (b.includes("@")) {
|
|
801
|
-
const
|
|
896
|
+
const parts = b.split("@");
|
|
897
|
+
const afterAtB = parts[parts.length - 1] || "";
|
|
802
898
|
versionB = afterAtB.replace(new RegExp(`^${escapeRegExp(versionPrefix || "")}`), "");
|
|
803
899
|
} else {
|
|
804
900
|
versionB = b.replace(new RegExp(`^${escapeRegExp(packageName)}`), "").replace(new RegExp(`^${escapeRegExp(versionPrefix || "")}`), "");
|
|
@@ -809,12 +905,6 @@ async function getLatestTagForPackage(packageName, versionPrefix, options) {
|
|
|
809
905
|
});
|
|
810
906
|
log(`Found ${packageTags.length} package tags using configured pattern`, "debug");
|
|
811
907
|
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
908
|
return sortedPackageTags2[0];
|
|
819
909
|
}
|
|
820
910
|
if (versionPrefix) {
|
|
@@ -822,9 +912,11 @@ async function getLatestTagForPackage(packageName, versionPrefix, options) {
|
|
|
822
912
|
packageTags = allTags.filter((tag) => pattern1.test(tag));
|
|
823
913
|
if (packageTags.length > 0) {
|
|
824
914
|
const sortedPackageTags2 = [...packageTags].sort((a, b) => {
|
|
825
|
-
const
|
|
915
|
+
const aParts = a.split("@");
|
|
916
|
+
const afterAt = aParts[aParts.length - 1] || "";
|
|
826
917
|
const versionA = afterAt.replace(new RegExp(`^${escapeRegExp(versionPrefix || "")}`), "");
|
|
827
|
-
const
|
|
918
|
+
const bParts = b.split("@");
|
|
919
|
+
const afterAtB = bParts[bParts.length - 1] || "";
|
|
828
920
|
const versionB = afterAtB.replace(new RegExp(`^${escapeRegExp(versionPrefix || "")}`), "");
|
|
829
921
|
const cleanVersionA = import_semver.default.clean(versionA) || "0.0.0";
|
|
830
922
|
const cleanVersionB = import_semver.default.clean(versionB) || "0.0.0";
|
|
@@ -840,8 +932,10 @@ async function getLatestTagForPackage(packageName, versionPrefix, options) {
|
|
|
840
932
|
packageTags = allTags.filter((tag) => pattern2.test(tag));
|
|
841
933
|
if (packageTags.length > 0) {
|
|
842
934
|
const sortedPackageTags2 = [...packageTags].sort((a, b) => {
|
|
843
|
-
const
|
|
844
|
-
const
|
|
935
|
+
const aParts = a.split("@");
|
|
936
|
+
const versionA = import_semver.default.clean(aParts[aParts.length - 1] || "") || "0.0.0";
|
|
937
|
+
const bParts = b.split("@");
|
|
938
|
+
const versionB = import_semver.default.clean(bParts[bParts.length - 1] || "") || "0.0.0";
|
|
845
939
|
return import_semver.default.rcompare(versionA, versionB);
|
|
846
940
|
});
|
|
847
941
|
log(`Found ${packageTags.length} package tags using pattern: ${versionPrefix}packageName@...`, "debug");
|
|
@@ -861,8 +955,10 @@ async function getLatestTagForPackage(packageName, versionPrefix, options) {
|
|
|
861
955
|
return "";
|
|
862
956
|
}
|
|
863
957
|
const sortedPackageTags = [...packageTags].sort((a, b) => {
|
|
864
|
-
const
|
|
865
|
-
const
|
|
958
|
+
const aParts = a.split("@");
|
|
959
|
+
const versionA = import_semver.default.clean(aParts[aParts.length - 1] || "") || "0.0.0";
|
|
960
|
+
const bParts = b.split("@");
|
|
961
|
+
const versionB = import_semver.default.clean(bParts[bParts.length - 1] || "") || "0.0.0";
|
|
866
962
|
return import_semver.default.rcompare(versionA, versionB);
|
|
867
963
|
});
|
|
868
964
|
log(`Found ${packageTags.length} package tags for ${packageName}`, "debug");
|
|
@@ -1039,6 +1135,7 @@ var import_config3 = require("@releasekit/config");
|
|
|
1039
1135
|
var import_semver2 = __toESM(require("semver"), 1);
|
|
1040
1136
|
|
|
1041
1137
|
// src/git/tagVerification.ts
|
|
1138
|
+
init_commandExecutor();
|
|
1042
1139
|
function verifyTag(tagName, cwd4) {
|
|
1043
1140
|
if (!tagName || tagName.trim() === "") {
|
|
1044
1141
|
return { exists: false, reachable: false, error: "Empty tag name" };
|
|
@@ -1142,12 +1239,17 @@ var VersionMismatchError = class extends Error {
|
|
|
1142
1239
|
this.name = "VersionMismatchError";
|
|
1143
1240
|
}
|
|
1144
1241
|
};
|
|
1145
|
-
async function getBestVersionSource(tagName, packageVersion, cwd4, mismatchStrategy = "error") {
|
|
1242
|
+
async function getBestVersionSource(tagName, packageVersion, cwd4, mismatchStrategy = "error", strictReachable = false) {
|
|
1146
1243
|
if (!tagName?.trim()) {
|
|
1147
1244
|
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
1245
|
}
|
|
1149
1246
|
const verification = verifyTag(tagName, cwd4);
|
|
1150
1247
|
if (!verification.exists || !verification.reachable) {
|
|
1248
|
+
if (strictReachable) {
|
|
1249
|
+
throw new Error(
|
|
1250
|
+
`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.`
|
|
1251
|
+
);
|
|
1252
|
+
}
|
|
1151
1253
|
if (packageVersion) {
|
|
1152
1254
|
log(
|
|
1153
1255
|
`Git tag '${tagName}' unreachable (${verification.error}), using package version: ${packageVersion}`,
|
|
@@ -1253,7 +1355,8 @@ async function calculateVersion(config, options) {
|
|
|
1253
1355
|
prereleaseIdentifier: configPrereleaseIdentifier,
|
|
1254
1356
|
branchPattern,
|
|
1255
1357
|
baseBranch,
|
|
1256
|
-
mismatchStrategy
|
|
1358
|
+
mismatchStrategy,
|
|
1359
|
+
strictReachable
|
|
1257
1360
|
} = config;
|
|
1258
1361
|
const {
|
|
1259
1362
|
latestTag,
|
|
@@ -1298,7 +1401,13 @@ async function calculateVersion(config, options) {
|
|
|
1298
1401
|
const packageDir = pkgPath || (0, import_node_process2.cwd)();
|
|
1299
1402
|
const manifestResult = getVersionFromManifests(packageDir);
|
|
1300
1403
|
const packageVersion = manifestResult.manifestFound && manifestResult.version ? manifestResult.version : void 0;
|
|
1301
|
-
versionSource = await getBestVersionSource(
|
|
1404
|
+
versionSource = await getBestVersionSource(
|
|
1405
|
+
latestTag,
|
|
1406
|
+
packageVersion,
|
|
1407
|
+
packageDir,
|
|
1408
|
+
mismatchStrategy,
|
|
1409
|
+
strictReachable
|
|
1410
|
+
);
|
|
1302
1411
|
log(`Using version source: ${versionSource.source} (${versionSource.reason})`, "info");
|
|
1303
1412
|
}
|
|
1304
1413
|
const specifiedType = type;
|
|
@@ -1540,6 +1649,11 @@ var PackageProcessor = class {
|
|
|
1540
1649
|
if (verification.exists && verification.reachable) {
|
|
1541
1650
|
revisionRange = `${latestTag}..HEAD`;
|
|
1542
1651
|
} else {
|
|
1652
|
+
if (this.config.strictReachable) {
|
|
1653
|
+
throw new Error(
|
|
1654
|
+
`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.`
|
|
1655
|
+
);
|
|
1656
|
+
}
|
|
1543
1657
|
log(`Tag ${latestTag} is unreachable (${verification.error}), using all commits for changelog`, "debug");
|
|
1544
1658
|
revisionRange = "HEAD";
|
|
1545
1659
|
}
|
|
@@ -1547,6 +1661,19 @@ var PackageProcessor = class {
|
|
|
1547
1661
|
revisionRange = "HEAD";
|
|
1548
1662
|
}
|
|
1549
1663
|
changelogEntries = extractChangelogEntriesFromCommits(pkgPath, revisionRange);
|
|
1664
|
+
const allPackageDirs = packages.map((p) => p.dir);
|
|
1665
|
+
const sharedPackageNames = ["config", "core", "@releasekit/config", "@releasekit/core"];
|
|
1666
|
+
const sharedPackageDirs = packages.filter((p) => sharedPackageNames.includes(p.packageJson.name)).map((p) => p.dir);
|
|
1667
|
+
const repoLevelEntries = extractRepoLevelChangelogEntries(
|
|
1668
|
+
pkgPath,
|
|
1669
|
+
revisionRange,
|
|
1670
|
+
allPackageDirs,
|
|
1671
|
+
sharedPackageDirs
|
|
1672
|
+
);
|
|
1673
|
+
if (repoLevelEntries.length > 0) {
|
|
1674
|
+
log(`Adding ${repoLevelEntries.length} repo-level commit(s) to ${name} changelog`, "debug");
|
|
1675
|
+
changelogEntries = [...repoLevelEntries, ...changelogEntries];
|
|
1676
|
+
}
|
|
1550
1677
|
if (changelogEntries.length === 0) {
|
|
1551
1678
|
changelogEntries = [
|
|
1552
1679
|
{
|
|
@@ -1855,6 +1982,11 @@ function createSyncStrategy(config) {
|
|
|
1855
1982
|
});
|
|
1856
1983
|
revisionRange = `${latestTag}..HEAD`;
|
|
1857
1984
|
} catch {
|
|
1985
|
+
if (config.strictReachable) {
|
|
1986
|
+
throw new Error(
|
|
1987
|
+
`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.`
|
|
1988
|
+
);
|
|
1989
|
+
}
|
|
1858
1990
|
log(`Tag ${latestTag} doesn't exist, using all commits for changelog`, "debug");
|
|
1859
1991
|
revisionRange = "HEAD";
|
|
1860
1992
|
}
|
|
@@ -1974,6 +2106,11 @@ function createSingleStrategy(config) {
|
|
|
1974
2106
|
});
|
|
1975
2107
|
revisionRange = `${latestTag}..HEAD`;
|
|
1976
2108
|
} catch {
|
|
2109
|
+
if (config.strictReachable) {
|
|
2110
|
+
throw new Error(
|
|
2111
|
+
`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.`
|
|
2112
|
+
);
|
|
2113
|
+
}
|
|
1977
2114
|
log(`Tag ${latestTag} doesn't exist, using all commits for changelog`, "debug");
|
|
1978
2115
|
revisionRange = "HEAD";
|
|
1979
2116
|
}
|
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,86 @@ 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|$)/;
|
|
1134
|
-
function
|
|
1171
|
+
function extractAllChangelogEntriesWithHash(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 all commits with hash: ${errorMessage}`, "error");
|
|
1188
|
+
return [];
|
|
1189
|
+
}
|
|
1190
|
+
}
|
|
1191
|
+
function commitTouchesAnyPackage(projectDir, commitHash, packageDirs, sharedPackageDirs = []) {
|
|
1135
1192
|
try {
|
|
1136
|
-
const output = execSync("git", ["
|
|
1193
|
+
const output = execSync("git", ["diff-tree", "--no-commit-id", "--name-only", "-r", commitHash], {
|
|
1137
1194
|
cwd: projectDir,
|
|
1138
1195
|
encoding: "utf8"
|
|
1139
|
-
}).toString();
|
|
1196
|
+
}).toString().trim();
|
|
1197
|
+
if (!output) {
|
|
1198
|
+
return false;
|
|
1199
|
+
}
|
|
1200
|
+
const changedFiles = output.split("\n");
|
|
1201
|
+
return changedFiles.some((file) => {
|
|
1202
|
+
return packageDirs.some((pkgDir) => {
|
|
1203
|
+
if (sharedPackageDirs.some((sharedDir) => pkgDir.includes(sharedDir))) {
|
|
1204
|
+
return false;
|
|
1205
|
+
}
|
|
1206
|
+
const normalizedFile = file.replace(/\\/g, "/");
|
|
1207
|
+
const normalizedPkgDir = pkgDir.replace(/\\/g, "/").replace(/^\.\//, "");
|
|
1208
|
+
return normalizedFile.startsWith(normalizedPkgDir);
|
|
1209
|
+
});
|
|
1210
|
+
});
|
|
1211
|
+
} catch (error) {
|
|
1212
|
+
log(
|
|
1213
|
+
`Error checking if commit ${commitHash} touches packages: ${error instanceof Error ? error.message : String(error)}`,
|
|
1214
|
+
"debug"
|
|
1215
|
+
);
|
|
1216
|
+
return false;
|
|
1217
|
+
}
|
|
1218
|
+
}
|
|
1219
|
+
function extractRepoLevelChangelogEntries(projectDir, revisionRange, packageDirs, sharedPackageDirs = []) {
|
|
1220
|
+
try {
|
|
1221
|
+
const allCommits = extractAllChangelogEntriesWithHash(projectDir, revisionRange);
|
|
1222
|
+
const repoLevelCommits = allCommits.filter((commit) => {
|
|
1223
|
+
const touchesPackage = commitTouchesAnyPackage(projectDir, commit.hash, packageDirs, sharedPackageDirs);
|
|
1224
|
+
return !touchesPackage;
|
|
1225
|
+
});
|
|
1226
|
+
if (repoLevelCommits.length > 0) {
|
|
1227
|
+
log(
|
|
1228
|
+
`Found ${repoLevelCommits.length} repo-level commit(s) (including shared packages: ${sharedPackageDirs.join(", ")})`,
|
|
1229
|
+
"debug"
|
|
1230
|
+
);
|
|
1231
|
+
}
|
|
1232
|
+
return repoLevelCommits.map((c) => c.entry);
|
|
1233
|
+
} catch (error) {
|
|
1234
|
+
log(`Error extracting repo-level commits: ${error instanceof Error ? error.message : String(error)}`, "warning");
|
|
1235
|
+
return [];
|
|
1236
|
+
}
|
|
1237
|
+
}
|
|
1238
|
+
function extractChangelogEntriesFromCommits(projectDir, revisionRange) {
|
|
1239
|
+
return extractCommitsFromGitLog(projectDir, revisionRange, true);
|
|
1240
|
+
}
|
|
1241
|
+
function extractCommitsFromGitLog(projectDir, revisionRange, filterToPath) {
|
|
1242
|
+
try {
|
|
1243
|
+
const args = ["log", revisionRange, "--pretty=format:%B---COMMIT_DELIMITER---", "--no-merges"];
|
|
1244
|
+
if (filterToPath) {
|
|
1245
|
+
args.push("--", ".");
|
|
1246
|
+
}
|
|
1247
|
+
const output = execSync("git", args, { cwd: projectDir, encoding: "utf8" }).toString();
|
|
1140
1248
|
const commits = output.split("---COMMIT_DELIMITER---").filter((commit) => commit.trim() !== "");
|
|
1141
1249
|
return commits.map((commit) => parseCommitMessage(commit)).filter((entry) => entry !== null);
|
|
1142
1250
|
} catch (error) {
|
|
@@ -1229,8 +1337,12 @@ function extractIssueIds(body) {
|
|
|
1229
1337
|
return issueIds;
|
|
1230
1338
|
}
|
|
1231
1339
|
|
|
1340
|
+
// src/core/versionStrategies.ts
|
|
1341
|
+
init_commandExecutor();
|
|
1342
|
+
|
|
1232
1343
|
// src/git/commands.ts
|
|
1233
1344
|
var import_node_process2 = require("process");
|
|
1345
|
+
init_commandExecutor();
|
|
1234
1346
|
async function gitAdd(files) {
|
|
1235
1347
|
return execAsync("git", ["add", ...files]);
|
|
1236
1348
|
}
|
|
@@ -1535,6 +1647,11 @@ var PackageProcessor = class {
|
|
|
1535
1647
|
if (verification.exists && verification.reachable) {
|
|
1536
1648
|
revisionRange = `${latestTag}..HEAD`;
|
|
1537
1649
|
} else {
|
|
1650
|
+
if (this.config.strictReachable) {
|
|
1651
|
+
throw new Error(
|
|
1652
|
+
`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.`
|
|
1653
|
+
);
|
|
1654
|
+
}
|
|
1538
1655
|
log(`Tag ${latestTag} is unreachable (${verification.error}), using all commits for changelog`, "debug");
|
|
1539
1656
|
revisionRange = "HEAD";
|
|
1540
1657
|
}
|
|
@@ -1542,6 +1659,19 @@ var PackageProcessor = class {
|
|
|
1542
1659
|
revisionRange = "HEAD";
|
|
1543
1660
|
}
|
|
1544
1661
|
changelogEntries = extractChangelogEntriesFromCommits(pkgPath, revisionRange);
|
|
1662
|
+
const allPackageDirs = packages.map((p) => p.dir);
|
|
1663
|
+
const sharedPackageNames = ["config", "core", "@releasekit/config", "@releasekit/core"];
|
|
1664
|
+
const sharedPackageDirs = packages.filter((p) => sharedPackageNames.includes(p.packageJson.name)).map((p) => p.dir);
|
|
1665
|
+
const repoLevelEntries = extractRepoLevelChangelogEntries(
|
|
1666
|
+
pkgPath,
|
|
1667
|
+
revisionRange,
|
|
1668
|
+
allPackageDirs,
|
|
1669
|
+
sharedPackageDirs
|
|
1670
|
+
);
|
|
1671
|
+
if (repoLevelEntries.length > 0) {
|
|
1672
|
+
log(`Adding ${repoLevelEntries.length} repo-level commit(s) to ${name} changelog`, "debug");
|
|
1673
|
+
changelogEntries = [...repoLevelEntries, ...changelogEntries];
|
|
1674
|
+
}
|
|
1545
1675
|
if (changelogEntries.length === 0) {
|
|
1546
1676
|
changelogEntries = [
|
|
1547
1677
|
{
|
|
@@ -1850,6 +1980,11 @@ function createSyncStrategy(config) {
|
|
|
1850
1980
|
});
|
|
1851
1981
|
revisionRange = `${latestTag}..HEAD`;
|
|
1852
1982
|
} catch {
|
|
1983
|
+
if (config.strictReachable) {
|
|
1984
|
+
throw new Error(
|
|
1985
|
+
`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.`
|
|
1986
|
+
);
|
|
1987
|
+
}
|
|
1853
1988
|
log(`Tag ${latestTag} doesn't exist, using all commits for changelog`, "debug");
|
|
1854
1989
|
revisionRange = "HEAD";
|
|
1855
1990
|
}
|
|
@@ -1969,6 +2104,11 @@ function createSingleStrategy(config) {
|
|
|
1969
2104
|
});
|
|
1970
2105
|
revisionRange = `${latestTag}..HEAD`;
|
|
1971
2106
|
} catch {
|
|
2107
|
+
if (config.strictReachable) {
|
|
2108
|
+
throw new Error(
|
|
2109
|
+
`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.`
|
|
2110
|
+
);
|
|
2111
|
+
}
|
|
1972
2112
|
log(`Tag ${latestTag} doesn't exist, using all commits for changelog`, "debug");
|
|
1973
2113
|
revisionRange = "HEAD";
|
|
1974
2114
|
}
|
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-25A2IEAC.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,
|