package-versioner 0.5.0 → 0.5.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 CHANGED
@@ -87,7 +87,7 @@ Customize behavior by creating a `version.config.json` file in your project root
87
87
  "versionPrefix": "v",
88
88
  "tagTemplate": "${prefix}${version}",
89
89
  "packageTagTemplate": "${packageName}@${prefix}${version}",
90
- "commitMessage": "chore(release): {{currentTag}} [skip ci]",
90
+ "commitMessage": "chore(release): ${version}",
91
91
  "monorepo": {
92
92
  "synced": true,
93
93
  "skip": [
@@ -99,7 +99,10 @@ Customize behavior by creating a `version.config.json` file in your project root
99
99
  }
100
100
  ```
101
101
 
102
- **Note:** Options like `synced`, `packages`, and `updateInternalDependencies` enable monorepo-specific behaviours. The `tagTemplate` and `packageTagTemplate` allow you to customize how Git tags are formatted for releases.
102
+ **Notes:**
103
+ - Options like `synced`, `packages`, and `updateInternalDependencies` enable monorepo-specific behaviours.
104
+ - The `tagTemplate` and `packageTagTemplate` allow you to customize how Git tags are formatted for releases.
105
+ - The `commitMessage` template can include CI skip tokens like `[skip ci]` if you want to prevent CI runs after version commits (e.g., `"commitMessage": "chore(release): ${version} [skip ci]"`). See [CI/CD Integration](./docs/CI_CD_INTEGRATION.md) for more details.
103
106
 
104
107
  ## How Versioning Works
105
108
 
package/dist/index.cjs CHANGED
@@ -141,9 +141,6 @@ function printJsonOutput() {
141
141
 
142
142
  // src/utils/logging.ts
143
143
  function log(message, status = "info") {
144
- if (isJsonOutputMode() && status !== "error") {
145
- return;
146
- }
147
144
  let chalkFn;
148
145
  switch (status) {
149
146
  case "success":
@@ -161,7 +158,18 @@ function log(message, status = "info") {
161
158
  default:
162
159
  chalkFn = import_chalk.default.blue;
163
160
  }
164
- console.log(chalkFn(message));
161
+ if (isJsonOutputMode()) {
162
+ if (status === "error") {
163
+ chalkFn(message);
164
+ console.error(message);
165
+ }
166
+ return;
167
+ }
168
+ if (status === "error") {
169
+ console.error(chalkFn(message));
170
+ } else {
171
+ console.log(chalkFn(message));
172
+ }
165
173
  }
166
174
 
167
175
  // src/core/versionStrategies.ts
@@ -389,11 +397,12 @@ async function lastMergeBranchName(branches, baseBranch) {
389
397
  }
390
398
  async function getLatestTagForPackage(packageName, tagPrefix) {
391
399
  try {
392
- const tags = await (0, import_git_semver_tags.getSemverTags)({
393
- package: packageName,
400
+ const allTags = await (0, import_git_semver_tags.getSemverTags)({
394
401
  tagPrefix
395
402
  });
396
- return tags[0] || "";
403
+ const packageTagPattern = tagPrefix ? new RegExp(`^${escapeRegExp(tagPrefix)}${escapeRegExp(packageName)}@`) : new RegExp(`^${escapeRegExp(packageName)}@`);
404
+ const packageTags = allTags.filter((tag) => packageTagPattern.test(tag));
405
+ return packageTags[0] || "";
397
406
  } catch (error) {
398
407
  const errorMessage = error instanceof Error ? error.message : String(error);
399
408
  log(`Failed to get latest tag for package ${packageName}: ${errorMessage}`, "error");
@@ -673,10 +682,27 @@ var PackageProcessor = class {
673
682
  const name = pkg.packageJson.name;
674
683
  const pkgPath = pkg.dir;
675
684
  const formattedPrefix = formatTagPrefix(this.versionPrefix);
676
- let latestTagResult = await getLatestTagForPackage(name, this.versionPrefix);
685
+ let latestTagResult = "";
686
+ try {
687
+ latestTagResult = await getLatestTagForPackage(name, this.versionPrefix);
688
+ } catch (error) {
689
+ const errorMessage = error instanceof Error ? error.message : String(error);
690
+ log(
691
+ `Error getting package-specific tag for ${name}, falling back to global tag: ${errorMessage}`,
692
+ "warning"
693
+ );
694
+ }
677
695
  if (!latestTagResult) {
678
- const globalTagResult = await this.getLatestTag();
679
- latestTagResult = globalTagResult || "";
696
+ try {
697
+ const globalTagResult = await this.getLatestTag();
698
+ latestTagResult = globalTagResult || "";
699
+ if (globalTagResult) {
700
+ log(`Using global tag ${globalTagResult} as fallback for package ${name}`, "info");
701
+ }
702
+ } catch (error) {
703
+ const errorMessage = error instanceof Error ? error.message : String(error);
704
+ log(`Error getting global tag, using empty tag value: ${errorMessage}`, "warning");
705
+ }
680
706
  }
681
707
  const latestTag = latestTagResult;
682
708
  const nextVersion = await calculateVersion(this.fullConfig, {
@@ -732,7 +758,6 @@ var PackageProcessor = class {
732
758
  } else {
733
759
  commitMessage = `chore(release): ${packageNames} ${representativeVersion}`;
734
760
  }
735
- commitMessage += " [skip-ci]";
736
761
  setCommitMessage(commitMessage);
737
762
  if (!this.dryRun) {
738
763
  try {
package/dist/index.js CHANGED
@@ -118,9 +118,6 @@ function printJsonOutput() {
118
118
 
119
119
  // src/utils/logging.ts
120
120
  function log(message, status = "info") {
121
- if (isJsonOutputMode() && status !== "error") {
122
- return;
123
- }
124
121
  let chalkFn;
125
122
  switch (status) {
126
123
  case "success":
@@ -138,7 +135,18 @@ function log(message, status = "info") {
138
135
  default:
139
136
  chalkFn = chalk.blue;
140
137
  }
141
- console.log(chalkFn(message));
138
+ if (isJsonOutputMode()) {
139
+ if (status === "error") {
140
+ chalkFn(message);
141
+ console.error(message);
142
+ }
143
+ return;
144
+ }
145
+ if (status === "error") {
146
+ console.error(chalkFn(message));
147
+ } else {
148
+ console.log(chalkFn(message));
149
+ }
142
150
  }
143
151
 
144
152
  // src/core/versionStrategies.ts
@@ -366,11 +374,12 @@ async function lastMergeBranchName(branches, baseBranch) {
366
374
  }
367
375
  async function getLatestTagForPackage(packageName, tagPrefix) {
368
376
  try {
369
- const tags = await getSemverTags({
370
- package: packageName,
377
+ const allTags = await getSemverTags({
371
378
  tagPrefix
372
379
  });
373
- return tags[0] || "";
380
+ const packageTagPattern = tagPrefix ? new RegExp(`^${escapeRegExp(tagPrefix)}${escapeRegExp(packageName)}@`) : new RegExp(`^${escapeRegExp(packageName)}@`);
381
+ const packageTags = allTags.filter((tag) => packageTagPattern.test(tag));
382
+ return packageTags[0] || "";
374
383
  } catch (error) {
375
384
  const errorMessage = error instanceof Error ? error.message : String(error);
376
385
  log(`Failed to get latest tag for package ${packageName}: ${errorMessage}`, "error");
@@ -649,10 +658,27 @@ var PackageProcessor = class {
649
658
  const name = pkg.packageJson.name;
650
659
  const pkgPath = pkg.dir;
651
660
  const formattedPrefix = formatTagPrefix(this.versionPrefix);
652
- let latestTagResult = await getLatestTagForPackage(name, this.versionPrefix);
661
+ let latestTagResult = "";
662
+ try {
663
+ latestTagResult = await getLatestTagForPackage(name, this.versionPrefix);
664
+ } catch (error) {
665
+ const errorMessage = error instanceof Error ? error.message : String(error);
666
+ log(
667
+ `Error getting package-specific tag for ${name}, falling back to global tag: ${errorMessage}`,
668
+ "warning"
669
+ );
670
+ }
653
671
  if (!latestTagResult) {
654
- const globalTagResult = await this.getLatestTag();
655
- latestTagResult = globalTagResult || "";
672
+ try {
673
+ const globalTagResult = await this.getLatestTag();
674
+ latestTagResult = globalTagResult || "";
675
+ if (globalTagResult) {
676
+ log(`Using global tag ${globalTagResult} as fallback for package ${name}`, "info");
677
+ }
678
+ } catch (error) {
679
+ const errorMessage = error instanceof Error ? error.message : String(error);
680
+ log(`Error getting global tag, using empty tag value: ${errorMessage}`, "warning");
681
+ }
656
682
  }
657
683
  const latestTag = latestTagResult;
658
684
  const nextVersion = await calculateVersion(this.fullConfig, {
@@ -708,7 +734,6 @@ var PackageProcessor = class {
708
734
  } else {
709
735
  commitMessage = `chore(release): ${packageNames} ${representativeVersion}`;
710
736
  }
711
- commitMessage += " [skip-ci]";
712
737
  setCommitMessage(commitMessage);
713
738
  if (!this.dryRun) {
714
739
  try {
@@ -156,6 +156,24 @@ git push origin "v$NEW_VERSION"
156
156
  - `NO_COLOR=1`: Disables colored output in logs (automatically detected in CI environments)
157
157
  - `CI=true`: Most CI environments set this automatically, which helps the tool adjust its output behavior
158
158
 
159
+ ## Skipping CI for Version Commits
160
+
161
+ If you want to prevent additional CI runs when version commits are made, you can include CI skip flags in your commit message template in `version.config.json`:
162
+
163
+ ```json
164
+ {
165
+ "commitMessage": "chore(release): ${version} [skip ci]",
166
+ // other configuration options...
167
+ }
168
+ ```
169
+
170
+ Common CI skip patterns include:
171
+ - `[skip ci]` or `[ci skip]` - Works in GitHub Actions, GitLab CI, CircleCI
172
+ - `[skip-ci]` - Alternative format supported by some CI systems
173
+ - `[no ci]` - Another variant
174
+
175
+ Each CI system might have slightly different syntax, so check your CI provider's documentation for the exact skip token to use.
176
+
159
177
  ## Tips for Reliable CI/CD Integration
160
178
 
161
179
  1. **Always use `--json`** in CI/CD pipelines for consistent output parsing
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "package-versioner",
3
3
  "description": "A lightweight yet powerful CLI tool for automated semantic versioning based on Git history and conventional commits.",
4
- "version": "0.5.0",
4
+ "version": "0.5.2",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
7
7
  "module": "./dist/index.mjs",