package-versioner 0.7.1 → 0.7.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +85 -6
- package/dist/index.cjs +246 -111
- package/dist/index.js +246 -111
- package/docs/versioning.md +182 -16
- package/package-versioner.schema.json +5 -6
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -92,14 +92,14 @@ For detailed examples of how to use this in CI/CD pipelines, see [CI/CD Integrat
|
|
|
92
92
|
|
|
93
93
|
## Configuration
|
|
94
94
|
|
|
95
|
-
Customize
|
|
95
|
+
Customize behaviour by creating a `version.config.json` file in your project root:
|
|
96
96
|
|
|
97
97
|
```json
|
|
98
98
|
{
|
|
99
99
|
"preset": "angular",
|
|
100
100
|
"versionPrefix": "v",
|
|
101
|
-
"tagTemplate": "${prefix}${version}",
|
|
102
|
-
"
|
|
101
|
+
"tagTemplate": "${packageName}@${prefix}${version}",
|
|
102
|
+
"packageSpecificTags": true,
|
|
103
103
|
"commitMessage": "chore: release ${packageName}@${version} [skip ci]",
|
|
104
104
|
"updateChangelog": true,
|
|
105
105
|
"changelogFormat": "keep-a-changelog",
|
|
@@ -108,7 +108,7 @@ Customize behavior by creating a `version.config.json` file in your project root
|
|
|
108
108
|
"docs",
|
|
109
109
|
"e2e"
|
|
110
110
|
],
|
|
111
|
-
"packages": ["
|
|
111
|
+
"packages": ["@mycompany/*"],
|
|
112
112
|
"mainPackage": "primary-package",
|
|
113
113
|
"cargo": {
|
|
114
114
|
"enabled": true,
|
|
@@ -133,13 +133,92 @@ Customize behavior by creating a `version.config.json` file in your project root
|
|
|
133
133
|
#### Monorepo-Specific Options
|
|
134
134
|
- `synced`: Whether all packages should be versioned together (default: true)
|
|
135
135
|
- `skip`: Array of package names to exclude from versioning
|
|
136
|
-
- `packages`:
|
|
136
|
+
- `packages`: Array of package names or patterns to target for versioning. Supports exact names, scope wildcards, and global wildcards (e.g., ["@scope/package-a", "@scope/*", "*"])
|
|
137
137
|
- `mainPackage`: Package name whose commit history should drive version determination
|
|
138
|
-
- `
|
|
138
|
+
- `packageSpecificTags`: Whether to enable package-specific tagging behaviour (default: false)
|
|
139
139
|
- `updateInternalDependencies`: How to update internal dependencies ("patch", "minor", "major", or "inherit")
|
|
140
140
|
|
|
141
141
|
For more details on CI/CD integration and advanced usage, see [CI/CD Integration](./docs/CI_CD_INTEGRATION.md).
|
|
142
142
|
|
|
143
|
+
### Package Targeting
|
|
144
|
+
|
|
145
|
+
The `packages` configuration option allows you to specify which packages should be processed for versioning. It supports several pattern types:
|
|
146
|
+
|
|
147
|
+
#### Exact Package Names
|
|
148
|
+
```json
|
|
149
|
+
{
|
|
150
|
+
"packages": ["@mycompany/core", "@mycompany/utils", "standalone-package"]
|
|
151
|
+
}
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
#### Scope Wildcards
|
|
155
|
+
Target all packages within a specific scope:
|
|
156
|
+
```json
|
|
157
|
+
{
|
|
158
|
+
"packages": ["@mycompany/*"]
|
|
159
|
+
}
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
#### Global Wildcard
|
|
163
|
+
Target all packages in the workspace:
|
|
164
|
+
```json
|
|
165
|
+
{
|
|
166
|
+
"packages": ["*"]
|
|
167
|
+
}
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
#### Mixed Patterns
|
|
171
|
+
Combine different pattern types:
|
|
172
|
+
```json
|
|
173
|
+
{
|
|
174
|
+
"packages": ["@mycompany/*", "@utils/logger", "legacy-package"]
|
|
175
|
+
}
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
**Note**: Package discovery is handled by your workspace configuration (pnpm-workspace.yaml, package.json workspaces, etc.). The `packages` option only filters which discovered packages to process.
|
|
179
|
+
|
|
180
|
+
### Package-Specific Tagging
|
|
181
|
+
|
|
182
|
+
The `packageSpecificTags` option controls whether the tool creates and searches for package-specific Git tags:
|
|
183
|
+
|
|
184
|
+
- **When `false` (default)**: Creates global tags like `v1.2.3` and searches for the latest global tag
|
|
185
|
+
- **When `true`**: Creates package-specific tags like `@scope/package-a@v1.2.3` and searches for package-specific tags
|
|
186
|
+
|
|
187
|
+
This option works in conjunction with `tagTemplate` to control tag formatting. The `tagTemplate` is used for all tag creation, with the `packageSpecificTags` boolean controlling whether the `${packageName}` variable is populated:
|
|
188
|
+
|
|
189
|
+
- When `packageSpecificTags` is `false`: The `${packageName}` variable is empty, so templates should use `${prefix}${version}`
|
|
190
|
+
- When `packageSpecificTags` is `true`: The `${packageName}` variable contains the package name
|
|
191
|
+
|
|
192
|
+
**Examples:**
|
|
193
|
+
|
|
194
|
+
For single-package repositories or synced monorepos:
|
|
195
|
+
```json
|
|
196
|
+
{
|
|
197
|
+
"packageSpecificTags": true,
|
|
198
|
+
"tagTemplate": "${packageName}@${prefix}${version}"
|
|
199
|
+
}
|
|
200
|
+
```
|
|
201
|
+
Creates tags like `my-package@v1.2.3`
|
|
202
|
+
|
|
203
|
+
For global versioning:
|
|
204
|
+
```json
|
|
205
|
+
{
|
|
206
|
+
"packageSpecificTags": false,
|
|
207
|
+
"tagTemplate": "${prefix}${version}"
|
|
208
|
+
}
|
|
209
|
+
```
|
|
210
|
+
Creates tags like `v1.2.3`
|
|
211
|
+
|
|
212
|
+
**Important Notes:**
|
|
213
|
+
- In **synced mode** with a single package, `packageSpecificTags: true` will use the package name even though all packages are versioned together
|
|
214
|
+
- In **synced mode** with multiple packages, package names are not used regardless of the setting
|
|
215
|
+
- In **async mode**, each package gets its own tag when `packageSpecificTags` is enabled
|
|
216
|
+
|
|
217
|
+
With package-specific tagging enabled, the tool will:
|
|
218
|
+
1. Look for existing tags matching the configured pattern for each package
|
|
219
|
+
2. Create new tags using the same pattern when releasing
|
|
220
|
+
3. Fall back to global tag lookup if no package-specific tags are found
|
|
221
|
+
|
|
143
222
|
## How Versioning Works
|
|
144
223
|
|
|
145
224
|
`package-versioner` determines the next version based on your configuration (`version.config.json`). The two main approaches are:
|
package/dist/index.cjs
CHANGED
|
@@ -138,7 +138,23 @@ function extractChangelogEntriesFromCommits(projectDir, revisionRange) {
|
|
|
138
138
|
const commits = output.split("---COMMIT_DELIMITER---").filter((commit) => commit.trim() !== "");
|
|
139
139
|
return commits.map((commit) => parseCommitMessage(commit)).filter((entry) => entry !== null);
|
|
140
140
|
} catch (error) {
|
|
141
|
-
|
|
141
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
142
|
+
if (errorMessage.includes("ambiguous argument") && errorMessage.includes("unknown revision")) {
|
|
143
|
+
const tagName = revisionRange.split("..")[0] || revisionRange;
|
|
144
|
+
if (tagName.startsWith("v") && !tagName.includes("@")) {
|
|
145
|
+
log(
|
|
146
|
+
`Error: Tag "${tagName}" not found. If you're using package-specific tags (like "package-name@v1.0.0"), you may need to configure "tagTemplate" in your version.config.json to use: \${packageName}@\${prefix}\${version}`,
|
|
147
|
+
"error"
|
|
148
|
+
);
|
|
149
|
+
} else {
|
|
150
|
+
log(
|
|
151
|
+
`Error: Tag or revision "${tagName}" not found in the repository. Please check if this tag exists or if you need to fetch it from the remote.`,
|
|
152
|
+
"error"
|
|
153
|
+
);
|
|
154
|
+
}
|
|
155
|
+
} else {
|
|
156
|
+
log(`Error extracting commits: ${errorMessage}`, "error");
|
|
157
|
+
}
|
|
142
158
|
return [];
|
|
143
159
|
}
|
|
144
160
|
}
|
|
@@ -788,38 +804,42 @@ var import_git_semver_tags = require("git-semver-tags");
|
|
|
788
804
|
function escapeRegExp(string) {
|
|
789
805
|
return string.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
790
806
|
}
|
|
791
|
-
function
|
|
792
|
-
|
|
793
|
-
version,
|
|
794
|
-
prefix: versionPrefix || "",
|
|
795
|
-
packageName: packageName || ""
|
|
796
|
-
};
|
|
797
|
-
const template = packageName ? packageTagTemplate : tagTemplate;
|
|
798
|
-
return createTemplateString(template, variables);
|
|
799
|
-
}
|
|
800
|
-
function formatVersionPrefix(versionPrefix, scope) {
|
|
801
|
-
if (!versionPrefix) return "";
|
|
802
|
-
const cleanPrefix = versionPrefix.replace(/\/$/, "");
|
|
803
|
-
if (scope) {
|
|
804
|
-
return `${cleanPrefix}/${scope}`;
|
|
805
|
-
}
|
|
806
|
-
return cleanPrefix;
|
|
807
|
-
}
|
|
808
|
-
function formatCommitMessage(template, version, packageName, scope) {
|
|
809
|
-
return createTemplateString(template, {
|
|
810
|
-
version,
|
|
811
|
-
scope,
|
|
812
|
-
packageName: packageName || ""
|
|
813
|
-
});
|
|
807
|
+
function formatVersionPrefix(prefix) {
|
|
808
|
+
return prefix.endsWith("/") ? prefix.slice(0, -1) : prefix;
|
|
814
809
|
}
|
|
815
|
-
function
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
810
|
+
function formatTag(version, prefix, packageName, template, packageSpecificTags) {
|
|
811
|
+
if ((template == null ? void 0 : template.includes("${packageName}")) && !packageName) {
|
|
812
|
+
log(
|
|
813
|
+
'Warning: Your tagTemplate contains ${packageName} but no package name is available.\nThis will result in an empty package name in the tag (e.g., "@v1.0.0" instead of "my-package@v1.0.0").\n\nTo fix this:\n\u2022 If using synced mode: Set "packageSpecificTags": true in your config to enable package names in tags\n\u2022 If you want global tags: Remove ${packageName} from your tagTemplate (e.g., use "${prefix}${version}")\n\u2022 If using single/async mode: Ensure your package.json has a valid "name" field',
|
|
814
|
+
"warning"
|
|
815
|
+
);
|
|
816
|
+
}
|
|
817
|
+
if (template) {
|
|
818
|
+
return template.replace(/\$\{version\}/g, version).replace(/\$\{prefix\}/g, prefix).replace(/\$\{packageName\}/g, packageName || "");
|
|
819
|
+
}
|
|
820
|
+
if (packageSpecificTags && packageName) {
|
|
821
|
+
return `${packageName}@${prefix}${version}`;
|
|
822
|
+
}
|
|
823
|
+
return `${prefix}${version}`;
|
|
824
|
+
}
|
|
825
|
+
function formatCommitMessage(template, version, packageName, additionalContext) {
|
|
826
|
+
if (template.includes("${packageName}") && !packageName) {
|
|
827
|
+
log(
|
|
828
|
+
'Warning: Your commitMessage template contains ${packageName} but no package name is available.\nThis will result in an empty package name in the commit message (e.g., "Release @v1.0.0").\n\nTo fix this:\n\u2022 If using synced mode: Set "packageSpecificTags": true to enable package names in commits\n\u2022 If you want generic commit messages: Remove ${packageName} from your commitMessage template\n\u2022 If using single/async mode: Ensure your package.json has a valid "name" field',
|
|
829
|
+
"warning"
|
|
830
|
+
);
|
|
831
|
+
}
|
|
832
|
+
let result = template.replace(/\$\{version\}/g, version).replace(/\$\{packageName\}/g, packageName || "");
|
|
833
|
+
if (additionalContext) {
|
|
834
|
+
for (const [key, value] of Object.entries(additionalContext)) {
|
|
835
|
+
const placeholder = `\${${key}}`;
|
|
836
|
+
result = result.replace(
|
|
837
|
+
new RegExp(placeholder.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"), "g"),
|
|
838
|
+
value
|
|
839
|
+
);
|
|
819
840
|
}
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
}, template);
|
|
841
|
+
}
|
|
842
|
+
return result;
|
|
823
843
|
}
|
|
824
844
|
|
|
825
845
|
// src/git/tagsAndBranches.ts
|
|
@@ -862,56 +882,71 @@ async function lastMergeBranchName(branches, baseBranch) {
|
|
|
862
882
|
return null;
|
|
863
883
|
}
|
|
864
884
|
}
|
|
865
|
-
async function getLatestTagForPackage(packageName, versionPrefix) {
|
|
885
|
+
async function getLatestTagForPackage(packageName, versionPrefix, options) {
|
|
866
886
|
try {
|
|
887
|
+
const tagTemplate = (options == null ? void 0 : options.tagTemplate) || "${prefix}${version}";
|
|
888
|
+
const packageSpecificTags = (options == null ? void 0 : options.packageSpecificTags) ?? false;
|
|
867
889
|
const escapedPackageName = escapeRegExp(packageName);
|
|
890
|
+
const escapedPrefix = versionPrefix ? escapeRegExp(versionPrefix) : "";
|
|
868
891
|
log(
|
|
869
|
-
`Looking for tags for package ${packageName} with prefix ${versionPrefix || "none"}`,
|
|
892
|
+
`Looking for tags for package ${packageName} with prefix ${versionPrefix || "none"}, packageSpecificTags: ${packageSpecificTags}`,
|
|
870
893
|
"debug"
|
|
871
894
|
);
|
|
872
895
|
const allTags = await (0, import_git_semver_tags.getSemverTags)({
|
|
873
896
|
tagPrefix: versionPrefix
|
|
874
897
|
});
|
|
875
898
|
log(`Retrieved ${allTags.length} tags: ${allTags.join(", ")}`, "debug");
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
899
|
+
if (packageSpecificTags) {
|
|
900
|
+
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.-]+)?)");
|
|
901
|
+
log(`Using package tag pattern: ${packageTagPattern}`, "debug");
|
|
902
|
+
const packageTagRegex = new RegExp(`^${packageTagPattern}$`);
|
|
903
|
+
let packageTags = allTags.filter((tag) => packageTagRegex.test(tag));
|
|
880
904
|
if (packageTags.length > 0) {
|
|
881
|
-
log(
|
|
882
|
-
`Found ${packageTags.length} package tags using pattern: packageName@${versionPrefix}...`,
|
|
883
|
-
"debug"
|
|
884
|
-
);
|
|
905
|
+
log(`Found ${packageTags.length} package tags using configured pattern`, "debug");
|
|
885
906
|
log(`Using tag: ${packageTags[0]}`, "debug");
|
|
886
907
|
return packageTags[0];
|
|
887
908
|
}
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
909
|
+
if (versionPrefix) {
|
|
910
|
+
const pattern1 = new RegExp(`^${escapedPackageName}@${escapeRegExp(versionPrefix)}`);
|
|
911
|
+
packageTags = allTags.filter((tag) => pattern1.test(tag));
|
|
912
|
+
if (packageTags.length > 0) {
|
|
913
|
+
log(
|
|
914
|
+
`Found ${packageTags.length} package tags using pattern: packageName@${versionPrefix}...`,
|
|
915
|
+
"debug"
|
|
916
|
+
);
|
|
917
|
+
log(`Using tag: ${packageTags[0]}`, "debug");
|
|
918
|
+
return packageTags[0];
|
|
919
|
+
}
|
|
899
920
|
}
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
921
|
+
if (versionPrefix) {
|
|
922
|
+
const pattern2 = new RegExp(`^${escapeRegExp(versionPrefix)}${escapedPackageName}@`);
|
|
923
|
+
packageTags = allTags.filter((tag) => pattern2.test(tag));
|
|
924
|
+
if (packageTags.length > 0) {
|
|
925
|
+
log(
|
|
926
|
+
`Found ${packageTags.length} package tags using pattern: ${versionPrefix}packageName@...`,
|
|
927
|
+
"debug"
|
|
928
|
+
);
|
|
929
|
+
log(`Using tag: ${packageTags[0]}`, "debug");
|
|
930
|
+
return packageTags[0];
|
|
931
|
+
}
|
|
932
|
+
}
|
|
933
|
+
const pattern3 = new RegExp(`^${escapedPackageName}@`);
|
|
934
|
+
packageTags = allTags.filter((tag) => pattern3.test(tag));
|
|
935
|
+
log(`Found ${packageTags.length} package tags for ${packageName}`, "debug");
|
|
936
|
+
if (packageTags.length === 0) {
|
|
937
|
+
log("No matching tags found for pattern: packageName@version", "debug");
|
|
938
|
+
if (allTags.length > 0) {
|
|
939
|
+
log(`Available tags: ${allTags.join(", ")}`, "debug");
|
|
940
|
+
} else {
|
|
941
|
+
log("No tags available in the repository", "debug");
|
|
942
|
+
}
|
|
908
943
|
} else {
|
|
909
|
-
log(
|
|
944
|
+
log(`Using tag: ${packageTags[0]}`, "debug");
|
|
910
945
|
}
|
|
911
|
-
|
|
912
|
-
log(`Using tag: ${packageTags[0]}`, "debug");
|
|
946
|
+
return packageTags[0] || "";
|
|
913
947
|
}
|
|
914
|
-
|
|
948
|
+
log(`Package-specific tags disabled for ${packageName}, falling back to global tags`, "debug");
|
|
949
|
+
return "";
|
|
915
950
|
} catch (error) {
|
|
916
951
|
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
917
952
|
log(`Failed to get latest tag for package ${packageName}: ${errorMessage}`, "error");
|
|
@@ -1446,32 +1481,90 @@ function bumpVersion(currentVersion, bumpType, prereleaseIdentifier) {
|
|
|
1446
1481
|
// src/core/versionCalculator.ts
|
|
1447
1482
|
async function calculateVersion(config, options) {
|
|
1448
1483
|
const {
|
|
1449
|
-
|
|
1450
|
-
|
|
1451
|
-
versionPrefix
|
|
1484
|
+
type: configType,
|
|
1485
|
+
preset = "angular",
|
|
1486
|
+
versionPrefix,
|
|
1487
|
+
prereleaseIdentifier: configPrereleaseIdentifier,
|
|
1452
1488
|
branchPattern,
|
|
1453
|
-
baseBranch
|
|
1454
|
-
|
|
1489
|
+
baseBranch
|
|
1490
|
+
} = config;
|
|
1491
|
+
const {
|
|
1492
|
+
latestTag,
|
|
1493
|
+
name,
|
|
1455
1494
|
path: pkgPath,
|
|
1456
|
-
|
|
1495
|
+
type: optionsType,
|
|
1496
|
+
prereleaseIdentifier: optionsPrereleaseIdentifier
|
|
1457
1497
|
} = options;
|
|
1458
|
-
const
|
|
1498
|
+
const type = optionsType || configType;
|
|
1499
|
+
const prereleaseIdentifier = optionsPrereleaseIdentifier || configPrereleaseIdentifier;
|
|
1459
1500
|
const initialVersion = "0.1.0";
|
|
1501
|
+
const hasNoTags = !latestTag || latestTag.trim() === "";
|
|
1460
1502
|
const normalizedPrereleaseId = normalizePrereleaseIdentifier(prereleaseIdentifier, config);
|
|
1461
1503
|
try {
|
|
1462
1504
|
let determineTagSearchPattern2 = function(packageName, prefix) {
|
|
1463
|
-
if (packageName) {
|
|
1464
|
-
|
|
1465
|
-
const escapedPrefix = escapeRegExp(prefix);
|
|
1466
|
-
return `${escapedPackageName}[@]?${escapedPrefix}`;
|
|
1505
|
+
if (!packageName) {
|
|
1506
|
+
return prefix;
|
|
1467
1507
|
}
|
|
1468
|
-
return
|
|
1508
|
+
return `${packageName}@${prefix}`;
|
|
1509
|
+
}, escapeRegExp3 = function(string) {
|
|
1510
|
+
return string.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
1469
1511
|
};
|
|
1470
|
-
var determineTagSearchPattern = determineTagSearchPattern2;
|
|
1471
|
-
const
|
|
1472
|
-
const originalPrefix = versionPrefix;
|
|
1512
|
+
var determineTagSearchPattern = determineTagSearchPattern2, escapeRegExp2 = escapeRegExp3;
|
|
1513
|
+
const originalPrefix = versionPrefix || "";
|
|
1473
1514
|
const tagSearchPattern = determineTagSearchPattern2(name, originalPrefix);
|
|
1474
|
-
const escapedTagPattern =
|
|
1515
|
+
const escapedTagPattern = escapeRegExp3(tagSearchPattern);
|
|
1516
|
+
if (!hasNoTags && pkgPath) {
|
|
1517
|
+
const packageDir = pkgPath || (0, import_node_process3.cwd)();
|
|
1518
|
+
const manifestResult = getVersionFromManifests(packageDir);
|
|
1519
|
+
if (manifestResult.manifestFound && manifestResult.version) {
|
|
1520
|
+
const cleanedTag = import_semver2.default.clean(latestTag) || latestTag;
|
|
1521
|
+
const tagVersion = import_semver2.default.clean(cleanedTag.replace(new RegExp(`^${escapedTagPattern}`), "")) || "0.0.0";
|
|
1522
|
+
const packageVersion = manifestResult.version;
|
|
1523
|
+
if (import_semver2.default.gt(packageVersion, tagVersion)) {
|
|
1524
|
+
log(
|
|
1525
|
+
`Warning: Version mismatch detected!
|
|
1526
|
+
\u2022 ${manifestResult.manifestType} version: ${packageVersion}
|
|
1527
|
+
\u2022 Latest Git tag version: ${tagVersion} (from ${latestTag})
|
|
1528
|
+
\u2022 Package version is AHEAD of Git tags
|
|
1529
|
+
|
|
1530
|
+
This usually happens when:
|
|
1531
|
+
\u2022 A version was released but the tag wasn't pushed to the remote repository
|
|
1532
|
+
\u2022 The ${manifestResult.manifestType} was manually updated without creating a corresponding tag
|
|
1533
|
+
\u2022 You're running in CI and the latest tag isn't available yet
|
|
1534
|
+
|
|
1535
|
+
The tool will use the Git tag version (${tagVersion}) as the base for calculation.
|
|
1536
|
+
Expected next version will be based on ${tagVersion}, not ${packageVersion}.
|
|
1537
|
+
|
|
1538
|
+
To fix this mismatch:
|
|
1539
|
+
\u2022 Push missing tags: git push origin --tags
|
|
1540
|
+
\u2022 Or use package version as base by ensuring tags are up to date`,
|
|
1541
|
+
"warning"
|
|
1542
|
+
);
|
|
1543
|
+
} else if (import_semver2.default.gt(tagVersion, packageVersion)) {
|
|
1544
|
+
log(
|
|
1545
|
+
`Warning: Version mismatch detected!
|
|
1546
|
+
\u2022 ${manifestResult.manifestType} version: ${packageVersion}
|
|
1547
|
+
\u2022 Latest Git tag version: ${tagVersion} (from ${latestTag})
|
|
1548
|
+
\u2022 Git tag version is AHEAD of package version
|
|
1549
|
+
|
|
1550
|
+
This usually happens when:
|
|
1551
|
+
\u2022 A release was tagged but the ${manifestResult.manifestType} wasn't updated
|
|
1552
|
+
\u2022 You're on an older branch that hasn't been updated with the latest version
|
|
1553
|
+
\u2022 Automated release process created tags but didn't update manifest files
|
|
1554
|
+
\u2022 You pulled tags but not the corresponding commits that update the package version
|
|
1555
|
+
|
|
1556
|
+
The tool will use the Git tag version (${tagVersion}) as the base for calculation.
|
|
1557
|
+
This will likely result in a version that's already been released.
|
|
1558
|
+
|
|
1559
|
+
To fix this mismatch:
|
|
1560
|
+
\u2022 Update ${manifestResult.manifestType}: Set version to ${tagVersion} or higher
|
|
1561
|
+
\u2022 Or checkout the branch/commit that corresponds to the tag
|
|
1562
|
+
\u2022 Or ensure your branch is up to date with the latest changes`,
|
|
1563
|
+
"warning"
|
|
1564
|
+
);
|
|
1565
|
+
}
|
|
1566
|
+
}
|
|
1567
|
+
}
|
|
1475
1568
|
const specifiedType = type;
|
|
1476
1569
|
if (specifiedType) {
|
|
1477
1570
|
if (hasNoTags) {
|
|
@@ -1618,13 +1711,39 @@ function calculateNextVersion(version, manifestType, name, releaseType, prerelea
|
|
|
1618
1711
|
return result || initialVersion;
|
|
1619
1712
|
}
|
|
1620
1713
|
|
|
1714
|
+
// src/utils/packageMatching.ts
|
|
1715
|
+
function matchesPackageTarget(packageName, target) {
|
|
1716
|
+
if (packageName === target) {
|
|
1717
|
+
return true;
|
|
1718
|
+
}
|
|
1719
|
+
if (target.endsWith("/*")) {
|
|
1720
|
+
const scope = target.slice(0, -2);
|
|
1721
|
+
if (scope.startsWith("@")) {
|
|
1722
|
+
return packageName.startsWith(`${scope}/`);
|
|
1723
|
+
}
|
|
1724
|
+
return packageName.startsWith(`${scope}/`);
|
|
1725
|
+
}
|
|
1726
|
+
if (target === "*") {
|
|
1727
|
+
return true;
|
|
1728
|
+
}
|
|
1729
|
+
return false;
|
|
1730
|
+
}
|
|
1731
|
+
function shouldProcessPackage(packageName, targets = [], skip = []) {
|
|
1732
|
+
if (skip.includes(packageName)) {
|
|
1733
|
+
return false;
|
|
1734
|
+
}
|
|
1735
|
+
if (targets.length === 0) {
|
|
1736
|
+
return true;
|
|
1737
|
+
}
|
|
1738
|
+
return targets.some((target) => matchesPackageTarget(packageName, target));
|
|
1739
|
+
}
|
|
1740
|
+
|
|
1621
1741
|
// src/package/packageProcessor.ts
|
|
1622
1742
|
var PackageProcessor = class {
|
|
1623
1743
|
skip;
|
|
1624
1744
|
targets;
|
|
1625
1745
|
versionPrefix;
|
|
1626
1746
|
tagTemplate;
|
|
1627
|
-
packageTagTemplate;
|
|
1628
1747
|
commitMessageTemplate;
|
|
1629
1748
|
dryRun;
|
|
1630
1749
|
skipHooks;
|
|
@@ -1637,7 +1756,6 @@ var PackageProcessor = class {
|
|
|
1637
1756
|
this.targets = options.targets || [];
|
|
1638
1757
|
this.versionPrefix = options.versionPrefix || "v";
|
|
1639
1758
|
this.tagTemplate = options.tagTemplate;
|
|
1640
|
-
this.packageTagTemplate = options.packageTagTemplate;
|
|
1641
1759
|
this.commitMessageTemplate = options.commitMessageTemplate || "";
|
|
1642
1760
|
this.dryRun = options.dryRun || false;
|
|
1643
1761
|
this.skipHooks = options.skipHooks || false;
|
|
@@ -1665,18 +1783,15 @@ var PackageProcessor = class {
|
|
|
1665
1783
|
const pkgsToConsider = packages.filter((pkg) => {
|
|
1666
1784
|
var _a2;
|
|
1667
1785
|
const pkgName = pkg.packageJson.name;
|
|
1668
|
-
|
|
1669
|
-
|
|
1670
|
-
|
|
1671
|
-
|
|
1672
|
-
|
|
1673
|
-
|
|
1674
|
-
|
|
1675
|
-
const isTargeted = this.targets.includes(pkgName);
|
|
1676
|
-
if (!isTargeted) {
|
|
1677
|
-
log(`Package ${pkgName} not in target list, skipping.`, "info");
|
|
1786
|
+
const shouldProcess = shouldProcessPackage(pkgName, this.targets, this.skip);
|
|
1787
|
+
if (!shouldProcess) {
|
|
1788
|
+
if ((_a2 = this.skip) == null ? void 0 : _a2.includes(pkgName)) {
|
|
1789
|
+
log(`Skipping package ${pkgName} as it's in the skip list.`, "info");
|
|
1790
|
+
} else {
|
|
1791
|
+
log(`Package ${pkgName} not in target list, skipping.`, "info");
|
|
1792
|
+
}
|
|
1678
1793
|
}
|
|
1679
|
-
return
|
|
1794
|
+
return shouldProcess;
|
|
1680
1795
|
});
|
|
1681
1796
|
log(`Found ${pkgsToConsider.length} targeted package(s) to process after filtering.`, "info");
|
|
1682
1797
|
if (pkgsToConsider.length === 0) {
|
|
@@ -1689,7 +1804,10 @@ var PackageProcessor = class {
|
|
|
1689
1804
|
const formattedPrefix = formatVersionPrefix(this.versionPrefix);
|
|
1690
1805
|
let latestTagResult = "";
|
|
1691
1806
|
try {
|
|
1692
|
-
latestTagResult = await getLatestTagForPackage(name, this.versionPrefix
|
|
1807
|
+
latestTagResult = await getLatestTagForPackage(name, this.versionPrefix, {
|
|
1808
|
+
tagTemplate: this.tagTemplate,
|
|
1809
|
+
packageSpecificTags: this.fullConfig.packageSpecificTags
|
|
1810
|
+
});
|
|
1693
1811
|
} catch (error) {
|
|
1694
1812
|
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
1695
1813
|
log(
|
|
@@ -1821,7 +1939,7 @@ var PackageProcessor = class {
|
|
|
1821
1939
|
this.versionPrefix,
|
|
1822
1940
|
name,
|
|
1823
1941
|
this.tagTemplate,
|
|
1824
|
-
this.
|
|
1942
|
+
this.fullConfig.packageSpecificTags
|
|
1825
1943
|
);
|
|
1826
1944
|
const tagMessage = `chore(release): ${name} ${nextVersion}`;
|
|
1827
1945
|
addTag(packageTag);
|
|
@@ -1907,16 +2025,9 @@ var PackageProcessor = class {
|
|
|
1907
2025
|
};
|
|
1908
2026
|
|
|
1909
2027
|
// src/core/versionStrategies.ts
|
|
1910
|
-
function
|
|
1911
|
-
var _a;
|
|
2028
|
+
function shouldProcessPackage2(pkg, config, targets = []) {
|
|
1912
2029
|
const pkgName = pkg.packageJson.name;
|
|
1913
|
-
|
|
1914
|
-
return false;
|
|
1915
|
-
}
|
|
1916
|
-
if (!targets || targets.length === 0) {
|
|
1917
|
-
return true;
|
|
1918
|
-
}
|
|
1919
|
-
return targets.includes(pkgName);
|
|
2030
|
+
return shouldProcessPackage(pkgName, targets, config.skip);
|
|
1920
2031
|
}
|
|
1921
2032
|
function createSyncedStrategy(config) {
|
|
1922
2033
|
return async (packages) => {
|
|
@@ -1972,6 +2083,7 @@ function createSyncedStrategy(config) {
|
|
|
1972
2083
|
}
|
|
1973
2084
|
const files = [];
|
|
1974
2085
|
const updatedPackages = [];
|
|
2086
|
+
const processedPaths = /* @__PURE__ */ new Set();
|
|
1975
2087
|
try {
|
|
1976
2088
|
if (packages.root) {
|
|
1977
2089
|
const rootPkgPath = path7.join(packages.root, "package.json");
|
|
@@ -1979,6 +2091,7 @@ function createSyncedStrategy(config) {
|
|
|
1979
2091
|
updatePackageVersion(rootPkgPath, nextVersion);
|
|
1980
2092
|
files.push(rootPkgPath);
|
|
1981
2093
|
updatedPackages.push("root");
|
|
2094
|
+
processedPaths.add(rootPkgPath);
|
|
1982
2095
|
}
|
|
1983
2096
|
} else {
|
|
1984
2097
|
log("Root package path is undefined, skipping root package.json update", "warning");
|
|
@@ -1988,13 +2101,17 @@ function createSyncedStrategy(config) {
|
|
|
1988
2101
|
log(`Failed to update root package.json: ${errMessage}`, "error");
|
|
1989
2102
|
}
|
|
1990
2103
|
for (const pkg of packages.packages) {
|
|
1991
|
-
if (!
|
|
2104
|
+
if (!shouldProcessPackage2(pkg, config)) {
|
|
1992
2105
|
continue;
|
|
1993
2106
|
}
|
|
1994
2107
|
const packageJsonPath = path7.join(pkg.dir, "package.json");
|
|
2108
|
+
if (processedPaths.has(packageJsonPath)) {
|
|
2109
|
+
continue;
|
|
2110
|
+
}
|
|
1995
2111
|
updatePackageVersion(packageJsonPath, nextVersion);
|
|
1996
2112
|
files.push(packageJsonPath);
|
|
1997
2113
|
updatedPackages.push(pkg.packageJson.name);
|
|
2114
|
+
processedPaths.add(packageJsonPath);
|
|
1998
2115
|
}
|
|
1999
2116
|
if (updatedPackages.length > 0) {
|
|
2000
2117
|
log(`Updated ${updatedPackages.length} package(s) to version ${nextVersion}`, "success");
|
|
@@ -2002,8 +2119,25 @@ function createSyncedStrategy(config) {
|
|
|
2002
2119
|
log("No packages were updated", "warning");
|
|
2003
2120
|
return;
|
|
2004
2121
|
}
|
|
2005
|
-
|
|
2006
|
-
|
|
2122
|
+
let tagPackageName = null;
|
|
2123
|
+
let commitPackageName = void 0;
|
|
2124
|
+
if (config.packageSpecificTags && packages.packages.length === 1) {
|
|
2125
|
+
tagPackageName = packages.packages[0].packageJson.name;
|
|
2126
|
+
commitPackageName = packages.packages[0].packageJson.name;
|
|
2127
|
+
}
|
|
2128
|
+
const nextTag = formatTag(
|
|
2129
|
+
nextVersion,
|
|
2130
|
+
formattedPrefix,
|
|
2131
|
+
tagPackageName,
|
|
2132
|
+
tagTemplate,
|
|
2133
|
+
config.packageSpecificTags || false
|
|
2134
|
+
);
|
|
2135
|
+
const formattedCommitMessage = formatCommitMessage(
|
|
2136
|
+
commitMessage,
|
|
2137
|
+
nextVersion,
|
|
2138
|
+
commitPackageName,
|
|
2139
|
+
void 0
|
|
2140
|
+
);
|
|
2007
2141
|
await createGitCommitAndTag(files, nextTag, formattedCommitMessage, skipHooks, dryRun);
|
|
2008
2142
|
} catch (error) {
|
|
2009
2143
|
if (error instanceof VersionError || error instanceof GitError) {
|
|
@@ -2024,7 +2158,6 @@ function createSingleStrategy(config) {
|
|
|
2024
2158
|
mainPackage,
|
|
2025
2159
|
versionPrefix,
|
|
2026
2160
|
tagTemplate,
|
|
2027
|
-
packageTagTemplate,
|
|
2028
2161
|
commitMessage = "chore(release): ${version}",
|
|
2029
2162
|
dryRun,
|
|
2030
2163
|
skipHooks
|
|
@@ -2046,7 +2179,10 @@ function createSingleStrategy(config) {
|
|
|
2046
2179
|
}
|
|
2047
2180
|
const pkgPath = pkg.dir;
|
|
2048
2181
|
const formattedPrefix = formatVersionPrefix(versionPrefix || "v");
|
|
2049
|
-
let latestTagResult = await getLatestTagForPackage(packageName, formattedPrefix
|
|
2182
|
+
let latestTagResult = await getLatestTagForPackage(packageName, formattedPrefix, {
|
|
2183
|
+
tagTemplate,
|
|
2184
|
+
packageSpecificTags: config.packageSpecificTags
|
|
2185
|
+
});
|
|
2050
2186
|
if (!latestTagResult) {
|
|
2051
2187
|
const globalTagResult = await getLatestTag();
|
|
2052
2188
|
latestTagResult = globalTagResult || "";
|
|
@@ -2077,7 +2213,7 @@ function createSingleStrategy(config) {
|
|
|
2077
2213
|
formattedPrefix,
|
|
2078
2214
|
packageName,
|
|
2079
2215
|
tagTemplate,
|
|
2080
|
-
|
|
2216
|
+
config.packageSpecificTags
|
|
2081
2217
|
);
|
|
2082
2218
|
const formattedCommitMessage = formatCommitMessage(commitMessage, nextVersion, packageName);
|
|
2083
2219
|
await createGitCommitAndTag(
|
|
@@ -2110,7 +2246,6 @@ function createAsyncStrategy(config) {
|
|
|
2110
2246
|
targets: config.packages || [],
|
|
2111
2247
|
versionPrefix: config.versionPrefix || "v",
|
|
2112
2248
|
tagTemplate: config.tagTemplate,
|
|
2113
|
-
packageTagTemplate: config.packageTagTemplate,
|
|
2114
2249
|
commitMessageTemplate: config.commitMessage || "",
|
|
2115
2250
|
dryRun: config.dryRun || false,
|
|
2116
2251
|
skipHooks: config.skipHooks || false,
|