Skip to content

Commit 904ba5a

Browse files
authored
Merge pull request #1384 from okorach:export-sync-if-no-output-file
Export-sync-if-no-output-file
2 parents e0a06af + 17bf293 commit 904ba5a

File tree

6 files changed

+149
-19
lines changed

6 files changed

+149
-19
lines changed

cli/config.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -255,7 +255,8 @@ def __export_config_async(endpoint: platform.Platform, what: list[str], **kwargs
255255

256256

257257
def __export_config(endpoint: platform.Platform, what: list[str], **kwargs) -> None:
258-
if kwargs[options.KEYS] or options.WHAT_PROJECTS not in what or kwargs[options.FORMAT] != "json":
258+
"""Exports the configuration of the SonarQube platform"""
259+
if kwargs[options.KEYS] or options.WHAT_PROJECTS not in what or kwargs[options.FORMAT] != "json" or not kwargs[options.REPORT_FILE]:
259260
__export_config_sync(endpoint=endpoint, what=what, **kwargs)
260261
else:
261262
__export_config_async(endpoint=endpoint, what=what, **kwargs)

sonar/organizations.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,9 @@ def get_object(cls, endpoint: pf.Platform, key: str) -> Organization:
8282
except HTTPError as e:
8383
if e.response.status_code == HTTPStatus.NOT_FOUND:
8484
raise exceptions.ObjectNotFound(key, f"Organization '{key}' not found")
85+
raise e
86+
if len(data["organizations"]) == 0:
87+
raise exceptions.ObjectNotFound(key, f"Organization '{key}' not found")
8588
return cls.load(endpoint, data["organizations"][0])
8689

8790
@classmethod
@@ -99,7 +102,7 @@ def load(cls, endpoint: pf.Platform, data: types.ApiPayload) -> Organization:
99102
raise exceptions.UnsupportedOperation(_NOT_SUPPORTED)
100103
uu = sqobject.uuid(data["key"], endpoint.url)
101104
o = _OBJECTS.get(uu, cls(endpoint, data["key"], data["name"]))
102-
o.json_data = data
105+
o._json = data
103106
o.name = data["name"]
104107
o.description = data["description"]
105108
return o

sonar/projects.py

Lines changed: 21 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -987,6 +987,27 @@ def __get_branch_export(self, export_settings: types.ConfigSettings) -> Optional
987987
return None
988988
return util.remove_nones(branch_data)
989989

990+
def migration_export(self, export_settings: types.ConfigSettings) -> types.ObjectJsonRepr:
991+
"""Produces the data that is exported for SQ to SC migration"""
992+
json_data = super().migration_export(export_settings)
993+
json_data["detectedCi"] = self.ci()
994+
json_data["revision"] = self.revision()
995+
last_task = self.last_task()
996+
json_data["backgroundTasks"] = {}
997+
if last_task:
998+
ctxt = last_task.scanner_context()
999+
if ctxt:
1000+
ctxt = {k: v for k, v in ctxt.items() if k not in _UNNEEDED_CONTEXT_DATA}
1001+
t_hist = []
1002+
for t in self.task_history():
1003+
t_hist.append({k: v for k, v in t._json.items() if k not in _UNNEEDED_TASK_DATA})
1004+
json_data["backgroundTasks"] = {
1005+
"lastTaskScannerContext": ctxt,
1006+
# "lastTaskWarnings": last_task.warnings(),
1007+
"taskHistory": t_hist,
1008+
}
1009+
return json_data
1010+
9901011
def export(self, export_settings: types.ConfigSettings, settings_list: dict[str, str] = None) -> types.ObjectJsonRepr:
9911012
"""Exports the entire project configuration as JSON
9921013
@@ -1018,22 +1039,6 @@ def export(self, export_settings: types.ConfigSettings, settings_list: dict[str,
10181039

10191040
if export_settings.get("MODE", "") == "MIGRATION":
10201041
json_data.update(self.migration_export(export_settings))
1021-
json_data["detectedCi"] = self.ci()
1022-
json_data["revision"] = self.revision()
1023-
last_task = self.last_task()
1024-
json_data["backgroundTasks"] = {}
1025-
if last_task:
1026-
ctxt = last_task.scanner_context()
1027-
if ctxt:
1028-
ctxt = {k: v for k, v in ctxt.items() if k not in _UNNEEDED_CONTEXT_DATA}
1029-
t_hist = []
1030-
for t in self.task_history():
1031-
t_hist.append({k: v for k, v in t._json.items() if k not in _UNNEEDED_TASK_DATA})
1032-
json_data["backgroundTasks"] = {
1033-
"lastTaskScannerContext": ctxt,
1034-
# "lastTaskWarnings": last_task.warnings(),
1035-
"taskHistory": t_hist,
1036-
}
10371042

10381043
settings_dict = settings.get_bulk(endpoint=self.endpoint, component=self, settings_list=settings_list, include_not_set=False)
10391044
# json_data.update({s.to_json() for s in settings_dict.values() if include_inherited or not s.inherited})

sonar/sqobject.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -134,7 +134,7 @@ def search_objects(endpoint: object, object_class: any, params: types.ApiParams,
134134
objects_list = {}
135135
data = json.loads(endpoint.get(api, params=new_params).text)
136136
for obj in data[returned_field]:
137-
if object_class.__name__ in ("Portfolio", "Group", "QualityProfile", "User", "Application", "Project"):
137+
if object_class.__name__ in ("Portfolio", "Group", "QualityProfile", "User", "Application", "Project", "Organization"):
138138
objects_list[obj[key_field]] = object_class.load(endpoint=endpoint, data=obj)
139139
else:
140140
objects_list[obj[key_field]] = object_class(endpoint, obj[key_field], data=obj)

test/test_sonarcloud.py

Lines changed: 120 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,120 @@
1+
#!/usr/bin/env python3
2+
#
3+
# sonar-tools tests
4+
# Copyright (C) 2024 Olivier Korach
5+
# mailto:olivier.korach AT gmail DOT com
6+
#
7+
# This program is free software; you can redistribute it and/or
8+
# modify it under the terms of the GNU Lesser General Public
9+
# License as published by the Free Software Foundation; either
10+
# version 3 of the License, or (at your option) any later version.
11+
#
12+
# This program is distributed in the hope that it will be useful,
13+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
14+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15+
# Lesser General Public License for more details.
16+
#
17+
# You should have received a copy of the GNU Lesser General Public License
18+
# along with this program; if not, write to the Free Software Foundation,
19+
# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20+
#
21+
""" sonarcloud tests """
22+
23+
import os
24+
import sys
25+
from unittest.mock import patch
26+
import pytest
27+
28+
import utilities as util
29+
from sonar import errcodes, exceptions
30+
from sonar import organizations
31+
import cli.options as opt
32+
from cli import config
33+
34+
CMD = "config.py"
35+
SC_OPTS = [f"-{opt.URL_SHORT}", "https://sonarcloud.io", f"-{opt.TOKEN_SHORT}", os.getenv("SONAR_TOKEN_SONARCLOUD")]
36+
37+
OPTS = [CMD] + SC_OPTS + [f"-{opt.EXPORT_SHORT}", f"-{opt.REPORT_FILE_SHORT}", util.JSON_FILE]
38+
MY_ORG_1 = "okorach"
39+
MY_ORG_2 = "okorach-github"
40+
41+
def test_sc_config_export() -> None:
42+
"""test_sc_config_export"""
43+
util.clean(util.JSON_FILE)
44+
with pytest.raises(SystemExit) as e:
45+
with patch.object(sys, "argv", OPTS + [f"-{opt.ORG_SHORT}", "okorach"]):
46+
config.main()
47+
assert int(str(e.value)) == errcodes.OK
48+
assert util.file_not_empty(util.JSON_FILE)
49+
util.clean(util.JSON_FILE)
50+
51+
52+
def test_sc_config_export_no_org() -> None:
53+
"""test_sc_config_export"""
54+
util.clean(util.JSON_FILE)
55+
with pytest.raises(SystemExit) as e:
56+
with patch.object(sys, "argv", OPTS):
57+
config.main()
58+
assert int(str(e.value)) == errcodes.ARGS_ERROR
59+
assert not os.path.isfile(util.JSON_FILE)
60+
61+
62+
def test_org_search() -> None:
63+
"""test_org_search"""
64+
org_list = organizations.search(endpoint=util.SC)
65+
assert MY_ORG_1 in org_list
66+
assert MY_ORG_2 in org_list
67+
68+
69+
def test_org_get_list() -> None:
70+
"""test_org_search"""
71+
org_list = organizations.get_list(endpoint=util.SC)
72+
assert MY_ORG_1 in org_list
73+
assert MY_ORG_2 in org_list
74+
75+
org_list = organizations.get_list(endpoint=util.SC, key_list=[MY_ORG_1])
76+
assert MY_ORG_1 in org_list
77+
assert MY_ORG_2 not in org_list
78+
79+
80+
def test_org_get_non_existing() -> None:
81+
"""test_org_search_sq"""
82+
with pytest.raises(exceptions.ObjectNotFound):
83+
_ = organizations.Organization.get_object(endpoint=util.SC, key="oko_foo_bar")
84+
85+
with pytest.raises(exceptions.ObjectNotFound):
86+
_ = organizations.get_list(endpoint=util.SC, key_list=["oko_foo_bar"])
87+
88+
89+
def test_org_str() -> None:
90+
"""test_org_str"""
91+
org = organizations.Organization.get_object(endpoint=util.SC, key=MY_ORG_1)
92+
assert str(org) == f"organization key '{MY_ORG_1}'"
93+
94+
95+
def test_org_export() -> None:
96+
"""test_org_export"""
97+
org = organizations.Organization.get_object(endpoint=util.SC, key=MY_ORG_1)
98+
exp = org.export()
99+
assert "newCodePeriod" in exp
100+
101+
102+
def test_org_attr() -> None:
103+
"""test_org_attr"""
104+
org = organizations.Organization.get_object(endpoint=util.SC, key=MY_ORG_1)
105+
assert org.key == MY_ORG_1
106+
assert org.name == "Olivier Korach"
107+
assert org._json["url"] == "https://github.com/okorach"
108+
(nc_type, nc_val) = org.new_code_period()
109+
assert nc_type == "PREVIOUS_VERSION"
110+
assert org.subscription() == "FREE"
111+
assert org.alm()["key"] == "github"
112+
113+
114+
def test_org_search_sq() -> None:
115+
"""test_org_search_sq"""
116+
with pytest.raises(exceptions.UnsupportedOperation):
117+
_ = organizations.search(endpoint=util.SQ)
118+
119+
with pytest.raises(exceptions.UnsupportedOperation):
120+
_ = organizations.get_list(endpoint=util.SQ)

test/utilities.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@
4343
CE_OPTS = [f"-{opt.URL_SHORT}", LATEST_CE, f"-{opt.TOKEN_SHORT}", os.getenv("SONAR_TOKEN_ADMIN_USER")]
4444

4545
SQ = platform.Platform(url=os.getenv("SONAR_HOST_URL"), token=os.getenv("SONAR_TOKEN_ADMIN_USER"))
46+
SC = platform.Platform(url="https://sonarcloud.io", token=os.getenv("SONAR_TOKEN_SONARCLOUD"))
4647
TEST_SQ = platform.Platform(url=LATEST_TEST, token=os.getenv("SONAR_TOKEN_ADMIN_USER"))
4748

4849

0 commit comments

Comments
 (0)