enablement-build-monorepo-version 8.4.1 → 8.4.5

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
@@ -27,6 +27,8 @@ npx enablement-build-monorepo-version@latest [flags]
27
27
  | `--hash` | off | Compute and **save** current hashes to the hash state file. Must be run before `--changed` / `--version` to establish a baseline. |
28
28
  | `--changed` | off | Print the list of changed packages and emit a `changed` pipeline variable. |
29
29
  | `--version` | off | Emit a pipeline variable per changed package containing its next version. |
30
+ | `--patchonly` | off | Restrict package version bumps to the patch number, even for commits normally classified as minor or major. |
31
+ | `--suffix <value>` | — | Force this prerelease suffix on every bumped version, replacing any existing suffix. A leading `-` is optional. |
30
32
  | `--save` | off | Write the bumped version back into each changed package's version manifests (`package.json`, `version.json`, and/or `pyproject.toml`). Requires `--version`. |
31
33
  | `--tag` | off | Create a git tag (`<short-name>/<version>`) for each changed package, where `short-name` is the npm package name with its scope prefix removed (e.g. `@scope/lib-foo` → `lib-foo/1.2.3`). |
32
34
  | `--retag` | off | Convert existing tags that use the old folder-name format to the new short-package-name format. Non-destructive: old tags are left in place. |
@@ -43,6 +45,8 @@ npx enablement-build-monorepo-version@latest [flags]
43
45
  | `--hashExcludeFiles <list>` | see below | Comma-separated file names to skip when hashing. |
44
46
  | `--hashFiles <list>` | — | Comma-separated individual file paths to include in the hash state (outside of `children` folders). |
45
47
 
48
+ Existing prerelease suffixes (for example, `-devA`) are retained when bumping versions unless `--suffix` is provided.
49
+
46
50
  **Default excluded folders:** `node_modules`, `coverage`, `dist`, `bin`, `obj`, `__pycache__`, `.vs`, `.nx`, `.vscode`, `.idea`, `.git`, `.github`, `.azuredevops`, `.release`
47
51
 
48
52
  **Default excluded files:** `.npmrc`, `CHANGELOG.md`, `README.md`
package/package.json CHANGED
@@ -1,12 +1,17 @@
1
1
  {
2
2
  "name": "enablement-build-monorepo-version",
3
- "version": "8.4.1",
3
+ "version": "8.4.5",
4
4
  "description": "This detects changes in the children packages of a monorepo.",
5
5
  "type": "module",
6
6
  "module": "./src/index.mjs",
7
7
  "bin": "./src/index.mjs",
8
8
  "license": "MIT",
9
9
  "author": "Contributors",
10
+ "scripts": {
11
+ "start": "node src/index.mjs",
12
+ "test": "node --experimental-vm-modules node_modules/jest/bin/jest.js",
13
+ "test:watch": "node --experimental-vm-modules node_modules/jest/bin/jest.js --watch"
14
+ },
10
15
  "jest": {
11
16
  "testEnvironment": "node",
12
17
  "testMatch": [
@@ -14,15 +19,10 @@
14
19
  ]
15
20
  },
16
21
  "dependencies": {
17
- "minimatch": "~10.1.1",
18
- "enablement-build-manifest": "1.8.2"
22
+ "enablement-build-manifest": "workspace:*",
23
+ "minimatch": "~10.1.1"
19
24
  },
20
25
  "devDependencies": {
21
26
  "jest": "^30.4.2"
22
- },
23
- "scripts": {
24
- "start": "node src/index.mjs",
25
- "test": "node --experimental-vm-modules node_modules/jest/bin/jest.js",
26
- "test:watch": "node --experimental-vm-modules node_modules/jest/bin/jest.js --watch"
27
27
  }
28
28
  }
package/src/index.mjs CHANGED
@@ -12,11 +12,14 @@ const packageVersion = packageMetadata.version;
12
12
  import { dependencyMap, compare, getCurrentVersion, updateVersion, retagToPackageNames, detectOldFormatTags, resolveWorkspaceChildren, excludeChildren, applyInitScripts, RELEASE_SCRIPTS, emitVariable, hashElement, resolveHashFilePath, ensureHashFileExists, loadHashFile, writeHashFile } from "./lib.mjs";
13
13
 
14
14
 
15
- function bumpPatchVersion(version) {
15
+ function bumpPatchVersion(version, forcedSuffix) {
16
16
  const value = (version || '0.0.0').trim();
17
17
  const parts = value.split('-');
18
18
  const base = parts[0] || '0.0.0';
19
- const suffix = parts.length > 1 ? parts.slice(1).join('-') : '';
19
+ let suffix = parts.length > 1 ? parts.slice(1).join('-') : '';
20
+ if (forcedSuffix !== null && forcedSuffix !== undefined) {
21
+ suffix = String(forcedSuffix).replace(/^-+/, '');
22
+ }
20
23
 
21
24
  const nums = base.split('.');
22
25
  const major = Number.parseInt(nums[0] || '0', 10) || 0;
@@ -35,7 +38,7 @@ async function updateRootVersionIfNeeded(options, changeList) {
35
38
 
36
39
  const pkg = JSON.parse(readFileSync(rootPackageFile, 'utf8'));
37
40
  const previous = pkg.version || '0.0.0';
38
- const next = bumpPatchVersion(previous);
41
+ const next = bumpPatchVersion(previous, options.suffix);
39
42
 
40
43
  if (options.try) {
41
44
  console.log('\x1b[36m%s\x1b[0m', `[try] Would update ${rootPackageFile} version ${previous} -> ${next}`);
@@ -196,7 +199,13 @@ async function main(options) {
196
199
  let children = options.children.replace(/\s/g, ",");
197
200
  children.split(',').forEach((packageFolder) => {
198
201
  scanlist.push(new Promise((resolve, reject) => {
199
- hashElement(path.join(options.prefixPath, packageFolder), hashOptions).then(async hash => {
202
+ const folderPath = path.join(options.prefixPath, packageFolder);
203
+ if (!existsSync(folderPath)) {
204
+ console.log('\x1b[33m%s\x1b[0m', `Warning: workspace folder "${packageFolder}" does not exist, skipping`);
205
+ resolve("OK");
206
+ return;
207
+ }
208
+ hashElement(folderPath, hashOptions).then(async hash => {
200
209
  const children = hash.children;
201
210
  if (options.debug) console.log("HASH", JSON.stringify(children));
202
211
 
@@ -257,7 +266,8 @@ async function main(options) {
257
266
  resolve("OK");
258
267
  })
259
268
  .catch(error => {
260
- return console.error('hashing failed:', error);
269
+ console.error('hashing failed:', error);
270
+ resolve("OK");
261
271
  });
262
272
  }));
263
273
  });
@@ -336,6 +346,8 @@ async function main(options) {
336
346
  let options = {
337
347
  saveVersion: false,
338
348
  changed: false,
349
+ patchonly: false,
350
+ suffix: null,
339
351
  version: false,
340
352
  hash: false,
341
353
  tag: false,
@@ -365,6 +377,15 @@ if (process.argv.length === 2) {
365
377
  if (argv[i] === "--save") options.saveVersion = true;
366
378
  else if (argv[i] === "--debug") options.debug = true;
367
379
  else if (argv[i] === "--changed") options.changed = true;
380
+ else if (argv[i] === "--patchonly") options.patchonly = true;
381
+ else if (argv[i] === "--suffix") {
382
+ if (!argv[i + 1] || argv[i + 1].startsWith("--")) {
383
+ console.error("Expected a value for --suffix");
384
+ process.exit(1);
385
+ }
386
+ options.suffix = argv[i + 1];
387
+ i++;
388
+ }
368
389
  else if (argv[i] === "--version") options.version = true;
369
390
  else if (argv[i] === "--hash") options.hash = true;
370
391
  else if (argv[i] === "--tag") options.tag = true;
package/src/version.mjs CHANGED
@@ -51,7 +51,10 @@ function processMessage(message, tag, imageName, options, args) {
51
51
  let minor = Number.parseInt(parts[1] || '0', 10) || 0;
52
52
  let patch = Number.parseInt(parts[2] || '0', 10) || 0;
53
53
 
54
- const bump = getBumpType(message);
54
+ const bump = options.patchonly ? "patch" : getBumpType(message);
55
+ if (options.suffix !== null && options.suffix !== undefined) {
56
+ suffix = String(options.suffix).replace(/^-+/, "");
57
+ }
55
58
  let build = false;
56
59
 
57
60
  if (bump === "major") {
@@ -25,6 +25,36 @@ describe('version bump parsing', () => {
25
25
  expect(result.version).toBe('2.0.0');
26
26
  });
27
27
 
28
+ it('preserves a suffix during a normal bump without patchonly', () => {
29
+ const result = processMessage('feat: add endpoint', '1.2.3-devA', 'pkg', options, {});
30
+ expect(result.version).toBe('1.3.0-devA');
31
+ });
32
+
33
+ it('limits breaking changes to a patch bump when patchonly is enabled', () => {
34
+ const result = processMessage('feat!: remove old API', '1.2.3', 'pkg', { ...options, patchonly: true }, {});
35
+ expect(result.version).toBe('1.2.4');
36
+ });
37
+
38
+ it('limits minor changes to a patch bump when patchonly is enabled', () => {
39
+ const result = processMessage('feat: add endpoint', '1.2.3', 'pkg', { ...options, patchonly: true }, {});
40
+ expect(result.version).toBe('1.2.4');
41
+ });
42
+
43
+ it('preserves a suffix when patchonly is enabled', () => {
44
+ const result = processMessage('feat!: remove old API', '1.2.3-devA', 'pkg', { ...options, patchonly: true }, {});
45
+ expect(result.version).toBe('1.2.4-devA');
46
+ });
47
+
48
+ it('adds a forced suffix when the version has none', () => {
49
+ const result = processMessage('fix: adjust typo', '1.2.3', 'pkg', { ...options, suffix: 'devA' }, {});
50
+ expect(result.version).toBe('1.2.4-devA');
51
+ });
52
+
53
+ it('replaces an existing suffix with the forced suffix', () => {
54
+ const result = processMessage('feat: add endpoint', '1.2.3-old', 'pkg', { ...options, suffix: '-devA' }, {});
55
+ expect(result.version).toBe('1.3.0-devA');
56
+ });
57
+
28
58
  it('classifies bump types directly', () => {
29
59
  expect(getBumpType('feat(parser): support x')).toBe('minor');
30
60
  expect(getBumpType('refactor(core): split module')).toBe('minor');