Skip to content

Commit a85131d

Browse files
Fix after review
1 parent 80cc6aa commit a85131d

5 files changed

Lines changed: 108 additions & 73 deletions

File tree

src/pysonar_scanner/__main__.py

Lines changed: 34 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@
2020

2121
from pysonar_scanner import app_logging
2222
from pysonar_scanner import cache
23-
from pysonar_scanner.api import get_base_urls, SonarQubeApi, BaseUrls
23+
from pysonar_scanner.api import get_base_urls, SonarQubeApi, BaseUrls, MIN_SUPPORTED_SQ_VERSION
2424
from pysonar_scanner.configuration import configuration_loader
2525
from pysonar_scanner.configuration.configuration_loader import ConfigurationLoader
2626
from pysonar_scanner.configuration.properties import (
@@ -29,8 +29,11 @@
2929
SONAR_SCANNER_API_BASE_URL,
3030
SONAR_SCANNER_SONARCLOUD_URL,
3131
SONAR_SCANNER_PROXY_PORT,
32+
SONAR_SCANNER_JAVA_EXE_PATH,
3233
)
33-
from pysonar_scanner.scannerengine import ScannerEngine
34+
from pysonar_scanner.exceptions import SQTooOldException
35+
from pysonar_scanner.jre import JREResolvedPath, JREProvisioner, JREResolver, JREResolverConfiguration
36+
from pysonar_scanner.scannerengine import ScannerEngine, ScannerEngineProvisioner
3437

3538

3639
def scan():
@@ -40,12 +43,30 @@ def scan():
4043
set_logging_options(config)
4144

4245
cache_manager = cache.get_default()
46+
4347
api = __build_api(config)
48+
check_version(api)
4449
__update_config_with_api_urls(config, api.base_urls)
45-
scanner = ScannerEngine(api, cache_manager)
50+
51+
scanner = create_scanner_engine(api, cache_manager, config)
52+
4653
return scanner.run(config)
4754

4855

56+
def create_scanner_engine(api, cache_manager, config):
57+
jre_path = create_jre(api, cache_manager, config)
58+
config[SONAR_SCANNER_JAVA_EXE_PATH] = str(jre_path.path)
59+
scanner_engine_path = ScannerEngineProvisioner(api, cache_manager).provision()
60+
scanner = ScannerEngine(jre_path, scanner_engine_path)
61+
return scanner
62+
63+
64+
def create_jre(api, cache, config: dict[str, any]) -> JREResolvedPath:
65+
jre_provisioner = JREProvisioner(api, cache)
66+
jre_resolver = JREResolver(JREResolverConfiguration.from_dict(config), jre_provisioner)
67+
return jre_resolver.resolve_jre()
68+
69+
4970
def set_logging_options(config):
5071
app_logging.configure_logging_level(verbose=config.get(SONAR_VERBOSE, False))
5172

@@ -61,5 +82,14 @@ def __update_config_with_api_urls(config, base_urls: BaseUrls):
6182
config[SONAR_SCANNER_API_BASE_URL] = base_urls.api_base_url
6283
if base_urls.is_sonar_qube_cloud:
6384
config[SONAR_SCANNER_SONARCLOUD_URL] = base_urls.base_url
64-
config[SONAR_SCANNER_SONARCLOUD_URL] = base_urls.base_url
6585
config[SONAR_SCANNER_PROXY_PORT] = "443" if base_urls.base_url.startswith("https") else "80"
86+
87+
88+
def check_version(api):
89+
if api.is_sonar_qube_cloud():
90+
return
91+
version = api.get_analysis_version()
92+
if not version.does_support_bootstrapping():
93+
raise SQTooOldException(
94+
f"Only SonarQube versions >= {MIN_SUPPORTED_SQ_VERSION} are supported, but got {version}"
95+
)

src/pysonar_scanner/jre.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@
3838
SONAR_SCANNER_SKIP_JRE_PROVISIONING,
3939
SONAR_SCANNER_OS,
4040
Key,
41+
SONAR_SCANNER_ARCH,
4142
)
4243

4344

src/pysonar_scanner/scannerengine.py

Lines changed: 6 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -25,12 +25,10 @@
2525
from threading import Thread
2626
from typing import IO, Callable, Optional
2727

28-
import pysonar_scanner.api as api
2928
from pysonar_scanner.api import SonarQubeApi
3029
from pysonar_scanner.cache import Cache, CacheFile
31-
from pysonar_scanner.configuration.properties import SONAR_SCANNER_JAVA_EXE_PATH
32-
from pysonar_scanner.exceptions import ChecksumException, SQTooOldException
33-
from pysonar_scanner.jre import JREProvisioner, JREResolvedPath, JREResolver, JREResolverConfiguration
30+
from pysonar_scanner.exceptions import ChecksumException
31+
from pysonar_scanner.jre import JREResolvedPath
3432

3533

3634
@dataclass(frozen=True)
@@ -136,20 +134,12 @@ def __download_scanner_engine(self, cache_file: CacheFile) -> None:
136134

137135

138136
class ScannerEngine:
139-
def __init__(self, api: SonarQubeApi, cache: Cache):
140-
self.api = api
141-
self.cache = cache
142-
143-
def __fetch_scanner_engine(self) -> pathlib.Path:
144-
return ScannerEngineProvisioner(self.api, self.cache).provision()
137+
def __init__(self, jre_path: JREResolvedPath, scanner_engine_path: pathlib.Path):
138+
self.jre_path = jre_path
139+
self.scanner_engine_path = scanner_engine_path
145140

146141
def run(self, config: dict[str, any]):
147-
self.__version_check()
148-
jre_path = self.__resolve_jre(config)
149-
150-
config[SONAR_SCANNER_JAVA_EXE_PATH] = str(jre_path.path)
151-
scanner_engine_path = self.__fetch_scanner_engine()
152-
cmd = self.__build_command(jre_path, scanner_engine_path)
142+
cmd = self.__build_command(self.jre_path, self.scanner_engine_path)
153143
properties_str = self.__config_to_json(config)
154144
return CmdExecutor(cmd, properties_str).execute()
155145

@@ -163,17 +153,3 @@ def __build_command(self, jre_path: JREResolvedPath, scanner_engine_path: pathli
163153
def __config_to_json(self, config: dict[str, any]) -> str:
164154
scanner_properties = [{"key": k, "value": v} for k, v in config.items()]
165155
return json.dumps({"scannerProperties": scanner_properties})
166-
167-
def __version_check(self):
168-
if self.api.is_sonar_qube_cloud():
169-
return
170-
version = self.api.get_analysis_version()
171-
if not version.does_support_bootstrapping():
172-
raise SQTooOldException(
173-
f"Only SonarQube versions >= {api.MIN_SUPPORTED_SQ_VERSION} are supported, but got {version}"
174-
)
175-
176-
def __resolve_jre(self, config: dict[str, any]) -> JREResolvedPath:
177-
jre_provisionner = JREProvisioner(self.api, self.cache)
178-
jre_resolver = JREResolver(JREResolverConfiguration.from_dict(config), jre_provisionner)
179-
return jre_resolver.resolve_jre()

tests/unit/test_main.py

Lines changed: 59 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -17,11 +17,15 @@
1717
# along with this program; if not, write to the Free Software Foundation,
1818
# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
1919
#
20-
from unittest.mock import patch
20+
import pathlib
21+
from pathlib import Path
22+
from unittest.mock import patch, Mock
2123

2224
from pyfakefs import fake_filesystem_unittest as pyfakefs
2325

24-
from pysonar_scanner.__main__ import scan
26+
from pysonar_scanner.__main__ import scan, check_version, create_jre
27+
from pysonar_scanner.api import SQVersion, SonarQubeApi
28+
from pysonar_scanner.cache import Cache
2529
from pysonar_scanner.configuration.configuration_loader import ConfigurationLoader
2630
from pysonar_scanner.configuration.properties import (
2731
SONAR_PROJECT_KEY,
@@ -30,14 +34,31 @@
3034
SONAR_SCANNER_API_BASE_URL,
3135
SONAR_SCANNER_SONARCLOUD_URL,
3236
SONAR_SCANNER_PROXY_PORT,
37+
SONAR_SCANNER_OS,
38+
SONAR_SCANNER_ARCH,
39+
SONAR_SCANNER_JAVA_EXE_PATH,
3340
)
34-
from pysonar_scanner.scannerengine import ScannerEngine
41+
from pysonar_scanner.exceptions import SQTooOldException
42+
from pysonar_scanner.jre import JREResolvedPath, JREResolver
43+
from pysonar_scanner.scannerengine import ScannerEngine, ScannerEngineProvisioner
44+
from tests.unit import sq_api_utils
3545

3646

3747
class TestMain(pyfakefs.TestCase):
38-
@patch.object(ConfigurationLoader, "load", return_value={SONAR_TOKEN: "myToken", SONAR_PROJECT_KEY: "myProjectKey"})
48+
@patch.object(
49+
ConfigurationLoader,
50+
"load",
51+
return_value={
52+
SONAR_TOKEN: "myToken",
53+
SONAR_PROJECT_KEY: "myProjectKey",
54+
SONAR_SCANNER_OS: "linux",
55+
SONAR_SCANNER_ARCH: "x64",
56+
},
57+
)
58+
@patch.object(ScannerEngineProvisioner, "provision", return_value=JREResolvedPath(Path("scanner_engine_path")))
59+
@patch("pysonar_scanner.__main__.create_jre", return_value=JREResolvedPath(Path("jre_path")))
3960
@patch.object(ScannerEngine, "run", return_value=0)
40-
def test_minimal_success_run(self, run_mock, load_mock):
61+
def test_minimal_success_run(self, run_mock, create_jre_mock, provision_mock, load_mock):
4162
exitcode = scan()
4263
self.assertEqual(exitcode, 0)
4364

@@ -49,10 +70,43 @@ def test_minimal_success_run(self, run_mock, load_mock):
4970
expected_config = {
5071
SONAR_TOKEN: "myToken",
5172
SONAR_PROJECT_KEY: "myProjectKey",
73+
SONAR_SCANNER_OS: "linux",
74+
SONAR_SCANNER_ARCH: "x64",
5275
SONAR_HOST_URL: "https://sonarcloud.io",
5376
SONAR_SCANNER_API_BASE_URL: "https://api.sonarcloud.io",
5477
SONAR_SCANNER_SONARCLOUD_URL: "https://sonarcloud.io",
5578
SONAR_SCANNER_PROXY_PORT: "443",
79+
SONAR_SCANNER_JAVA_EXE_PATH: "jre_path",
5680
}
5781

5882
self.assertEqual(expected_config, config)
83+
84+
def test_version_check_outdated_sonarqube(self):
85+
sq_cloud_api = sq_api_utils.get_sq_server()
86+
sq_cloud_api.get_analysis_version = Mock(return_value=SQVersion.from_str("9.9.9"))
87+
88+
with self.assertRaises(SQTooOldException):
89+
check_version(sq_cloud_api)
90+
91+
def test_version_check_recent_sonarqube(self):
92+
sq_cloud_api = sq_api_utils.get_sq_server()
93+
sq_cloud_api.get_analysis_version = Mock(return_value=SQVersion.from_str("10.7"))
94+
95+
check_version(sq_cloud_api)
96+
sq_cloud_api.get_analysis_version.assert_called_once()
97+
98+
def test_version_check_sonarqube_cloud(self):
99+
sq_cloud_api = sq_api_utils.get_sq_cloud()
100+
sq_cloud_api.get_analysis_version = Mock()
101+
102+
check_version(sq_cloud_api)
103+
sq_cloud_api.get_analysis_version.assert_not_called()
104+
105+
106+
@patch("pysonar_scanner.scannerengine.CmdExecutor")
107+
@patch.object(JREResolver, "resolve_jre")
108+
def test_get_jre(self, resolve_jre_mock):
109+
resolve_jre_mock.return_value = JREResolvedPath(pathlib.Path("jre/bin/java"))
110+
api = SonarQubeApi(Mock(), Mock())
111+
cache = Cache(Mock())
112+
create_jre(api, cache, {SONAR_SCANNER_OS: "linux", SONAR_SCANNER_ARCH: "x64"})

tests/unit/test_scannerengine.py

Lines changed: 8 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -135,15 +135,13 @@ def setUp(self):
135135
self.setUpPyfakefs()
136136

137137
@patch("pysonar_scanner.scannerengine.CmdExecutor")
138-
@patch.object(JREResolver, "resolve_jre")
139-
@patch.object(ScannerEngineProvisioner, "provision")
140-
def test_command_building(self, provision_mock, resolve_jre_mock, execute_mock):
141-
provision_mock.return_value = pathlib.Path("/test/scanner-engine.jar")
142-
resolve_jre_mock.return_value = JREResolvedPath(pathlib.Path("jre/bin/java"))
143-
138+
def test_command_building(self, execute_mock):
144139
config = {
145140
"sonar.token": "myToken",
146141
"sonar.projectKey": "myProjectKey",
142+
"sonar.scanner.os": "linux",
143+
"sonar.scanner.arch": "x64",
144+
"sonar.scanner.javaExePath": "jre/bin/java",
147145
}
148146

149147
expected_std_in = json.dumps(
@@ -157,40 +155,16 @@ def test_command_building(self, provision_mock, resolve_jre_mock, execute_mock):
157155
]
158156
}
159157
)
158+
jre_resolve_path_mock = Mock()
159+
jre_resolve_path_mock.path = pathlib.Path("jre/bin/java")
160+
scanner_engine_mock = pathlib.Path("/test/scanner-engine.jar")
160161

161-
scannerengine.ScannerEngine(sq_api_utils.get_sq_cloud(), cache.get_default()).run(config)
162+
scannerengine.ScannerEngine(jre_resolve_path_mock, scanner_engine_mock).run(config)
162163

163164
execute_mock.assert_called_once_with(
164165
[pathlib.Path("jre/bin/java"), "-jar", pathlib.Path("/test/scanner-engine.jar")], expected_std_in
165166
)
166167

167-
def test_version_check(self):
168-
with self.subTest("SQ:Server is too old"):
169-
sq_cloud_api = sq_api_utils.get_sq_server()
170-
sq_cloud_api.get_analysis_version = Mock(return_value=SQVersion.from_str("9.9.9"))
171-
scannerengine = ScannerEngine(sq_cloud_api, cache.get_default())
172-
173-
with self.assertRaises(SQTooOldException):
174-
scannerengine._ScannerEngine__version_check()
175-
176-
with self.subTest("SQ:Server that is new than 10.6"):
177-
sq_cloud_api = sq_api_utils.get_sq_server()
178-
sq_cloud_api.get_analysis_version = Mock(return_value=SQVersion.from_str("10.7"))
179-
scannerengine = ScannerEngine(sq_cloud_api, cache.get_default())
180-
181-
scannerengine._ScannerEngine__version_check()
182-
183-
sq_cloud_api.get_analysis_version.assert_called_once()
184-
185-
with self.subTest("SQ:Cloud "):
186-
sq_cloud_api = sq_api_utils.get_sq_cloud()
187-
sq_cloud_api.get_analysis_version = Mock()
188-
scannerengine = ScannerEngine(sq_cloud_api, cache.get_default())
189-
190-
scannerengine._ScannerEngine__version_check()
191-
192-
sq_cloud_api.get_analysis_version.assert_not_called()
193-
194168

195169
class TestScannerEngineProvisioner(pyfakefs.TestCase):
196170
def setUp(self):

0 commit comments

Comments
 (0)