Skip to content

Commit 79279fc

Browse files
committed
PR feedback
1 parent afb6812 commit 79279fc

3 files changed

Lines changed: 54 additions & 50 deletions

File tree

libraries/rush-lib/src/cli/parsing/ParseParallelism.ts

Lines changed: 50 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -5,39 +5,67 @@ import * as os from 'node:os';
55

66
import { IS_WINDOWS } from '../../utilities/executionUtilities';
77

8+
export function getNumberOfCores(): number {
9+
return os.availableParallelism?.() ?? os.cpus().length;
10+
}
11+
12+
/**
13+
* Since the JSON value is a string, it must be a percentage like "50%",
14+
* which we convert to a number based on the available parallelism.
15+
* For example, if the available parallelism (not the -p flag) is 8 and the weight is "50%",
16+
* then the resulting weight will be 4.
17+
*
18+
* @param weight
19+
* @returns
20+
*/
21+
export function parseParallelismPercent(weight: string, numberOfCores: number = getNumberOfCores()): number {
22+
const percentageRegExp: RegExp = /^\d+(\.\d+)?%$/;
23+
24+
if (!percentageRegExp.test(weight)) {
25+
throw new Error(`Expecting a percentage string like "12%" or "34.56%".`);
26+
}
27+
28+
const percentValue: number = parseFloat(weight.slice(0, -1));
29+
30+
if (percentValue <= 0) {
31+
throw new Error(`Invalid percentage value of "${percentValue}": value must be greater than zero`);
32+
}
33+
34+
if (percentValue > 100) {
35+
throw new Error(`Invalid percentage value of "${percentValue}": value must not exceed 100%`);
36+
}
37+
38+
// Use as much CPU as possible, so we round down the weight here
39+
return Math.max(1, Math.floor((percentValue / 100) * numberOfCores));
40+
}
41+
842
/**
943
* Parses a command line specification for desired parallelism.
1044
* Factored out to enable unit tests
1145
*/
1246
export function parseParallelism(
1347
rawParallelism: string | undefined,
14-
numberOfCores: number = os.availableParallelism?.() ?? os.cpus().length
48+
numberOfCores: number = getNumberOfCores()
1549
): number {
1650
if (rawParallelism) {
51+
rawParallelism = rawParallelism.trim();
52+
1753
if (rawParallelism === 'max') {
1854
return numberOfCores;
19-
} else {
20-
const parallelismAsNumber: number = Number(rawParallelism);
21-
22-
if (typeof rawParallelism === 'string' && rawParallelism.trim().endsWith('%')) {
23-
const parsedPercentage: number = Number(rawParallelism.trim().replace(/\%$/, ''));
24-
25-
if (parsedPercentage <= 0 || parsedPercentage > 100) {
26-
throw new Error(
27-
`Invalid percentage value of '${rawParallelism}', value cannot be less than '0%' or more than '100%'`
28-
);
29-
}
30-
31-
const workers: number = Math.floor((parsedPercentage / 100) * numberOfCores);
32-
return Math.max(workers, 1);
33-
} else if (!isNaN(parallelismAsNumber)) {
34-
return Math.max(parallelismAsNumber, 1);
35-
} else {
36-
throw new Error(
37-
`Invalid parallelism value of '${rawParallelism}', expected a number, a percentage, or 'max'`
38-
);
39-
}
4055
}
56+
57+
if (rawParallelism.endsWith('%')) {
58+
return parseParallelismPercent(rawParallelism, numberOfCores);
59+
}
60+
61+
const parallelismAsNumber: number = Number(rawParallelism);
62+
if (!isNaN(parallelismAsNumber)) {
63+
return Math.max(parallelismAsNumber, 1);
64+
}
65+
66+
throw new Error(
67+
`Invalid parallelism value of "${rawParallelism}": expected a number, a percentage string, or "max"`
68+
);
4169
} else {
4270
// If an explicit parallelism number wasn't provided, then choose a sensible
4371
// default.
Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
// Jest Snapshot v1, https://goo.gl/fbAQLP
22

3-
exports[`parseParallelism throwsErrorOnInvalidParallelism 1`] = `"Invalid parallelism value of 'tequila', expected a number, a percentage, or 'max'"`;
3+
exports[`parseParallelism throwsErrorOnInvalidParallelism 1`] = `"Invalid parallelism value of \\"tequila\\": expected a number, a percentage string, or \\"max\\""`;
44

5-
exports[`parseParallelism throwsErrorOnInvalidParallelismPercentage 1`] = `"Invalid percentage value of '200%', value cannot be less than '0%' or more than '100%'"`;
5+
exports[`parseParallelism throwsErrorOnInvalidParallelismPercentage 1`] = `"Invalid percentage value of \\"200\\": value must not exceed 100%"`;

libraries/rush-lib/src/logic/operations/WeightedOperationPlugin.ts

Lines changed: 2 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,6 @@
11
// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license.
22
// See LICENSE in the project root for license information.
33

4-
import os from 'node:os';
5-
64
import { Async } from '@rushstack/node-core-library';
75

86
import type { Operation } from './Operation';
@@ -14,6 +12,7 @@ import type {
1412
import type { IOperationSettings, RushProjectConfiguration } from '../../api/RushProjectConfiguration';
1513
import type { IOperationExecutionResult } from './IOperationExecutionResult';
1614
import type { OperationExecutionRecord } from './OperationExecutionRecord';
15+
import { parseParallelismPercent } from '../../cli/parsing/ParseParallelism';
1716

1817
const PLUGIN_NAME: 'WeightedOperationPlugin' = 'WeightedOperationPlugin';
1918

@@ -33,29 +32,6 @@ function weightOperations(
3332
context: ICreateOperationsContext
3433
): Map<Operation, IOperationExecutionResult> {
3534
const { projectConfigurations } = context;
36-
const availableParallelism: number = os.availableParallelism();
37-
38-
const percentageRegExp: RegExp = /^[1-9][0-9]*(\.\d+)?%$/;
39-
40-
/**
41-
* Since the JSON value is a string, it must be a percentage like "50%",
42-
* which we convert to a number based on the available parallelism.
43-
* For example, if the available parallelism (not the -p flag) is 8 and the weight is "50%",
44-
* then the resulting weight will be 4.
45-
*
46-
* @param weight
47-
* @returns
48-
*/
49-
function _tryConvertPercentWeight(weight: `${number}%`): number {
50-
if (!percentageRegExp.test(weight)) {
51-
throw new Error(`Because the JSON value is a string, expecting a percentage like "23.4%".`);
52-
}
53-
54-
const percentValue: number = parseFloat(weight.slice(0, -1));
55-
56-
// Use as much CPU as possible, so we round down the weight here
57-
return Math.max(1, Math.floor((percentValue / 100) * availableParallelism));
58-
}
5935

6036
for (const [operation, record] of operations) {
6137
const { runner } = record as OperationExecutionRecord;
@@ -71,7 +47,7 @@ function weightOperations(
7147
operation.weight = operationSettings.weight;
7248
} else if (typeof operationSettings.weight === 'string') {
7349
try {
74-
operation.weight = _tryConvertPercentWeight(operationSettings.weight);
50+
operation.weight = parseParallelismPercent(operationSettings.weight);
7551
} catch (error) {
7652
throw new Error(
7753
`${operation.name} (invalid weight: ${JSON.stringify(operationSettings.weight)}) ${(error as Error).message}`

0 commit comments

Comments
 (0)