Skip to content

Commit 5b40b7b

Browse files
authored
PYSCAN-73: Fix download of scanner binaries for arm architecture (#75)
1 parent 0ef088d commit 5b40b7b

File tree

4 files changed

+55
-18
lines changed

4 files changed

+55
-18
lines changed

.cirrus.yml

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -84,8 +84,10 @@ analysis_task:
8484
name: "SC Analysis"
8585
analysis_script:
8686
- poetry run pytest --cov-report=xml:coverage.xml --cov-config=pyproject.toml --cov=src --cov-branch tests
87-
- poetry install
88-
- poetry run pysonar-scanner -Dsonar.organization=sonarsource -DbuildNumber=${CI_BUILD_NUMBER}
87+
- python -m venv .venv
88+
- source .venv/bin/activate
89+
- pip install .
90+
- pysonar-scanner -Dsonar.organization=sonarsource -DbuildNumber=${CI_BUILD_NUMBER}
8991
always:
9092
pytest_artifacts:
9193
path: "coverage.xml"

src/pysonar_scanner/configuration.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ class Configuration:
4141
def __init__(self):
4242
self.log = ApplicationLogger.get_logger()
4343
self.sonar_scanner_path = ".scanner"
44-
self.sonar_scanner_version = "6.0.0.4432"
44+
self.sonar_scanner_version = "6.1.0.4477"
4545
self.sonar_scanner_executable_path = ""
4646
self.scan_arguments = []
4747
self.wrapper_arguments = argparse.Namespace(debug=False, read_project_config=False)

src/pysonar_scanner/environment.py

Lines changed: 21 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ class Environment:
3737
cfg: Configuration
3838

3939
# a full download path for a scanner has the following shape:
40-
# https://binaries.sonarsource.com/Distribution/sonar-scanner-cli/sonar-scanner-cli-${version}-${os}.zip
40+
# https://binaries.sonarsource.com/Distribution/sonar-scanner-cli/sonar-scanner-cli-${version}-${os}-${arch}.zip
4141
scanner_base_url: str = "https://binaries.sonarsource.com/Distribution/sonar-scanner-cli/sonar-scanner-cli"
4242

4343
def __init__(self, cfg: Configuration):
@@ -57,16 +57,23 @@ def setup(self):
5757
self.cfg.sonar_scanner_executable_path = "sonar-scanner"
5858
else:
5959
system_name = systems.get(platform.uname().system, "linux")
60-
self._install_scanner(system_name)
60+
arch_name = self._get_platform_arch()
61+
self._install_scanner(system_name, arch_name)
6162
sonar_scanner_home = os.path.join(
6263
self.cfg.sonar_scanner_path,
63-
f"sonar-scanner-{self.cfg.sonar_scanner_version}-{system_name}",
64+
f"sonar-scanner-{self.cfg.sonar_scanner_version}-{system_name}-{arch_name}",
6465
)
6566
self.cfg.sonar_scanner_executable_path = os.path.join(sonar_scanner_home, "bin", "sonar-scanner")
6667

6768
ascii_banner = pyfiglet.figlet_format("Sonar Scanner")
6869
self.log.info(ascii_banner)
6970

71+
def _get_release(self) -> str:
72+
return platform.uname().release
73+
74+
def _get_platform_arch(self) -> str:
75+
return "x64" if "ARM64" not in self._get_release().upper() else "aarch64"
76+
7077
def scanner(self) -> Scanner:
7178
return Scanner(self.cfg)
7279

@@ -77,11 +84,14 @@ def cleanup(self):
7784
if os.path.exists(self.cfg.sonar_scanner_path):
7885
shutil.rmtree(self.cfg.sonar_scanner_path)
7986

80-
def _install_scanner(self, system_name: str):
87+
def _install_scanner(self, system_name: str, arch_name: str):
8188
os.mkdir(self.cfg.sonar_scanner_path)
8289
# Download the binaries and unzip them
8390
scanner_zip_path = self._download_scanner_binaries(
84-
self.cfg.sonar_scanner_path, self.cfg.sonar_scanner_version, system_name
91+
self.cfg.sonar_scanner_path,
92+
self.cfg.sonar_scanner_version,
93+
system_name,
94+
arch_name,
8595
)
8696
unzip_binaries(scanner_zip_path, self.cfg.sonar_scanner_path)
8797
os.remove(scanner_zip_path)
@@ -94,9 +104,13 @@ def _change_permissions_recursive(self, path, mode):
94104
for file in [os.path.join(root, f) for f in files]:
95105
os.chmod(file, mode)
96106

97-
def _download_scanner_binaries(self, destination: str, scanner_version: str, system_name: str) -> str:
107+
def _download_scanner_binaries(
108+
self, destination: str, scanner_version: str, system_name: str, arch_name: str
109+
) -> str:
98110
try:
99-
scanner_res = urllib.request.urlopen(f"{self.scanner_base_url}-{scanner_version}-{system_name}.zip")
111+
scanner_res = urllib.request.urlopen(
112+
f"{self.scanner_base_url}-{scanner_version}-{system_name}-{arch_name}.zip"
113+
)
100114
scanner_zip_path = os.path.join(destination, "scanner.zip")
101115
write_binaries(scanner_res, scanner_zip_path)
102116
return scanner_zip_path

tests/test_environment.py

Lines changed: 29 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -34,9 +34,9 @@ def test_download_scanner(self, mock_urlopen, mock_write_binaries):
3434
mock_urlopen.return_value = bytes()
3535

3636
expected_destination = "destination/scanner.zip"
37-
destination = environment._download_scanner_binaries("destination", "test_version", "os_name")
37+
destination = environment._download_scanner_binaries("destination", "test_version", "os_name", "aarch64")
3838

39-
mock_urlopen.assert_called_once_with("http://scanner.com/download-test_version-os_name.zip")
39+
mock_urlopen.assert_called_once_with("http://scanner.com/download-test_version-os_name-aarch64.zip")
4040
mock_write_binaries.assert_called_once_with(bytes(), expected_destination)
4141
assert destination == expected_destination
4242

@@ -46,12 +46,12 @@ def test_download_scanner_http_error(self, mock_urlopen, mock_write_binaries):
4646
cfg = Configuration()
4747
environment = Environment(cfg)
4848
environment.scanner_base_url = "http://scanner.com/download"
49-
url = "http://scanner.com/download-test_version-os_name.zip"
49+
url = "http://scanner.com/download-test_version-os_name-x64.zip"
5050
mock_urlopen.side_effect = Mock(side_effect=HTTPError(url, 504, "Test", {}, None))
5151

5252
with self.assertLogs(environment.log) as log:
5353
with self.assertRaises(HTTPError):
54-
environment._download_scanner_binaries("destination", "test_version", "os_name")
54+
environment._download_scanner_binaries("destination", "test_version", "os_name", "x64")
5555
mock_urlopen.assert_called_once_with(url)
5656
assert not mock_write_binaries.called
5757
expected_error_message = "ERROR: could not download scanner binaries - 504 - Test"
@@ -75,10 +75,13 @@ def test_install_scanner(self, mock_os, mock_unzip_binaries):
7575
environment._change_permissions_recursive = Mock()
7676

7777
system_name = "test"
78-
environment._install_scanner(system_name)
78+
arch_name = "arch-test"
79+
environment._install_scanner(system_name, arch_name)
7980

8081
mock_os.mkdir.assert_called_once_with(scanner_path)
81-
environment._download_scanner_binaries.assert_called_once_with(scanner_path, scanner_version, system_name)
82+
environment._download_scanner_binaries.assert_called_once_with(
83+
scanner_path, scanner_version, system_name, arch_name
84+
)
8285
mock_unzip_binaries.assert_called_once_with(download_destination, scanner_path)
8386

8487
mock_os.remove.assert_called_once_with(download_destination)
@@ -103,16 +106,19 @@ def test_setup_when_scanner_is_not_on_path(self, mock_systems):
103106
environment = Environment(cfg)
104107
environment.cleanup = Mock()
105108
system_name = "test"
109+
arch_name = "arch-test"
110+
environment._get_platform_arch = Mock(return_value=arch_name)
106111
mock_systems.get = Mock(return_value=system_name)
107112
environment._is_sonar_scanner_on_path = Mock(return_value=False)
108113
environment._install_scanner = Mock()
109-
expected_path = "path/sonar-scanner-4.1.2-test/bin/sonar-scanner"
114+
expected_path = "path/sonar-scanner-4.1.2-test-arch-test/bin/sonar-scanner"
110115

111116
environment.setup()
112117

113118
environment.cleanup.assert_called_once()
114119
mock_systems.get.assert_called_once()
115-
environment._install_scanner.assert_called_once_with(system_name)
120+
environment._get_platform_arch.assert_called_once()
121+
environment._install_scanner.assert_called_once_with(system_name, arch_name)
116122

117123
assert cfg.sonar_scanner_executable_path == expected_path
118124

@@ -158,6 +164,21 @@ def test_is_sonar_scanner_on_path(self, mock_shutil):
158164

159165
mock_shutil.which.assert_called_once_with("sonar-scanner")
160166

167+
def test_get_platform_arch(self):
168+
release_names = ["root:test/release_arm64_T8101", "6.0.1-generic", "root:xnu-7195.60.75~1/RELEASE_ARM64_T8101"]
169+
170+
def releases():
171+
return release_names.pop(0)
172+
173+
cfg = Configuration()
174+
cfg.sonar_scanner_path = "path"
175+
cfg.sonar_scanner_version = "4.1.2"
176+
environment = Environment(cfg)
177+
environment._get_release = Mock(side_effect=releases)
178+
assert environment._get_platform_arch() == "aarch64"
179+
assert environment._get_platform_arch() == "x64"
180+
assert environment._get_platform_arch() == "aarch64"
181+
161182
def test_env_scan(self):
162183
cfg = Configuration()
163184
environment = Environment(cfg)

0 commit comments

Comments
 (0)