Skip to content

Commit 959ba9c

Browse files
authored
Fix-2039 (#2043)
* Bump version * Fixes #2039 * Merge branch 'branch-3.16.x' into fix-2039 * Update doc about release 3.16.1 * Adjust to 3.16.1
1 parent 4651e56 commit 959ba9c

File tree

10 files changed

+99
-13
lines changed

10 files changed

+99
-13
lines changed

conf/release.Dockerfile

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -28,11 +28,11 @@ COPY ./LICENSE .
2828
COPY ./sonar/audit sonar/audit
2929

3030
RUN pip install --upgrade pip \
31-
&& pip install sonar-tools==3.17
31+
&& pip install sonar-tools==3.16.1
3232

3333
USER ${USERNAME}
3434
WORKDIR /home/${USERNAME}
3535

36-
HEALTHCHECK --interval=180s --timeout=5s CMD [ "sonar-tools-help" ]
36+
HEALTHCHECK --interval=180s --timeout=5s CMD [ "sonar-tools" ]
3737

38-
CMD [ "sonar-tools-help" ]
38+
CMD [ "sonar-tools" ]

doc/what-is-new.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
11
# Next version
22

3+
# Version 3.16.1
4+
5+
- Patch for [Issue #2039](https://github.com/okorach/sonar-tools/issues/2039) that may affect merely all the Sonar Tools
6+
37
# Version 3.16
48

59
* `sonar-config`:

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[project]
22
name = "sonar-tools"
3-
version = "3.17"
3+
version = "3.16.1"
44
description = "A collection of utility tools for the SonarQube ecosystem"
55
authors = [
66
{name = "Olivier Korach", email = "[email protected]"},

sonar/errcodes.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,3 +69,6 @@
6969
OBJECT_NOT_FOUND = 16
7070

7171
SONAR_INTERNAL_ERROR = 17
72+
73+
74+
TOO_MANY_RESULTS = 18

sonar/exceptions.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,3 +75,11 @@ class ConnectionError(SonarException):
7575

7676
def __init__(self, message: str) -> None:
7777
super().__init__(message, errcodes.CONNECTION_ERROR)
78+
79+
80+
class TooManyResults(SonarException):
81+
"""When a call to APIs returns too many results."""
82+
83+
def __init__(self, nbr_results: int, message: str) -> None:
84+
super().__init__(message, errcodes.TOO_MANY_RESULTS)
85+
self.nbr_results = nbr_results

sonar/projects.py

Lines changed: 17 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,8 @@
4040
import sonar.platform as pf
4141

4242
from sonar.util import types, cache
43+
from sonar.util import project_utils as putils
44+
4345
from sonar import exceptions, errcodes
4446
from sonar import sqobject, components, qualitygates, qualityprofiles, tasks, settings, webhooks, devops
4547
import sonar.permissions.permissions as perms
@@ -1357,14 +1359,22 @@ def count(endpoint: pf.Platform, params: types.ApiParams = None) -> int:
13571359
def search(endpoint: pf.Platform, params: types.ApiParams = None, threads: int = 8) -> dict[str, Project]:
13581360
"""Searches projects in SonarQube
13591361
1360-
:param endpoint: Reference to the SonarQube platform
1361-
:param params: list of parameters to narrow down the search
1362-
:returns: list of projects
1362+
:param Platform endpoint: Reference to the SonarQube platform
1363+
:param ApiParams params: list of filter parameters to narrow down the search
1364+
:param int threads: Number of threads to use for the search
13631365
"""
13641366
new_params = {} if params is None else params.copy()
1365-
if not endpoint.is_sonarcloud():
1367+
if not endpoint.is_sonarcloud() and not new_params.get("filter", None):
13661368
new_params["filter"] = _PROJECT_QUALIFIER
1367-
return sqobject.search_objects(endpoint=endpoint, object_class=Project, params=new_params, threads=threads)
1369+
try:
1370+
log.info("Searching projects with parameters: %s", str(new_params))
1371+
return sqobject.search_objects(endpoint=endpoint, object_class=Project, params=new_params, threads=threads)
1372+
except exceptions.TooManyResults as e:
1373+
log.warning(e.message)
1374+
filter_1, filter_2 = putils.split_loc_filter(new_params["filter"])
1375+
return search(endpoint, params={**new_params, "filter": filter_1}, threads=threads) | search(
1376+
endpoint, params={**new_params, "filter": filter_2}, threads=threads
1377+
)
13681378

13691379

13701380
def get_list(endpoint: pf.Platform, key_list: types.KeyList = None, threads: int = 8, use_cache: bool = True) -> dict[str, Project]:
@@ -1375,8 +1385,8 @@ def get_list(endpoint: pf.Platform, key_list: types.KeyList = None, threads: int
13751385
:return: the list of all projects
13761386
:rtype: dict{key: Project}
13771387
"""
1378-
with _CLASS_LOCK:
1379-
if key_list is None or len(key_list) == 0 or not use_cache:
1388+
if key_list is None or len(key_list) == 0 or not use_cache:
1389+
with _CLASS_LOCK:
13801390
log.info("Listing projects")
13811391
p_list = dict(sorted(search(endpoint=endpoint, threads=threads).items()))
13821392
return p_list

sonar/sqobject.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -242,6 +242,10 @@ def search_objects(endpoint: object, object_class: Any, params: types.ApiParams,
242242
data = __get(endpoint, api, {**new_params, p_field: 1})
243243
nb_pages = utilities.nbr_pages(data, api_version)
244244
nb_objects = max(len(data[returned_field]), utilities.nbr_total_elements(data, api_version))
245+
246+
if nb_objects > c.ELASTIC_MAX_RESULTS:
247+
raise exceptions.TooManyResults(nb_objects, f"Too many {cname}s ({nb_objects}) returned by search")
248+
245249
log.info(
246250
"Searching %d %ss, %d pages of %d elements, %d pages in parallel...",
247251
nb_objects,

sonar/util/constants.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,3 +74,5 @@
7474

7575
SQS_USERS = "sonar-users" # SonarQube Server users default group name
7676
SQC_USERS = "Members" # SonarQube Cloud users default group name
77+
78+
ELASTIC_MAX_RESULTS = 10000 # ElasticSearch max results limit

sonar/util/project_utils.py

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
#
2+
# sonar-tools
3+
# Copyright (C) 2025 Olivier Korach
4+
# mailto:olivier.korach AT gmail DOT com
5+
#
6+
# This program is free software; you can redistribute it and/or
7+
# modify it under the terms of the GNU Lesser General Public
8+
# License as published by the Free Software Foundation; either
9+
# version 3 of the License, or (at your option) any later version.
10+
#
11+
# This program is distributed in the hope that it will be useful,
12+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
13+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14+
# Lesser General Public License for more details.
15+
#
16+
# You should have received a copy of the GNU Lesser General Public License
17+
# along with this program; if not, write to the Free Software Foundation,
18+
# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
19+
#
20+
21+
import math
22+
23+
24+
def split_loc_filter(loc_filter: str) -> tuple[str, str]:
25+
"""Parses a ncloc filter and returns new filters to split the search"""
26+
__FILTER_AND = " and "
27+
loc_min, loc_max = 0, 100000000
28+
new_filters = []
29+
for f in loc_filter.split(__FILTER_AND):
30+
if f.startswith("ncloc>="):
31+
try:
32+
loc_min = int(f[len("ncloc>=") :])
33+
except ValueError:
34+
pass
35+
elif f.startswith("ncloc>"):
36+
try:
37+
loc_min = int(f[len("ncloc>") :]) + 1
38+
except ValueError:
39+
pass
40+
elif f.startswith("ncloc<="):
41+
try:
42+
loc_max = int(f[len("ncloc<=") :])
43+
except ValueError:
44+
pass
45+
elif f.startswith("ncloc<"):
46+
try:
47+
loc_max = int(f[len("ncloc<") :]) - 1
48+
except ValueError:
49+
pass
50+
else:
51+
new_filters.append(f)
52+
loc_middle = int(math.exp((math.log2(loc_max) - math.log2(max(loc_min, 1))) / 2))
53+
slice1 = __FILTER_AND.join(new_filters + [f"ncloc>={loc_min}", f"ncloc<={loc_middle}"])
54+
slice2 = __FILTER_AND.join(new_filters + [f"ncloc>{loc_middle}", f"ncloc<={loc_max}"])
55+
return slice1, slice2

sonar/version.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,5 +24,5 @@
2424
2525
"""
2626

27-
PACKAGE_VERSION = "3.17"
28-
MIGRATION_TOOL_VERSION = "0.7"
27+
PACKAGE_VERSION = "3.16.1"
28+
MIGRATION_TOOL_VERSION = "0.6-snapshot"

0 commit comments

Comments
 (0)