Skip to content

Commit 12f7bd0

Browse files
SCANPY-162 Allow for shorter property names in pyproject.toml
1 parent 7289d73 commit 12f7bd0

4 files changed

Lines changed: 56 additions & 27 deletions

File tree

src/pysonar_scanner/configuration/properties.py

Lines changed: 21 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -111,14 +111,27 @@ class Property:
111111
cli_getter: Optional[Callable[[argparse.Namespace], any]] = None
112112
"""function to get the value from the CLI arguments namespace. If None, the property is not settable via CLI"""
113113

114-
def python_name(self) -> str:
115-
"""Convert Java-style camel case name to Python-style kebab-case name."""
116-
result = []
117-
for i, char in enumerate(self.name):
118-
if char.isupper() and i > 0:
119-
result.append("-")
120-
result.append(char.lower())
121-
return "".join(result)
114+
def python_names(self) -> list[str]:
115+
"""Convert Java-style camel case name to Python-style kebab-case names.
116+
Additionally, if the property has 4 or more parts and the second part is 'python',
117+
generate an alternative name omitting the 'python' part."""
118+
parts = self.name.split(".")
119+
kebab_parts = []
120+
for part in parts:
121+
kebab_part = []
122+
for i, char in enumerate(part):
123+
if char.isupper() and i > 0:
124+
kebab_part.append("-")
125+
kebab_part.append(char.lower())
126+
kebab_parts.append("".join(kebab_part))
127+
128+
names = [".".join(kebab_parts)]
129+
130+
if len(parts) >= 4 and parts[1] == "python":
131+
alt_parts = [kebab_parts[0]] + kebab_parts[2:]
132+
names.append(".".join(alt_parts))
133+
134+
return names
122135

123136
def env_variable_name(self) -> str:
124137
"""Convert property name to environment variable name format.

src/pysonar_scanner/configuration/pyproject_toml.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,9 @@ def load(base_dir: Path) -> TomlProperties:
5858
def __read_sonar_properties(toml_dict) -> Dict[str, str]:
5959
if "tool" in toml_dict and "sonar" in toml_dict["tool"]:
6060
sonar_config = toml_dict["tool"]["sonar"]
61-
python_to_java_names = {prop.python_name(): prop.name for prop in properties.PROPERTIES}
61+
python_to_java_names = {
62+
python_name: prop.name for prop in properties.PROPERTIES for python_name in prop.python_names()
63+
}
6264
flattened_sonar_config = TomlConfigurationLoader.__flatten_config_dict(sonar_config, prefix="sonar.")
6365
return {python_to_java_names.get(key, key): value for key, value in flattened_sonar_config.items()}
6466
return {}

tests/test_properties.py

Lines changed: 23 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -40,35 +40,40 @@ def test_python_name_conversion(self):
4040
"""Test conversion of property names to Python-style kebab-case names"""
4141
test_cases = [
4242
# Simple properties
43-
(SONAR_HOST_URL, "sonar.host.url"),
44-
(SONAR_TOKEN, "sonar.token"),
45-
(SONAR_VERBOSE, "sonar.verbose"),
43+
(SONAR_HOST_URL, ["sonar.host.url"]),
44+
(SONAR_TOKEN, ["sonar.token"]),
45+
(SONAR_VERBOSE, ["sonar.verbose"]),
4646
# CamelCase properties
47-
(SONAR_SCANNER_APP_VERSION, "sonar.scanner.app-version"),
48-
(SONAR_SCANNER_SOCKET_TIMEOUT, "sonar.scanner.socket-timeout"),
49-
(SONAR_SCANNER_PROXY_PASSWORD, "sonar.scanner.proxy-password"),
47+
(SONAR_SCANNER_APP_VERSION, ["sonar.scanner.app-version"]),
48+
(SONAR_SCANNER_SOCKET_TIMEOUT, ["sonar.scanner.socket-timeout"]),
49+
(SONAR_SCANNER_PROXY_PASSWORD, ["sonar.scanner.proxy-password"]),
5050
# Complex properties
51-
(SONAR_SCANNER_INTERNAL_DUMP_TO_FILE, "sonar.scanner.internal.dump-to-file"),
52-
(SONAR_PROJECT_KEY, "sonar.project-key"),
53-
(SONAR_PROJECT_BASE_DIR, "sonar.project-base-dir"),
51+
(SONAR_SCANNER_INTERNAL_DUMP_TO_FILE, ["sonar.scanner.internal.dump-to-file"]),
52+
(SONAR_PROJECT_KEY, ["sonar.project-key"]),
53+
(SONAR_PROJECT_BASE_DIR, ["sonar.project-base-dir"]),
54+
# Python-specific properties with alternative names
55+
("sonar.python.pylint.reportPath", ["sonar.python.pylint.report-path", "sonar.pylint.report-path"]),
56+
(
57+
"sonar.python.coverage.reportPaths",
58+
["sonar.python.coverage.report-paths", "sonar.coverage.report-paths"],
59+
),
60+
("sonar.python.version", ["sonar.python.version"]), # No alternative name (only 3 parts)
5461
]
5562

56-
for name, expected_python_name in test_cases:
57-
# Find property in PROPERTIES list
63+
for name, expected_python_names in test_cases:
5864
prop = next((p for p in PROPERTIES if p.name == name), None)
5965
if prop:
6066
self.assertEqual(
61-
prop.python_name(),
62-
expected_python_name,
63-
f"Failed to convert {name} to Python name, got {prop.python_name()}",
67+
prop.python_names(),
68+
expected_python_names,
69+
f"Failed to convert {name} to Python names, got {prop.python_names()}",
6470
)
6571
else:
66-
# Create test property if not in list
6772
prop = Property(name=name, default_value=None)
6873
self.assertEqual(
69-
prop.python_name(),
70-
expected_python_name,
71-
f"Failed to convert {name} to Python name, got {prop.python_name()}",
74+
prop.python_names(),
75+
expected_python_names,
76+
f"Failed to convert {name} to Python names, got {prop.python_names()}",
7277
)
7378

7479
def test_env_variable_name_conversion(self):

tests/unit/test_pyproject_toml.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,8 @@ def test_load_toml_file_with_sonarqube_config(self):
3636
projectName = "My Project"
3737
sources = "src"
3838
exclusions = "**/generated/**/*,**/deprecated/**/*,**/testdata/**/*"
39+
python.mypy.report-paths = "mypy-report.xml,my/other/mypy/report.xml"
40+
ruff.report-paths = "ruff-report.xml,my/other/ruff/report.xml"
3941
some.unknownProperty = "unknown_property_value"
4042
""",
4143
)
@@ -44,6 +46,13 @@ def test_load_toml_file_with_sonarqube_config(self):
4446
self.assertEqual(properties.sonar_properties.get("sonar.projectKey"), "my-project")
4547
self.assertEqual(properties.sonar_properties.get("sonar.projectName"), "My Project")
4648
self.assertEqual(properties.sonar_properties.get("sonar.sources"), "src")
49+
self.assertEqual(properties.sonar_properties.get("sonar.sources"), "src")
50+
self.assertEqual(
51+
properties.sonar_properties.get("sonar.python.mypy.reportPaths"), "mypy-report.xml,my/other/mypy/report.xml"
52+
)
53+
self.assertEqual(
54+
properties.sonar_properties.get("sonar.python.ruff.reportPaths"), "ruff-report.xml,my/other/ruff/report.xml"
55+
)
4756
self.assertEqual(
4857
properties.sonar_properties.get("sonar.exclusions"), "**/generated/**/*,**/deprecated/**/*,**/testdata/**/*"
4958
)

0 commit comments

Comments
 (0)