Skip to content

Commit fba666f

Browse files
committed
Address allowed values enum review feedback
1 parent 0db39ad commit fba666f

6 files changed

Lines changed: 134 additions & 24 deletions

File tree

‎api/src/main/java/com/cloud/cpu/CPU.java‎

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,11 @@ public String getType() {
4141
return type;
4242
}
4343

44+
@Override
45+
public String toString() {
46+
return type;
47+
}
48+
4449
public int getBits() {
4550
return bits;
4651
}

‎api/src/main/java/org/apache/cloudstack/api/command/user/iso/ListIsosCmd.java‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,7 @@ public class ListIsosCmd extends BaseListTaggedResourcesCmd implements UserCmd {
9090

9191
@Parameter(name = ApiConstants.ARCH,
9292
type = CommandType.STRING,
93-
description = "the CPU arch of the ISO. Valid options are: x86_64, aarch64, s390x",
93+
description = "the CPU arch of the ISO. Valid options are: i686, x86_64, aarch64, s390x",
9494
since = "4.20",
9595
allowedValueType = CPU.CPUArch.class)
9696
private String arch;

‎api/src/main/java/org/apache/cloudstack/api/command/user/template/ListTemplatesCmd.java‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -115,7 +115,7 @@ public class ListTemplatesCmd extends BaseListTaggedResourcesCmd implements User
115115

116116
@Parameter(name = ApiConstants.ARCH,
117117
type = CommandType.STRING,
118-
description = "the CPU arch of the template. Valid options are: x86_64, aarch64, s390x",
118+
description = "the CPU arch of the template. Valid options are: i686, x86_64, aarch64, s390x",
119119
since = "4.20",
120120
allowedValueType = CPU.CPUArch.class)
121121
private String arch;

‎scripts/check_allowed_values.py‎

Lines changed: 81 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -165,6 +165,18 @@ def extract_inner_enums(source):
165165
for constant in body.split(","):
166166
constant = constant.strip()
167167

168+
# Enum constants with a constructor argument, e.g.
169+
# x86("i686", 32)
170+
value_match = re.match(
171+
r"[A-Za-z_][A-Za-z0-9_]*\s*\(\s*\"([^\"]+)\"",
172+
constant,
173+
)
174+
175+
if value_match:
176+
constants.append(value_match.group(1))
177+
continue
178+
179+
# Plain enum constants, e.g. LEAKS, ALL
168180
constant_match = re.match(
169181
r"([A-Z][A-Z0-9_]*)\b",
170182
constant,
@@ -178,6 +190,31 @@ def extract_inner_enums(source):
178190

179191
return enums
180192

193+
def build_enum_index():
194+
enum_index = {}
195+
196+
for path in find_java_files():
197+
source = path.read_text(encoding="utf-8")
198+
enums = extract_inner_enums(source)
199+
200+
for enum_name, values in enums.items():
201+
enum_index[enum_name] = values
202+
203+
return enum_index
204+
205+
def extract_allowed_value_type(block):
206+
match = re.search(
207+
r"\ballowedValueType\s*=\s*([A-Za-z_][A-Za-z0-9_]*)(?:\.([A-Za-z_][A-Za-z0-9_]*))?\.class",
208+
block,
209+
)
210+
211+
if not match:
212+
return None
213+
214+
if match.group(2):
215+
return match.group(2)
216+
217+
return match.group(1)
181218

182219
def extract_parameter_field_name(source, parameter_end):
183220
match = re.match(
@@ -205,22 +242,21 @@ def find_enum_for_parameter(source, parameter_end, field_name):
205242

206243
return None
207244

208-
def check_file(path):
245+
def check_file(path, enum_index=None):
209246
source = Path(path).read_text(encoding="utf-8")
210247
violations = []
211-
212248
enums = extract_inner_enums(source)
213249

250+
if enum_index is None:
251+
enum_index = {}
252+
214253
for start, block in extract_parameter_blocks(source):
215254
if not is_string_parameter(block):
216255
continue
217256

218257
if re.search(r"\ballowedValues\s*=", block):
219258
continue
220259

221-
if re.search(r"\ballowedValueType\s*=", block):
222-
continue
223-
224260
parameter_end = start + len(block)
225261
field_name = extract_parameter_field_name(
226262
source,
@@ -233,28 +269,51 @@ def check_file(path):
233269
field_name,
234270
)
235271

272+
if not enum_name:
273+
enum_name = extract_allowed_value_type(block)
274+
275+
description = extract_description(block)
276+
values = extract_valid_values(description) if description else []
277+
278+
enum_values = None
236279
if enum_name and enum_name in enums:
237-
line = source[:start].count("\n") + 1
238-
name = extract_parameter_name(block)
239-
240-
violations.append(
241-
(
242-
str(path),
243-
line,
244-
enums[enum_name],
245-
name,
280+
enum_values = enums[enum_name]
281+
elif enum_name and enum_name in enum_index:
282+
enum_values = enum_index[enum_name]
283+
284+
if enum_values is not None:
285+
286+
if re.search(r"\ballowedValueType\s*=", block):
287+
if values and values != enum_values:
288+
line = source[:start].count("\n") + 1
289+
name = extract_parameter_name(block)
290+
291+
violations.append(
292+
(
293+
str(path),
294+
line,
295+
enum_values,
296+
name,
297+
)
298+
)
299+
else:
300+
line = source[:start].count("\n") + 1
301+
name = extract_parameter_name(block)
302+
303+
violations.append(
304+
(
305+
str(path),
306+
line,
307+
enum_values,
308+
name,
309+
)
246310
)
247-
)
248311

249312
continue
250313

251-
description = extract_description(block)
252-
253-
if not description:
314+
if re.search(r"\ballowedValueType\s*=", block):
254315
continue
255316

256-
values = extract_valid_values(description)
257-
258317
if not values:
259318
continue
260319

@@ -269,9 +328,10 @@ def check_file(path):
269328

270329
def main():
271330
violations = []
331+
enum_index = build_enum_index()
272332

273333
for path in find_java_files():
274-
violations.extend(check_file(path))
334+
violations.extend(check_file(path, enum_index))
275335

276336
if violations:
277337
print("Missing allowedValues annotations:")

‎scripts/test_check_allowed_values.py‎

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -281,6 +281,50 @@ def test_enum_parameter_with_allowed_value_type_is_not_reported(self):
281281
finally:
282282
path.unlink()
283283

284+
def test_external_enum_parameter_with_mismatched_description_is_reported(self):
285+
enum_source = """
286+
public class CPU {
287+
public enum CPUArch {
288+
x86("i686", 32),
289+
amd64("x86_64", 64),
290+
arm64("aarch64", 64),
291+
s390x("s390x", 64);
292+
}
293+
}
294+
"""
295+
296+
command_source = """
297+
public class TestCmd {
298+
@Parameter(
299+
name = "arch",
300+
type = CommandType.STRING,
301+
allowedValueType = CPU.CPUArch.class,
302+
description = "the CPU arch. Valid options are: x86_64, aarch64, s390x"
303+
)
304+
private String arch;
305+
}
306+
"""
307+
308+
with tempfile.NamedTemporaryFile(
309+
mode="w",
310+
suffix=".java",
311+
encoding="utf-8",
312+
delete=False,
313+
) as file:
314+
file.write(command_source)
315+
path = Path(file.name)
316+
317+
try:
318+
enum_index = check_allowed_values.extract_inner_enums(enum_source)
319+
violations = check_allowed_values.check_file(path, enum_index)
320+
321+
self.assertEqual(len(violations), 1)
322+
self.assertEqual(
323+
violations[0][2],
324+
["i686", "x86_64", "aarch64", "s390x"],
325+
)
326+
finally:
327+
path.unlink()
284328

285329
if __name__ == "__main__":
286330
unittest.main()

‎server/src/main/java/com/cloud/template/TemplateManagerImpl.java‎

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2443,10 +2443,11 @@ public TemplateType validateTemplateType(BaseCmd cmd, boolean isAdmin, boolean i
24432443
}
24442444
if (newType != null) {
24452445
try {
2446+
TemplateApiType.valueOf(newType.toUpperCase());
24462447
templateType = TemplateType.valueOf(newType.toUpperCase());
24472448
} catch (IllegalArgumentException ex) {
24482449
throw new InvalidParameterValueException(String.format("Please specify a valid templatetype: %s",
2449-
org.apache.commons.lang3.StringUtils.join(",", TemplateType.values())));
2450+
org.apache.commons.lang3.StringUtils.join(",", TemplateApiType.values())));
24502451
}
24512452
}
24522453
if (templateType != null) {

0 commit comments

Comments
 (0)