Skip to content

Commit 5ff9d8a

Browse files
authored
SCANPY-213: Add parameters for parallelization (#246)
1 parent b800976 commit 5ff9d8a

File tree

4 files changed

+70
-1
lines changed

4 files changed

+70
-1
lines changed

CLI_ARGS.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,8 @@
6464
| `--sonar-pullrequest-base`, `-Dsonar.pullrequest.base` | Base branch of the pull request being analyzed |
6565
| `--sonar-pullrequest-branch`, `-Dsonar.pullrequest.branch` | Branch of the pull request being analyzed |
6666
| `--sonar-pullrequest-key`, `-Dsonar.pullrequest.key` | Key of the pull request being analyzed |
67+
| `--sonar-python-analysis-parallel`, `--no-sonar-python-analysis-parallel`, `--analysis-in-parallel`, `--no-analysis-in-parallel`, `-Dsonar.python.analysis.parallel` | When set to False the analysis will be single threaded |
68+
| `--sonar-python-analysis-threads`, `--nr-analysis-threads`, `-Dsonar.python.analysis.threads` | Set the number of threads to use during analysis. This property is ignored if --sonar-python-analysis-parallel is set to False |
6769
| `--sonar-python-skip-unchanged`, `--no-sonar-python-skip-unchanged` | Override the SonarQube configuration of skipping or not the analysis of unchanged Python files |
6870
| `--sonar-qualitygate-timeout`, `-Dsonar.qualitygate.timeout` | The number of seconds that the scanner should wait for a report to be processed |
6971
| `--sonar-qualitygate-wait`, `--no-sonar-qualitygate-wait` | Forces the analysis step to poll the server instance and wait for the Quality Gate status |

src/pysonar_scanner/configuration/cli.py

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -170,6 +170,22 @@ def __create_parser(cls):
170170
"--sonar-modules", "-Dsonar.modules", type=str, help="Comma-delimited list of modules to analyze"
171171
)
172172

173+
parser.add_argument(
174+
"--sonar-python-analysis-parallel",
175+
"--analysis-in-parallel",
176+
"-Dsonar.python.analysis.parallel",
177+
type=bool,
178+
action=argparse.BooleanOptionalAction,
179+
help="When set to False the analysis will be single threaded",
180+
)
181+
parser.add_argument(
182+
"--sonar-python-analysis-threads",
183+
"--nr-analysis-threads",
184+
"-Dsonar.python.analysis.threads",
185+
type=int,
186+
help="Set the number of threads to use during analysis. This property is ignored if --sonar-python-analysis-parallel is set to False",
187+
)
188+
173189
server_connection_group = parser.add_argument_group("SonarQube Connection")
174190
server_connection_group.add_argument(
175191
"--sonar-host-url",

src/pysonar_scanner/configuration/properties.py

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,8 @@
9494
SONAR_WORKING_DIRECTORY: Key = "sonar.working.directory"
9595
SONAR_SCM_FORCE_RELOAD_ALL: Key = "sonar.scm.forceReloadAll"
9696
SONAR_MODULES: Key = "sonar.modules"
97+
SONAR_PYTHON_ANALYSIS_PARALLEL: Key = "sonar.python.analysis.parallel"
98+
SONAR_PYTHON_ANALYSIS_THREADS: Key = "sonar.python.analysis.threads"
9799
SONAR_PYTHON_XUNIT_REPORT_PATH: Key = "sonar.python.xunit.reportPath"
98100
SONAR_PYTHON_XUNIT_SKIP_DETAILS: Key = "sonar.python.xunit.skipDetails"
99101
SONAR_PYTHON_MYPY_REPORT_PATHS: Key = "sonar.python.mypy.reportPaths"
@@ -541,6 +543,16 @@ def env_variable_name(self) -> str:
541543
default_value=None,
542544
cli_getter=None,
543545
deprecation_message="SONAR_SCANNER_OPTS is deprecated, please use SONAR_SCANNER_JAVA_OPTS instead."
544-
)
546+
),
547+
Property(
548+
name=SONAR_PYTHON_ANALYSIS_PARALLEL,
549+
default_value=None,
550+
cli_getter=lambda args: args.sonar_python_analysis_parallel
551+
),
552+
Property(
553+
name=SONAR_PYTHON_ANALYSIS_THREADS,
554+
default_value=None,
555+
cli_getter=lambda args: args.sonar_python_analysis_threads
556+
),
545557
]
546558
# fmt: on

tests/unit/test_configuration_cli.py

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,8 @@
2626
from pysonar_scanner.configuration.properties import (
2727
SONAR_HOST_URL,
2828
SONAR_ORGANIZATION,
29+
SONAR_PYTHON_ANALYSIS_PARALLEL,
30+
SONAR_PYTHON_ANALYSIS_THREADS,
2931
SONAR_PYTHON_BANDIT_REPORT_PATHS,
3032
SONAR_PYTHON_FLAKE8_REPORT_PATHS,
3133
SONAR_PYTHON_MYPY_REPORT_PATHS,
@@ -159,6 +161,8 @@
159161
SONAR_PYTHON_COVERAGE_REPORT_PATHS: "path/to/coverage1,path/to/coverage2",
160162
SONAR_COVERAGE_EXCLUSIONS: "*/.local/*,/usr/*,utils/tirefire.py",
161163
SONAR_PYTHON_SKIP_UNCHANGED: True,
164+
SONAR_PYTHON_ANALYSIS_PARALLEL: True,
165+
SONAR_PYTHON_ANALYSIS_THREADS: 2,
162166
SONAR_PYTHON_XUNIT_REPORT_PATH: "path/to/xunit/report",
163167
SONAR_PYTHON_XUNIT_SKIP_DETAILS: True,
164168
SONAR_PYTHON_MYPY_REPORT_PATHS: "path/to/mypy/reports",
@@ -207,6 +211,36 @@ def test_alternative_cli_args(self):
207211
}
208212
self.assertDictEqual(configuration, expected_configuration)
209213

214+
def test_alternative_analysis_threads_cli_args(self):
215+
base_args = ["myscript.py", "-t", "myToken", "--sonar-project-key", "myProjectKey"]
216+
report_args = ["--nr-analysis-threads", "3"]
217+
218+
expected_configuration = {
219+
SONAR_TOKEN: "myToken",
220+
SONAR_PROJECT_KEY: "myProjectKey",
221+
SONAR_PYTHON_ANALYSIS_THREADS: 3,
222+
}
223+
224+
with patch("sys.argv", base_args + report_args), patch("sys.stderr", new=StringIO()):
225+
configuration = CliConfigurationLoader.load()
226+
self.assertDictEqual(configuration, expected_configuration)
227+
228+
def test_alternative_analysis_single_threaded_cli_args(self):
229+
base_args = ["myscript.py", "-t", "myToken", "--sonar-project-key", "myProjectKey"]
230+
report_args = [
231+
"--no-analysis-in-parallel",
232+
]
233+
234+
expected_configuration = {
235+
SONAR_TOKEN: "myToken",
236+
SONAR_PROJECT_KEY: "myProjectKey",
237+
SONAR_PYTHON_ANALYSIS_PARALLEL: False,
238+
}
239+
240+
with patch("sys.argv", base_args + report_args), patch("sys.stderr", new=StringIO()):
241+
configuration = CliConfigurationLoader.load()
242+
self.assertDictEqual(configuration, expected_configuration)
243+
210244
def test_alternative_report_cli_args(self):
211245
base_args = ["myscript.py", "-t", "myToken", "--sonar-project-key", "myProjectKey"]
212246
report_args = [
@@ -404,6 +438,9 @@ def test_impossible_os_choice(self):
404438
"module1,module2",
405439
"--sonar-scanner-java-heap-size",
406440
"8000Mb",
441+
"--analysis-in-parallel",
442+
"--nr-analysis-threads",
443+
"2",
407444
],
408445
)
409446
def test_all_cli_args(self):
@@ -474,6 +511,8 @@ def test_all_cli_args(self):
474511
"-Dsonar.python.pylint.reportPath=path/to/pylint/report",
475512
"-Dsonar.python.coverage.reportPaths=path/to/coverage1,path/to/coverage2",
476513
"-Dsonar.coverage.exclusions=*/.local/*,/usr/*,utils/tirefire.py",
514+
"-Dsonar.python.analysis.parallel",
515+
"-Dsonar.python.analysis.threads=2",
477516
"-Dsonar.python.skipUnchanged=true",
478517
"-Dsonar.python.xunit.reportPath=path/to/xunit/report",
479518
"-Dsonar.python.xunit.skipDetails=true",

0 commit comments

Comments
 (0)