argus-alm 0.12.10__py3-none-any.whl → 0.13.1__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (94) hide show
  1. argus/client/base.py +1 -1
  2. argus/client/driver_matrix_tests/cli.py +2 -2
  3. argus/client/driver_matrix_tests/client.py +1 -1
  4. argus/client/generic/cli.py +22 -2
  5. argus/client/generic/client.py +22 -0
  6. argus/client/generic_result.py +3 -3
  7. argus/client/sct/client.py +5 -4
  8. argus/client/sirenada/client.py +1 -1
  9. {argus_alm-0.12.10.dist-info → argus_alm-0.13.1.dist-info}/METADATA +2 -4
  10. argus_alm-0.13.1.dist-info/RECORD +20 -0
  11. argus/backend/.gitkeep +0 -0
  12. argus/backend/cli.py +0 -41
  13. argus/backend/controller/__init__.py +0 -0
  14. argus/backend/controller/admin.py +0 -20
  15. argus/backend/controller/admin_api.py +0 -354
  16. argus/backend/controller/api.py +0 -529
  17. argus/backend/controller/auth.py +0 -67
  18. argus/backend/controller/client_api.py +0 -108
  19. argus/backend/controller/main.py +0 -274
  20. argus/backend/controller/notification_api.py +0 -72
  21. argus/backend/controller/notifications.py +0 -13
  22. argus/backend/controller/team.py +0 -126
  23. argus/backend/controller/team_ui.py +0 -18
  24. argus/backend/controller/testrun_api.py +0 -482
  25. argus/backend/controller/view_api.py +0 -162
  26. argus/backend/db.py +0 -100
  27. argus/backend/error_handlers.py +0 -21
  28. argus/backend/events/event_processors.py +0 -34
  29. argus/backend/models/__init__.py +0 -0
  30. argus/backend/models/result.py +0 -138
  31. argus/backend/models/web.py +0 -389
  32. argus/backend/plugins/__init__.py +0 -0
  33. argus/backend/plugins/core.py +0 -225
  34. argus/backend/plugins/driver_matrix_tests/controller.py +0 -63
  35. argus/backend/plugins/driver_matrix_tests/model.py +0 -421
  36. argus/backend/plugins/driver_matrix_tests/plugin.py +0 -22
  37. argus/backend/plugins/driver_matrix_tests/raw_types.py +0 -62
  38. argus/backend/plugins/driver_matrix_tests/service.py +0 -60
  39. argus/backend/plugins/driver_matrix_tests/udt.py +0 -42
  40. argus/backend/plugins/generic/model.py +0 -79
  41. argus/backend/plugins/generic/plugin.py +0 -16
  42. argus/backend/plugins/generic/types.py +0 -13
  43. argus/backend/plugins/loader.py +0 -40
  44. argus/backend/plugins/sct/controller.py +0 -185
  45. argus/backend/plugins/sct/plugin.py +0 -38
  46. argus/backend/plugins/sct/resource_setup.py +0 -178
  47. argus/backend/plugins/sct/service.py +0 -491
  48. argus/backend/plugins/sct/testrun.py +0 -272
  49. argus/backend/plugins/sct/udt.py +0 -101
  50. argus/backend/plugins/sirenada/model.py +0 -113
  51. argus/backend/plugins/sirenada/plugin.py +0 -17
  52. argus/backend/service/admin.py +0 -27
  53. argus/backend/service/argus_service.py +0 -688
  54. argus/backend/service/build_system_monitor.py +0 -188
  55. argus/backend/service/client_service.py +0 -122
  56. argus/backend/service/event_service.py +0 -18
  57. argus/backend/service/jenkins_service.py +0 -240
  58. argus/backend/service/notification_manager.py +0 -150
  59. argus/backend/service/release_manager.py +0 -230
  60. argus/backend/service/results_service.py +0 -317
  61. argus/backend/service/stats.py +0 -540
  62. argus/backend/service/team_manager_service.py +0 -83
  63. argus/backend/service/testrun.py +0 -559
  64. argus/backend/service/user.py +0 -307
  65. argus/backend/service/views.py +0 -258
  66. argus/backend/template_filters.py +0 -27
  67. argus/backend/tests/__init__.py +0 -0
  68. argus/backend/tests/argus_web.test.yaml +0 -39
  69. argus/backend/tests/conftest.py +0 -44
  70. argus/backend/tests/results_service/__init__.py +0 -0
  71. argus/backend/tests/results_service/test_best_results.py +0 -70
  72. argus/backend/util/common.py +0 -65
  73. argus/backend/util/config.py +0 -38
  74. argus/backend/util/encoders.py +0 -41
  75. argus/backend/util/logsetup.py +0 -81
  76. argus/backend/util/module_loaders.py +0 -30
  77. argus/backend/util/send_email.py +0 -91
  78. argus/client/generic_result_old.py +0 -143
  79. argus/db/.gitkeep +0 -0
  80. argus/db/argus_json.py +0 -14
  81. argus/db/cloud_types.py +0 -125
  82. argus/db/config.py +0 -135
  83. argus/db/db_types.py +0 -139
  84. argus/db/interface.py +0 -370
  85. argus/db/testrun.py +0 -740
  86. argus/db/utils.py +0 -15
  87. argus_alm-0.12.10.dist-info/RECORD +0 -96
  88. /argus/{backend → common}/__init__.py +0 -0
  89. /argus/{backend/util → common}/enums.py +0 -0
  90. /argus/{backend/plugins/sct/types.py → common/sct_types.py} +0 -0
  91. /argus/{backend/plugins/sirenada/types.py → common/sirenada_types.py} +0 -0
  92. {argus_alm-0.12.10.dist-info → argus_alm-0.13.1.dist-info}/LICENSE +0 -0
  93. {argus_alm-0.12.10.dist-info → argus_alm-0.13.1.dist-info}/WHEEL +0 -0
  94. {argus_alm-0.12.10.dist-info → argus_alm-0.13.1.dist-info}/entry_points.txt +0 -0
@@ -1,188 +0,0 @@
1
- import logging
2
- from abc import ABC, abstractmethod
3
- import jenkins
4
- import click
5
- import re
6
- from flask import current_app
7
- from flask.cli import with_appcontext
8
-
9
- from argus.backend.db import ScyllaCluster
10
- from argus.backend.models.web import ArgusRelease, ArgusGroup, ArgusTest, ArgusTestException
11
- from argus.backend.service.release_manager import ReleaseManagerService
12
-
13
- LOGGER = logging.getLogger(__name__)
14
-
15
-
16
- class ArgusTestsMonitor(ABC):
17
- BUILD_SYSTEM_FILTERED_PREFIXES = [
18
-
19
- ]
20
-
21
- def __init__(self) -> None:
22
- self._cluster = ScyllaCluster.get()
23
- self._existing_releases = list(ArgusRelease.objects().limit(None))
24
- self._existing_groups = list(ArgusGroup.objects().limit(None))
25
- self._existing_tests = list(ArgusTest.objects().limit(None))
26
- self._filtered_groups: list[str] = self.BUILD_SYSTEM_FILTERED_PREFIXES
27
-
28
- def create_release(self, release_name):
29
- # pylint: disable=no-self-use
30
- release = ArgusRelease()
31
- release.name = release_name
32
- release.save()
33
-
34
- return release
35
-
36
- def create_group(self, release: ArgusRelease, group_name: str, build_id: str, group_pretty_name: str | None = None):
37
- # pylint: disable=no-self-use
38
- group = ArgusGroup()
39
- group.release_id = release.id
40
- group.name = group_name
41
- group.build_system_id = build_id
42
- if group_pretty_name:
43
- group.pretty_name = group_pretty_name
44
- group.save()
45
-
46
- return group
47
-
48
- def create_test(self, release: ArgusRelease, group: ArgusGroup,
49
- test_name: str, build_id: str, build_url: str) -> ArgusTest:
50
- # pylint: disable=no-self-use
51
- test = ArgusTest()
52
- test.name = test_name
53
- test.group_id = group.id
54
- test.release_id = release.id
55
- test.build_system_id = build_id
56
- test.build_system_url = build_url
57
- test.validate_build_system_id()
58
- test.save()
59
- ReleaseManagerService().move_test_runs(test)
60
-
61
- return test
62
-
63
- @abstractmethod
64
- def collect(self):
65
- raise NotImplementedError()
66
-
67
- def check_filter(self, group_name: str) -> bool:
68
- for prefix in self._filtered_groups:
69
- if prefix.lower() in group_name.lower():
70
- return False
71
-
72
- return True
73
-
74
-
75
- class JenkinsMonitor(ArgusTestsMonitor):
76
-
77
- BUILD_SYSTEM_FILTERED_PREFIXES = [
78
- "releng",
79
- ]
80
-
81
- JENKINS_MONITORED_RELEASES = [
82
- r"^scylla-master$",
83
- r"^scylla-staging$",
84
- r"^scylla-\d+\.\d+$",
85
- r"^manager-3.\d+$",
86
- r"^scylla-operator/operator-master$",
87
- r"^scylla-operator/operator-\d+.\d+$",
88
- r"^scylla-enterprise$",
89
- r"^enterprise-20\d{2}\.\d+$",
90
- r"^siren-tests$",
91
- ]
92
-
93
- def __init__(self) -> None:
94
- super().__init__()
95
- self._jenkins = jenkins.Jenkins(url=current_app.config["JENKINS_URL"],
96
- username=current_app.config["JENKINS_USER"],
97
- password=current_app.config["JENKINS_API_TOKEN"])
98
- self._monitored_releases = self.JENKINS_MONITORED_RELEASES
99
-
100
- def _check_release_name(self, release_name: str):
101
- return any(re.match(pattern, release_name, re.IGNORECASE) for pattern in self._monitored_releases)
102
-
103
- def collect(self):
104
- click.echo("Collecting new tests from jenkins")
105
- all_jobs = self._jenkins.get_all_jobs()
106
- all_monitored_folders = [job for job in all_jobs if self._check_release_name(job["fullname"])]
107
- LOGGER.info("Will collect %s", [f["fullname"] for f in all_monitored_folders])
108
-
109
- for release in all_monitored_folders:
110
- LOGGER.info("Processing release %s", release["name"])
111
- try:
112
- saved_release = ArgusRelease.get(name=release["name"])
113
- LOGGER.info("Release %s exists", release["name"])
114
- except ArgusRelease.DoesNotExist:
115
- LOGGER.warning("Release %s does not exist, creating...", release["name"])
116
- saved_release = self.create_release(release["name"])
117
- self._existing_releases.append(saved_release)
118
-
119
- try:
120
- groups = self.collect_groups_for_release(release["jobs"])
121
- except KeyError:
122
- LOGGER.error("Empty release!\n %s", release)
123
- continue
124
- folder_stack = [dict(parent_name="", parent_display_name="", group=g) for g in reversed(groups)]
125
- root_folder = {
126
- "parent_name": "",
127
- "parent_display_name": "",
128
- "group": {
129
- "name": f"{release['fullname']}-root",
130
- "displayName": "-- root directory --",
131
- "fullname": release["fullname"],
132
- "jobs": self.collect_root_folder_jobs(release["jobs"]),
133
- }
134
- }
135
- folder_stack.append(root_folder)
136
- while len(folder_stack) != 0:
137
- group_dict = folder_stack.pop()
138
- group = group_dict["group"]
139
- LOGGER.info("Processing group %s for release %s", group["name"], saved_release.name)
140
- try:
141
- group_name = group["name"] if not group_dict["parent_name"] else f"{group_dict['parent_name']}-{group['name']}"
142
- saved_group = filter(lambda g: g.build_system_id == group["fullname"], self._existing_groups)
143
- saved_group = next(saved_group)
144
- LOGGER.info("Group %s already exists. (id: %s)", saved_group.build_system_id, saved_group.id)
145
- except StopIteration:
146
- LOGGER.warning(
147
- "Group %s for release %s doesn't exist, creating...", group_name, saved_release.name)
148
- try:
149
- display_name = group.get("displayName", self._jenkins.get_job_info(name=group["fullname"])["displayName"])
150
- display_name = display_name if not group_dict[
151
- "parent_display_name"] else f"{group_dict['parent_display_name']} - {display_name}"
152
- except Exception:
153
- display_name = None
154
-
155
- saved_group = self.create_group(saved_release, group_name, group["fullname"], display_name)
156
- self._existing_groups.append(saved_group)
157
-
158
- for job in group["jobs"]:
159
- LOGGER.info("Processing job %s for release %s and group %s",
160
- job["fullname"], saved_group.name, saved_release.name)
161
- saved_test = None
162
- if "Folder" in job["_class"]:
163
- folder_stack.append(dict(parent_name=saved_group.name,
164
- parent_display_name=saved_group.pretty_name, group=job))
165
- if "WorkflowJob" in job["_class"]:
166
- try:
167
- saved_test = filter(lambda t: t.build_system_id == job["fullname"], self._existing_tests)
168
- saved_test = next(saved_test)
169
- LOGGER.info("Test %s already exists. (id: %s)", saved_test.build_system_id, saved_test.id)
170
- except StopIteration:
171
- LOGGER.warning("Test %s for release %s (group %s) doesn't exist, creating...",
172
- job["name"], saved_release.name, saved_group.name)
173
- try:
174
- saved_test = self.create_test(
175
- saved_release, saved_group, job["name"], job["fullname"], job["url"])
176
- self._existing_tests.append(saved_test)
177
- except ArgusTestException:
178
- LOGGER.error("Unable to create test for build_id %s", job["fullname"], exc_info=True)
179
-
180
- def collect_groups_for_release(self, jobs):
181
- # pylint: disable=no-self-use
182
- groups = [folder for folder in jobs if "Folder" in folder["_class"]]
183
- groups = [group for group in groups if self.check_filter(group["name"])]
184
-
185
- return groups
186
-
187
- def collect_root_folder_jobs(self, jobs):
188
- return [job for job in jobs if "WorkflowJob" in job["_class"]]
@@ -1,122 +0,0 @@
1
- import operator
2
- from dataclasses import asdict, is_dataclass
3
- from datetime import datetime, timezone
4
- from functools import partial
5
- from uuid import UUID
6
-
7
- from argus.backend.db import ScyllaCluster
8
- from argus.backend.models.result import ArgusGenericResultMetadata, ArgusGenericResultData
9
- from argus.backend.plugins.core import PluginModelBase
10
- from argus.backend.plugins.loader import AVAILABLE_PLUGINS
11
- from argus.backend.service.results_service import ResultsService, Cell
12
- from argus.backend.util.enums import TestStatus
13
-
14
-
15
- class ClientException(Exception):
16
- pass
17
-
18
-
19
- class ClientService:
20
- PLUGINS = {name: plugin.model for name, plugin in AVAILABLE_PLUGINS.items()}
21
-
22
- def __init__(self) -> None:
23
- self.cluster = ScyllaCluster.get()
24
-
25
- def get_model(self, run_type: str) -> PluginModelBase:
26
- cls = self.PLUGINS.get(run_type)
27
- if not cls:
28
- raise ClientException(f"Unsupported run type: {run_type}", run_type)
29
- return cls
30
-
31
- def submit_run(self, run_type: str, request_data: dict) -> str:
32
- model = self.get_model(run_type)
33
- model.submit_run(request_data=request_data)
34
-
35
- return "Created"
36
-
37
- def get_run(self, run_type: str, run_id: str):
38
- model = self.get_model(run_type)
39
- try:
40
- run = model.get(id=run_id)
41
- except model.DoesNotExist:
42
- return None
43
- return run
44
-
45
- def heartbeat(self, run_type: str, run_id: str) -> int:
46
- model = self.get_model(run_type)
47
- run = model.load_test_run(UUID(run_id))
48
- run.update_heartbeat()
49
- run.save()
50
- return run.heartbeat
51
-
52
- def get_run_status(self, run_type: str, run_id: str) -> str:
53
- model = self.get_model(run_type)
54
- run = model.load_test_run(UUID(run_id))
55
- return run.status
56
-
57
- def update_run_status(self, run_type: str, run_id: str, new_status: str) -> str:
58
- model = self.get_model(run_type)
59
- run = model.load_test_run(UUID(run_id))
60
- run.change_status(new_status=TestStatus(new_status))
61
- run.save()
62
-
63
- return run.status
64
-
65
- def submit_product_version(self, run_type: str, run_id: str, version: str) -> str:
66
- model = self.get_model(run_type)
67
- run = model.load_test_run(UUID(run_id))
68
- run.submit_product_version(version)
69
- run.save()
70
-
71
- return "Submitted"
72
-
73
- def submit_logs(self, run_type: str, run_id: str, logs: list[dict]) -> str:
74
- model = self.get_model(run_type)
75
- run = model.load_test_run(UUID(run_id))
76
- run.submit_logs(logs)
77
- run.save()
78
-
79
- return "Submitted"
80
-
81
- def finish_run(self, run_type: str, run_id: str, payload: dict | None = None) -> str:
82
- model = self.get_model(run_type)
83
- run = model.load_test_run(UUID(run_id))
84
- run.finish_run(payload)
85
- run.save()
86
-
87
- return "Finalized"
88
-
89
- def submit_results(self, run_type: str, run_id: str, results: dict) -> dict[str, str]:
90
- model = self.get_model(run_type)
91
- try:
92
- run = model.load_test_run(UUID(run_id))
93
- except model.DoesNotExist:
94
- return {"status": "error", "response": {
95
- "exception": "DoesNotExist",
96
- "arguments": [run_id]
97
- }}
98
- table_name = results["meta"]["name"]
99
- results_service = ResultsService()
100
- cells = [Cell(**cell) for cell in results["results"]]
101
- table_metadata = results_service.get_table_metadata(test_id=run.test_id, table_name=table_name)
102
- if table_metadata:
103
- table_metadata = table_metadata.update_if_changed(results["meta"])
104
- else:
105
- table_metadata = ArgusGenericResultMetadata(test_id=run.test_id, **results["meta"])
106
- table_metadata.save()
107
- if results.get("sut_timestamp", 0) == 0:
108
- results["sut_timestamp"] = run.sut_timestamp() # automatic sut_timestamp
109
- results["sut_timestamp"] = datetime.fromtimestamp(results["sut_timestamp"])
110
- best_results = results_service.update_best_results(test_id=run.test_id, table_name=table_name, table_metadata=table_metadata,
111
- cells=cells, run_id=run_id)
112
- table_name = results["meta"]["name"]
113
- sut_timestamp = results["sut_timestamp"]
114
- for cell in cells:
115
- cell.update_cell_status_based_on_rules(table_metadata, best_results)
116
- ArgusGenericResultData(test_id=run.test_id,
117
- run_id=run.id,
118
- name=table_name,
119
- sut_timestamp=sut_timestamp,
120
- **asdict(cell)
121
- ).save()
122
- return {"status": "ok", "message": "Results submitted"}
@@ -1,18 +0,0 @@
1
- from datetime import datetime
2
- import json
3
- from argus.backend.models.web import ArgusEvent, ArgusEventTypes
4
-
5
-
6
- class EventService:
7
- @staticmethod
8
- def create_run_event(kind: ArgusEventTypes, body: dict, user_id=None, run_id=None, release_id=None, group_id=None, test_id=None):
9
- event = ArgusEvent()
10
- event.release_id = release_id
11
- event.group_id = group_id
12
- event.test_id = test_id
13
- event.user_id = user_id
14
- event.run_id = run_id
15
- event.body = json.dumps(body, ensure_ascii=True, separators=(',', ':'))
16
- event.kind = kind.value
17
- event.created_at = datetime.utcnow()
18
- event.save()
@@ -1,240 +0,0 @@
1
- import re
2
- import requests
3
- from typing import Any, TypedDict
4
- from uuid import UUID
5
- import xml.etree.ElementTree as ET
6
- import jenkins
7
- import logging
8
-
9
- from flask import current_app, g
10
-
11
- from argus.backend.models.web import ArgusGroup, ArgusRelease, ArgusTest, UserOauthToken
12
-
13
- LOGGER = logging.getLogger(__name__)
14
- GITHUB_REPO_RE = r"(?P<http>^https?:\/\/(www\.)?github\.com\/(?P<user>[\w\d\-]+)\/(?P<repo>[\w\d\-]+)(\.git)?$)|(?P<ssh>git@github\.com:(?P<ssh_user>[\w\d\-]+)\/(?P<ssh_repo>[\w\d\-]+)(\.git)?)"
15
-
16
- class Parameter(TypedDict):
17
- _class: str
18
- name: str
19
- description: str
20
- value: Any
21
-
22
-
23
- class JenkinsServiceError(Exception):
24
- pass
25
-
26
-
27
- class JenkinsService:
28
- RESERVED_PARAMETER_NAME = "requested_by_user"
29
-
30
- SETTINGS_CONFIG_MAP = {
31
- "scylla-cluster-tests": {
32
- "gitRepo": "*//scm/userRemoteConfigs/hudson.plugins.git.UserRemoteConfig/url",
33
- "gitBranch": "*//scm/branches/hudson.plugins.git.BranchSpec/name",
34
- "pipelineFile": "*//scriptPath",
35
- },
36
- "driver-matrix-tests": {
37
- "gitRepo": "*//scm/userRemoteConfigs/hudson.plugins.git.UserRemoteConfig/url",
38
- "gitBranch": "*//scm/branches/hudson.plugins.git.BranchSpec/name",
39
- "pipelineFile": "*//scriptPath",
40
- },
41
- "sirenada": {
42
- "gitRepo": "*//scm/userRemoteConfigs/hudson.plugins.git.UserRemoteConfig/url",
43
- "gitBranch": "*//scm/branches/hudson.plugins.git.BranchSpec/name",
44
- "pipelineFile": "*//scriptPath",
45
- }
46
- }
47
-
48
- def __init__(self) -> None:
49
- self._jenkins = jenkins.Jenkins(url=current_app.config["JENKINS_URL"],
50
- username=current_app.config["JENKINS_USER"],
51
- password=current_app.config["JENKINS_API_TOKEN"])
52
-
53
- def retrieve_job_parameters(self, build_id: str, build_number: int) -> list[Parameter]:
54
- job_info = self._jenkins.get_build_info(name=build_id, number=build_number)
55
- raw_config = self._jenkins.get_job_config(name=build_id)
56
- config = ET.fromstring(raw_config)
57
- parameter_defs = config.find("*//parameterDefinitions")
58
- if parameter_defs:
59
- descriptions = {
60
- define.findtext("name"): f"{define.findtext('description', '')}" + f" (default: <span class=\"fw-bold\">{define.findtext('defaultValue')}</span>)" if define.findtext('defaultValue') else ""
61
- for define in parameter_defs.iterfind("hudson.model.StringParameterDefinition")
62
- }
63
- else:
64
- descriptions = {}
65
- params = next(a for a in job_info["actions"] if a.get("_class", "#NONE") == "hudson.model.ParametersAction")["parameters"]
66
- params = [param for param in params if param["name"] != self.RESERVED_PARAMETER_NAME]
67
- for idx, param in enumerate(params):
68
- params[idx]["description"] = descriptions.get(param["name"], "")
69
-
70
- return params
71
-
72
- def get_releases_for_clone(self, test_id: str):
73
- test_id = UUID(test_id)
74
- # TODO: Filtering based on origin location / user preferences
75
- _: ArgusTest = ArgusTest.get(id=test_id)
76
-
77
- releases = list(ArgusRelease.all())
78
-
79
- return sorted(releases, key=lambda r: r.pretty_name if r.pretty_name else r.name)
80
-
81
- def get_groups_for_release(self, release_id: str):
82
- groups = list(ArgusGroup.filter(release_id=release_id).all())
83
-
84
- return sorted(groups, key=lambda g: g.pretty_name if g.pretty_name else g.name)
85
-
86
- def _verify_sct_settings(self, new_settings: dict[str, str]) -> tuple[bool, str]:
87
- if not (match := re.match(GITHUB_REPO_RE, new_settings["gitRepo"])):
88
- return (False, "Repository doesn't conform to GitHub schema")
89
-
90
- git_info = match.groupdict()
91
- if git_info.get("ssh"):
92
- repo = git_info["ssh_repo"]
93
- user = git_info["ssh_user"]
94
- else:
95
- repo = git_info["repo"]
96
- user = git_info["user"]
97
-
98
- user_tokens = UserOauthToken.filter(user_id=g.user.id).all()
99
- token = None
100
- for tok in user_tokens:
101
- if tok.kind == "github":
102
- token = tok.token
103
- break
104
- if not token:
105
- raise JenkinsServiceError("Github token not found")
106
-
107
- response = requests.get(
108
- url=f"https://api.github.com/repos/{user}/{repo}/contents/{new_settings['pipelineFile']}?ref={new_settings['gitBranch']}",
109
- headers={
110
- "Accept": "application/vnd.github+json",
111
- "Authorization": f"Bearer {token}",
112
- }
113
- )
114
-
115
- if response.status_code == 404:
116
- return (False, f"Pipeline file not found in the <a href=\"https://github.com/{user}/{repo}/tree/{new_settings['gitBranch']}\"> target repository</a>, please check the repository before continuing")
117
-
118
- if response.status_code == 403:
119
- return (True, "No access to this repository using your token. The pipeline file cannot be verified.")
120
-
121
- if response.status_code == 200:
122
- return (True, "")
123
-
124
- return (False, "Generic Error")
125
-
126
- def verify_job_settings(self, build_id: str, new_settings: dict[str, str]) -> tuple[bool, str]:
127
- PLUGIN_MAP = {
128
- "scylla-cluster-tests": self._verify_sct_settings,
129
- # for now they match
130
- "sirenada": self._verify_sct_settings,
131
- "driver-matrix-tests": self._verify_sct_settings,
132
- }
133
- test: ArgusTest = ArgusTest.get(build_system_id=build_id)
134
- plugin_name = test.plugin_name
135
-
136
- validated, message = PLUGIN_MAP.get(plugin_name, lambda _: (True, ""))(new_settings)
137
-
138
- return {
139
- "validated": validated,
140
- "message": message,
141
- }
142
-
143
- def get_advanced_settings(self, build_id: str):
144
- test: ArgusTest = ArgusTest.get(build_system_id=build_id)
145
- plugin_name = test.plugin_name
146
-
147
- if not (plugin_settings := self.SETTINGS_CONFIG_MAP.get(plugin_name)):
148
- return {}
149
-
150
- settings = {}
151
- raw_config = self._jenkins.get_job_config(name=build_id)
152
- config = ET.fromstring(raw_config)
153
-
154
- for setting, xpath in plugin_settings.items():
155
- value = config.find(xpath)
156
- settings[setting] = value.text
157
-
158
- return settings
159
-
160
- def adjust_job_settings(self, build_id: str, plugin_name: str, settings: dict[str, str]):
161
- xpath_map = self.SETTINGS_CONFIG_MAP.get(plugin_name)
162
- if not xpath_map:
163
- return
164
-
165
- config = self._jenkins.get_job_config(name=build_id)
166
- xml = ET.fromstring(config)
167
- for setting, value in settings.items():
168
- element = xml.find(xpath_map[setting])
169
- element.text = value
170
-
171
- adjusted_config = ET.tostring(xml, encoding="unicode")
172
- self._jenkins.reconfig_job(name=build_id, config_xml=adjusted_config)
173
-
174
- def clone_job(self, current_test_id: str, new_name: str, target: str, group: str, advanced_settings: bool | dict[str, str]):
175
- cloned_test: ArgusTest = ArgusTest.get(id=current_test_id)
176
- target_release: ArgusRelease = ArgusRelease.get(id=target)
177
- target_group: ArgusGroup = ArgusGroup.get(id=group)
178
-
179
- if target_group.id == cloned_test.id and new_name == cloned_test.name:
180
- raise JenkinsServiceError("Unable to clone: source and destination are the same")
181
-
182
- if not target_group.build_system_id:
183
- raise JenkinsServiceError("Unable to clone: target group is missing jenkins folder path")
184
-
185
- jenkins_new_build_id = f"{target_group.build_system_id}/{new_name}"
186
-
187
- new_test = ArgusTest()
188
- new_test.name = new_name
189
- new_test.build_system_id = jenkins_new_build_id
190
- new_test.group_id = target_group.id
191
- new_test.release_id = target_release.id
192
- new_test.plugin_name = cloned_test.plugin_name
193
-
194
- old_config = self._jenkins.get_job_config(name=cloned_test.build_system_id)
195
- LOGGER.info(old_config)
196
- xml = ET.fromstring(old_config)
197
- display_name = xml.find("displayName")
198
- if display_name:
199
- display_name.text = new_name
200
- new_config = ET.tostring(xml, encoding="unicode")
201
- self._jenkins.create_job(name=jenkins_new_build_id, config_xml=new_config)
202
- new_job_info = self._jenkins.get_job_info(name=jenkins_new_build_id)
203
- new_test.build_system_url = new_job_info["url"]
204
- new_test.save()
205
-
206
- if advanced_settings:
207
- self.adjust_job_settings(build_id=jenkins_new_build_id, plugin_name=new_test.plugin_name, settings=advanced_settings)
208
-
209
- return {
210
- "new_job": new_job_info,
211
- "new_entity": new_test,
212
- }
213
-
214
- def clone_build_job(self, build_id: str, params: dict[str, str]):
215
- queue_item = self.build_job(build_id=build_id, params=params)
216
- return {
217
- "queueItem": queue_item,
218
- }
219
-
220
- def build_job(self, build_id: str, params: dict, user_override: str = None):
221
- queue_number = self._jenkins.build_job(build_id, {
222
- **params,
223
- # use the user's email as the default value for the requested by user parameter,
224
- # so it would align with how SCT default works, on runs not trigger by argus
225
- self.RESERVED_PARAMETER_NAME: g.user.email.split('@')[0] if not user_override else user_override
226
- })
227
- return queue_number
228
-
229
- def get_queue_info(self, queue_item: int):
230
- build_info = self._jenkins.get_queue_item(queue_item)
231
- LOGGER.info("%s", build_info)
232
- executable = build_info.get("executable")
233
- if executable:
234
- return executable
235
- else:
236
- return {
237
- "why": build_info["why"],
238
- "inQueueSince": build_info["inQueueSince"],
239
- "taskUrl": build_info["task"]["url"],
240
- }