Skip to content

Commit 9345789

Browse files
PYSCAN-43 Ensure CLI arguments to the sonar-scanner-cli are provided intentionally (#37)
1 parent 7acba3d commit 9345789

File tree

6 files changed

+52
-22
lines changed

6 files changed

+52
-22
lines changed

its/sources/minimal/pyproject.toml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
[project]
22
name = "minimal"
33

4+
[tool.poetry]
5+
version = "1.5"
6+
47
[tool.sonar]
58
projectKey="minimal"
69
sources="src"
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
sonar.projectVersion=1.2

its/tests/test_analysis.py

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,3 +27,30 @@ def test_minimal_project(sonarqube_client: SonarQubeClient):
2727
response = sonarqube_client.get_project_issues("minimal")
2828
data = response.json()
2929
assert len(data["issues"]) == 1
30+
analyses_data = sonarqube_client.get_project_analyses("minimal").json()
31+
latest_analysis_data = analyses_data['analyses'][0]
32+
assert latest_analysis_data['projectVersion'] == '1.2'
33+
34+
35+
def test_minimal_project_read_poetry_data(sonarqube_client: SonarQubeClient):
36+
process = CliClient().run_analysis(sonarqube_client, params=["-read.project.config"], sources_dir="minimal")
37+
assert process.returncode == 0
38+
response = sonarqube_client.get_project_issues("minimal")
39+
data = response.json()
40+
assert len(data["issues"]) == 1
41+
analyses_data = sonarqube_client.get_project_analyses("minimal").json()
42+
latest_analysis_data = analyses_data['analyses'][0]
43+
assert latest_analysis_data['projectVersion'] == '1.5'
44+
45+
46+
def test_minimal_project_unexpected_arg(sonarqube_client: SonarQubeClient):
47+
process = CliClient().run_analysis(sonarqube_client, params=["-unexpected"], sources_dir="minimal")
48+
assert process.returncode == 0
49+
assert "ERROR: Unrecognized option: -unexpected" in process.stdout
50+
51+
52+
def test_minimal_project_wrong_home(sonarqube_client: SonarQubeClient):
53+
process = CliClient().run_analysis(sonarqube_client, params=["-Dproject.home='unknown/path'"],
54+
sources_dir="minimal")
55+
assert process.returncode == 0
56+
assert "Project home must be an existing directory" in process.stdout

its/utils/sonarqube_client.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,3 +53,6 @@ def wait_for_analysis_completion(self):
5353

5454
def get_project_issues(self, project_key: str):
5555
return self.session.get(f"{self.base_url}/api/issues/search?projects={project_key}")
56+
57+
def get_project_analyses(self, project_key: str):
58+
return self.session.get(f"{self.base_url}/api/project_analyses/search?project={project_key}")

src/py_sonar_scanner/configuration.py

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -45,15 +45,25 @@ def __init__(self):
4545
self.sonar_scanner_executable_path = ""
4646
self.scan_arguments = []
4747
self.wrapper_arguments = argparse.Namespace(debug=False, read_project_config=False)
48+
self.unknown_arguments = []
4849

4950
def setup(self) -> None:
5051
"""This is executed when run from the command line"""
5152
self._read_wrapper_arguments()
5253
ApplicationLogger.set_debug(self.is_debug())
5354
self.scan_arguments = self._read_toml_args()
55+
# The sonar-scanner-cli may crash with an error when receiving unexpected arguments
56+
# Therefore, arguments only expected by the sonar-scanner-python are filtered out.
57+
self._append_common_arguments()
5458
# If duplicate properties are provided, newer values will override older ones.
5559
# We therefore read CLI arguments last so that they have priority over toml configuration.
56-
self.scan_arguments.extend(sys.argv[1:])
60+
self.scan_arguments.extend(self.unknown_arguments)
61+
62+
def _append_common_arguments(self):
63+
if self.wrapper_arguments.debug:
64+
self.scan_arguments.append("-X")
65+
if self.wrapper_arguments.project_home is not None:
66+
self.scan_arguments.append(f"-Dproject.home={self.wrapper_arguments.project_home}")
5767

5868
def _read_wrapper_arguments(self):
5969
argument_parser = argparse.ArgumentParser()
@@ -68,7 +78,7 @@ def _read_wrapper_arguments(self):
6878
action="store_true",
6979
dest="read_project_config",
7080
)
71-
self.wrapper_arguments, _ = argument_parser.parse_known_args(args=sys.argv[1:])
81+
self.wrapper_arguments, self.unknown_arguments = argument_parser.parse_known_args(args=sys.argv[1:])
7282

7383
def _read_toml_args(self) -> list[str]:
7484
scan_arguments: list[str] = []
@@ -107,7 +117,7 @@ def _extract_from_poetry_properties(self, poetry_properties):
107117
if "name" in poetry_properties:
108118
result["project.name"] = poetry_properties["name"]
109119
if "version" in poetry_properties:
110-
result["project.version"] = poetry_properties["version"]
120+
result["projectVersion"] = poetry_properties["version"]
111121
# Note: Python version can be extracted from dependencies.python, however it
112122
# may be specified with constraints, e.g ">3.8", which is not currently supported by sonar-python
113123
return result

tests/test_configuration.py

Lines changed: 5 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ def test_argument_parsing(self, mock_sys):
5959
configuration.setup()
6060
self.assertListEqual(
6161
configuration.scan_arguments,
62-
["-Dsonar.a=b", "-Dsonar.c=d", f"-Dtoml.path={CURRENT_DIR}/resources/pyproject.toml"],
62+
["-Dsonar.a=b", "-Dsonar.c=d"],
6363
)
6464

6565
mock_sys.argv = [SAMPLE_SCANNER_PATH, f"-Dproject.home={CURRENT_DIR}/resources/"]
@@ -139,7 +139,6 @@ def test_toml_with_valid_values(self, mock_sys):
139139
"-Dsonar.project.name=overridden_name",
140140
"-Dsonar.python.version=3.10",
141141
"-Dsonar.property_class.property1=value1",
142-
f"-Dtoml.path={CURRENT_DIR}/resources/{TEST_TOML_FILE_POETRY}",
143142
],
144143
)
145144

@@ -153,29 +152,22 @@ def test_toml_overridden_common_properties(self, mock_sys):
153152
configuration.scan_arguments,
154153
[
155154
"-Dsonar.project.name=my_name",
156-
"-Dsonar.project.version=0.0.1",
155+
"-Dsonar.projectVersion=0.0.1",
157156
"-Dsonar.project.name=overridden_name",
158157
"-Dsonar.python.version=3.10",
159158
"-Dsonar.property_class.property1=value1",
160-
f"-Dtoml.path={CURRENT_DIR}/resources/{TEST_TOML_FILE_POETRY}",
161-
"-read.project.config",
162159
],
163160
)
164161

165162
@patch("py_sonar_scanner.configuration.sys")
166163
def test_toml_no_common_properties(self, mock_sys):
167164
configuration = Configuration()
168165
toml_file_path = os.path.join(CURRENT_DIR, "resources", TOML_NO_COMMON_PROPERTIES)
169-
mock_sys.argv = [SAMPLE_SCANNER_PATH, f"-Dtoml.path={toml_file_path}", "-read.project.config"]
166+
mock_sys.argv = [SAMPLE_SCANNER_PATH, f"-Dtoml.path={toml_file_path}", "-read.project.config", "-DsomeProp"]
170167
configuration.setup()
171168
self.assertListEqual(
172169
configuration.scan_arguments,
173-
[
174-
"-Dsonar.project.name=my_project_name",
175-
"-Dsonar.python.version=3.10",
176-
f"-Dtoml.path={CURRENT_DIR}/resources/{TOML_NO_COMMON_PROPERTIES}",
177-
"-read.project.config",
178-
],
170+
["-Dsonar.project.name=my_project_name", "-Dsonar.python.version=3.10", "-DsomeProp"],
179171
)
180172

181173
@patch("py_sonar_scanner.configuration.sys")
@@ -190,7 +182,6 @@ def test_duplicate_values_toml_cli(self, mock_sys):
190182
"-Dsonar.project.name=overridden_name",
191183
"-Dsonar.python.version=3.10",
192184
"-Dsonar.property_class.property1=value1",
193-
f"-Dtoml.path={CURRENT_DIR}/resources/{TEST_TOML_FILE_POETRY}",
194185
"-Dsonar.project.name=second_override",
195186
],
196187
)
@@ -206,12 +197,7 @@ def test_error_while_reading_toml_file(self, mock_sys, mock_open):
206197
configuration = Configuration()
207198
configuration.setup()
208199

209-
self.assertListEqual(
210-
configuration.scan_arguments,
211-
[
212-
f"-Dtoml.path={CURRENT_DIR}/resources/{TEST_TOML_FILE_POETRY}",
213-
],
214-
)
200+
self.assertListEqual(configuration.scan_arguments, [])
215201

216202
self.assertEqual(
217203
"Error while opening .toml file: Test error while opening file.", log.records[0].getMessage()

0 commit comments

Comments
 (0)