argus-alm 0.12.9__py3-none-any.whl → 0.13.0__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.
- argus/client/base.py +1 -1
- argus/client/driver_matrix_tests/cli.py +2 -2
- argus/client/driver_matrix_tests/client.py +1 -1
- argus/client/generic/cli.py +2 -2
- argus/client/generic_result.py +3 -2
- argus/client/sct/client.py +3 -3
- argus/client/sirenada/client.py +1 -1
- {argus_alm-0.12.9.dist-info → argus_alm-0.13.0.dist-info}/METADATA +2 -4
- argus_alm-0.13.0.dist-info/RECORD +20 -0
- argus/backend/.gitkeep +0 -0
- argus/backend/cli.py +0 -41
- argus/backend/controller/__init__.py +0 -0
- argus/backend/controller/admin.py +0 -20
- argus/backend/controller/admin_api.py +0 -354
- argus/backend/controller/api.py +0 -529
- argus/backend/controller/auth.py +0 -67
- argus/backend/controller/client_api.py +0 -108
- argus/backend/controller/main.py +0 -274
- argus/backend/controller/notification_api.py +0 -72
- argus/backend/controller/notifications.py +0 -13
- argus/backend/controller/team.py +0 -126
- argus/backend/controller/team_ui.py +0 -18
- argus/backend/controller/testrun_api.py +0 -482
- argus/backend/controller/view_api.py +0 -162
- argus/backend/db.py +0 -100
- argus/backend/error_handlers.py +0 -21
- argus/backend/events/event_processors.py +0 -34
- argus/backend/models/__init__.py +0 -0
- argus/backend/models/result.py +0 -138
- argus/backend/models/web.py +0 -389
- argus/backend/plugins/__init__.py +0 -0
- argus/backend/plugins/core.py +0 -225
- argus/backend/plugins/driver_matrix_tests/controller.py +0 -63
- argus/backend/plugins/driver_matrix_tests/model.py +0 -421
- argus/backend/plugins/driver_matrix_tests/plugin.py +0 -22
- argus/backend/plugins/driver_matrix_tests/raw_types.py +0 -62
- argus/backend/plugins/driver_matrix_tests/service.py +0 -60
- argus/backend/plugins/driver_matrix_tests/udt.py +0 -42
- argus/backend/plugins/generic/model.py +0 -79
- argus/backend/plugins/generic/plugin.py +0 -16
- argus/backend/plugins/generic/types.py +0 -13
- argus/backend/plugins/loader.py +0 -40
- argus/backend/plugins/sct/controller.py +0 -185
- argus/backend/plugins/sct/plugin.py +0 -38
- argus/backend/plugins/sct/resource_setup.py +0 -178
- argus/backend/plugins/sct/service.py +0 -491
- argus/backend/plugins/sct/testrun.py +0 -272
- argus/backend/plugins/sct/udt.py +0 -101
- argus/backend/plugins/sirenada/model.py +0 -113
- argus/backend/plugins/sirenada/plugin.py +0 -17
- argus/backend/service/admin.py +0 -27
- argus/backend/service/argus_service.py +0 -688
- argus/backend/service/build_system_monitor.py +0 -188
- argus/backend/service/client_service.py +0 -122
- argus/backend/service/event_service.py +0 -18
- argus/backend/service/jenkins_service.py +0 -240
- argus/backend/service/notification_manager.py +0 -150
- argus/backend/service/release_manager.py +0 -230
- argus/backend/service/results_service.py +0 -317
- argus/backend/service/stats.py +0 -540
- argus/backend/service/team_manager_service.py +0 -83
- argus/backend/service/testrun.py +0 -559
- argus/backend/service/user.py +0 -307
- argus/backend/service/views.py +0 -258
- argus/backend/template_filters.py +0 -27
- argus/backend/tests/__init__.py +0 -0
- argus/backend/tests/argus_web.test.yaml +0 -39
- argus/backend/tests/conftest.py +0 -44
- argus/backend/tests/results_service/__init__.py +0 -0
- argus/backend/tests/results_service/test_best_results.py +0 -70
- argus/backend/util/common.py +0 -65
- argus/backend/util/config.py +0 -38
- argus/backend/util/encoders.py +0 -41
- argus/backend/util/logsetup.py +0 -81
- argus/backend/util/module_loaders.py +0 -30
- argus/backend/util/send_email.py +0 -91
- argus/client/generic_result_old.py +0 -143
- argus/db/.gitkeep +0 -0
- argus/db/argus_json.py +0 -14
- argus/db/cloud_types.py +0 -125
- argus/db/config.py +0 -135
- argus/db/db_types.py +0 -139
- argus/db/interface.py +0 -370
- argus/db/testrun.py +0 -740
- argus/db/utils.py +0 -15
- argus_alm-0.12.9.dist-info/RECORD +0 -96
- /argus/{backend → common}/__init__.py +0 -0
- /argus/{backend/util → common}/enums.py +0 -0
- /argus/{backend/plugins/sct/types.py → common/sct_types.py} +0 -0
- /argus/{backend/plugins/sirenada/types.py → common/sirenada_types.py} +0 -0
- {argus_alm-0.12.9.dist-info → argus_alm-0.13.0.dist-info}/LICENSE +0 -0
- {argus_alm-0.12.9.dist-info → argus_alm-0.13.0.dist-info}/WHEEL +0 -0
- {argus_alm-0.12.9.dist-info → argus_alm-0.13.0.dist-info}/entry_points.txt +0 -0
argus/backend/db.py
DELETED
|
@@ -1,100 +0,0 @@
|
|
|
1
|
-
from functools import cached_property
|
|
2
|
-
import logging
|
|
3
|
-
from typing import Optional
|
|
4
|
-
from flask import g, Flask
|
|
5
|
-
# pylint: disable=no-name-in-module
|
|
6
|
-
from cassandra.policies import WhiteListRoundRobinPolicy
|
|
7
|
-
from cassandra import ConsistencyLevel
|
|
8
|
-
from cassandra.cluster import ExecutionProfile, EXEC_PROFILE_DEFAULT, Cluster
|
|
9
|
-
from cassandra.cluster import PreparedStatement
|
|
10
|
-
from cassandra.cqlengine.management import sync_table, sync_type
|
|
11
|
-
from cassandra.cqlengine import connection
|
|
12
|
-
from cassandra.query import dict_factory
|
|
13
|
-
from cassandra.auth import PlainTextAuthProvider
|
|
14
|
-
from argus.backend.util.config import Config
|
|
15
|
-
|
|
16
|
-
from argus.backend.models.web import USED_MODELS, USED_TYPES
|
|
17
|
-
|
|
18
|
-
LOGGER = logging.getLogger(__name__)
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
class ScyllaCluster:
|
|
22
|
-
# pylint: disable=too-many-instance-attributes
|
|
23
|
-
APP_INSTANCE: Optional['ScyllaCluster'] = None
|
|
24
|
-
|
|
25
|
-
def __init__(self, config=None):
|
|
26
|
-
if not config:
|
|
27
|
-
config = Config.load_yaml_config()
|
|
28
|
-
self.config = config
|
|
29
|
-
self.auth_provider = PlainTextAuthProvider(
|
|
30
|
-
username=config["SCYLLA_USERNAME"], password=config["SCYLLA_PASSWORD"])
|
|
31
|
-
self.lb_policy = WhiteListRoundRobinPolicy(hosts=config["SCYLLA_CONTACT_POINTS"])
|
|
32
|
-
self.execution_profile = ExecutionProfile(
|
|
33
|
-
load_balancing_policy=self.lb_policy, consistency_level=ConsistencyLevel.QUORUM)
|
|
34
|
-
connection.setup(hosts=config["SCYLLA_CONTACT_POINTS"], default_keyspace=config["SCYLLA_KEYSPACE_NAME"],
|
|
35
|
-
auth_provider=self.auth_provider,
|
|
36
|
-
protocol_version=4,
|
|
37
|
-
execution_profiles={EXEC_PROFILE_DEFAULT: self.execution_profile})
|
|
38
|
-
self.cluster: Cluster = connection.get_cluster(connection='default')
|
|
39
|
-
self.prepared_statements = {}
|
|
40
|
-
self.read_exec_profile = ExecutionProfile(
|
|
41
|
-
consistency_level=ConsistencyLevel.ONE,
|
|
42
|
-
row_factory=dict_factory,
|
|
43
|
-
load_balancing_policy=self.lb_policy
|
|
44
|
-
)
|
|
45
|
-
self.read_named_tuple_exec_profile = ExecutionProfile(
|
|
46
|
-
consistency_level=ConsistencyLevel.ONE,
|
|
47
|
-
load_balancing_policy=self.lb_policy
|
|
48
|
-
)
|
|
49
|
-
self.cluster.add_execution_profile("read_fast", self.read_exec_profile)
|
|
50
|
-
self.cluster.add_execution_profile("read_fast_named_tuple", self.read_named_tuple_exec_profile)
|
|
51
|
-
|
|
52
|
-
@cached_property
|
|
53
|
-
def session(self):
|
|
54
|
-
return self.cluster.connect(keyspace=self.config["SCYLLA_KEYSPACE_NAME"])
|
|
55
|
-
|
|
56
|
-
@classmethod
|
|
57
|
-
def get(cls, config: dict = None) -> 'ScyllaCluster':
|
|
58
|
-
if cls.APP_INSTANCE:
|
|
59
|
-
return cls.APP_INSTANCE
|
|
60
|
-
|
|
61
|
-
cls.APP_INSTANCE = cls(config)
|
|
62
|
-
return cls.APP_INSTANCE
|
|
63
|
-
|
|
64
|
-
@classmethod
|
|
65
|
-
def shutdown(cls):
|
|
66
|
-
if cls.APP_INSTANCE:
|
|
67
|
-
cls.APP_INSTANCE.cluster.shutdown()
|
|
68
|
-
cls.APP_INSTANCE = None
|
|
69
|
-
|
|
70
|
-
def prepare(self, query: str) -> PreparedStatement:
|
|
71
|
-
if not (statement := self.prepared_statements.get(query)):
|
|
72
|
-
LOGGER.info("Unprepared statement %s, preparing...", query)
|
|
73
|
-
statement = self.session.prepare(query=query)
|
|
74
|
-
self.prepared_statements[query] = statement
|
|
75
|
-
return statement
|
|
76
|
-
|
|
77
|
-
def sync_core_tables(self):
|
|
78
|
-
for udt in USED_TYPES:
|
|
79
|
-
LOGGER.info("Syncing type: %s..", udt.__name__)
|
|
80
|
-
sync_type(ks_name=self.config["SCYLLA_KEYSPACE_NAME"], type_model=udt)
|
|
81
|
-
LOGGER.info("Core Types synchronized.")
|
|
82
|
-
for model in USED_MODELS:
|
|
83
|
-
LOGGER.info("Syncing model: %s..", model.__name__)
|
|
84
|
-
sync_table(model, keyspaces=[self.config["SCYLLA_KEYSPACE_NAME"]])
|
|
85
|
-
LOGGER.info("Core Models synchronized.")
|
|
86
|
-
|
|
87
|
-
@classmethod
|
|
88
|
-
def get_session(cls):
|
|
89
|
-
cluster = cls.get()
|
|
90
|
-
if 'scylla_session' not in g:
|
|
91
|
-
g.scylla_session = cluster.session # pylint: disable=assigning-non-slot
|
|
92
|
-
return g.scylla_session
|
|
93
|
-
|
|
94
|
-
@classmethod
|
|
95
|
-
def close_session(cls, error=None): # pylint: disable=unused-argument
|
|
96
|
-
g.pop("scylla_session", None)
|
|
97
|
-
|
|
98
|
-
@classmethod
|
|
99
|
-
def attach_to_app(cls, app: Flask):
|
|
100
|
-
app.teardown_appcontext(cls.close_session)
|
argus/backend/error_handlers.py
DELETED
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
import logging
|
|
2
|
-
from traceback import format_exception
|
|
3
|
-
from flask import request
|
|
4
|
-
|
|
5
|
-
LOGGER = logging.getLogger(__name__)
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
class APIException(Exception):
|
|
9
|
-
pass
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
def handle_api_exception(exception: Exception):
|
|
13
|
-
LOGGER.error("Exception in %s\n%s", request.endpoint, "".join(format_exception(exception)))
|
|
14
|
-
|
|
15
|
-
return {
|
|
16
|
-
"status": "error",
|
|
17
|
-
"response": {
|
|
18
|
-
"exception": exception.__class__.__name__,
|
|
19
|
-
"arguments": exception.args
|
|
20
|
-
}
|
|
21
|
-
}
|
|
@@ -1,34 +0,0 @@
|
|
|
1
|
-
from argus.backend.models.web import ArgusEventTypes
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
def event_process_posted_comment(event: dict) -> dict:
|
|
5
|
-
return event["message"].format(**event)
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
def event_process_status_changed(event: dict) -> dict:
|
|
9
|
-
return event["message"].format(**event)
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
def event_process_investigation_status_changed(event: dict) -> dict:
|
|
13
|
-
return event["message"].format(**event)
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
def event_process_assignee_changed(event: dict) -> dict:
|
|
17
|
-
return event["message"].format(**event)
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
def event_process_issue_added(event: dict) -> dict:
|
|
21
|
-
return event["message"].format(**event)
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
EVENT_PROCESSORS = {
|
|
25
|
-
ArgusEventTypes.AssigneeChanged: event_process_assignee_changed,
|
|
26
|
-
ArgusEventTypes.TestRunStatusChanged: event_process_status_changed,
|
|
27
|
-
ArgusEventTypes.TestRunCommentPosted: event_process_posted_comment,
|
|
28
|
-
ArgusEventTypes.TestRunCommentUpdated: event_process_posted_comment,
|
|
29
|
-
ArgusEventTypes.TestRunCommentDeleted: event_process_posted_comment,
|
|
30
|
-
ArgusEventTypes.TestRunIssueAdded: event_process_issue_added,
|
|
31
|
-
ArgusEventTypes.TestRunIssueRemoved: event_process_issue_added,
|
|
32
|
-
ArgusEventTypes.TestRunInvestigationStatusChanged: event_process_investigation_status_changed,
|
|
33
|
-
ArgusEventTypes.TestRunBatchInvestigationStatusChange: event_process_investigation_status_changed,
|
|
34
|
-
}
|
argus/backend/models/__init__.py
DELETED
|
File without changes
|
argus/backend/models/result.py
DELETED
|
@@ -1,138 +0,0 @@
|
|
|
1
|
-
import math
|
|
2
|
-
from datetime import datetime, timezone
|
|
3
|
-
|
|
4
|
-
from cassandra.cqlengine import columns
|
|
5
|
-
from cassandra.cqlengine.models import Model
|
|
6
|
-
from cassandra.cqlengine.usertype import UserType
|
|
7
|
-
|
|
8
|
-
class ValidationRules(UserType):
|
|
9
|
-
valid_from = columns.DateTime()
|
|
10
|
-
best_pct = columns.Double() # max value limit relative to best result in percent unit
|
|
11
|
-
best_abs = columns.Double() # max value limit relative to best result in absolute unit
|
|
12
|
-
fixed_limit = columns.Double() # fixed limit
|
|
13
|
-
|
|
14
|
-
class ColumnMetadata(UserType):
|
|
15
|
-
name = columns.Ascii()
|
|
16
|
-
unit = columns.Text()
|
|
17
|
-
type = columns.Ascii()
|
|
18
|
-
higher_is_better = columns.Boolean() # used for tracking best results, if None - no tracking
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
class ArgusGenericResultMetadata(Model):
|
|
22
|
-
__table_name__ = "generic_result_metadata_v1"
|
|
23
|
-
test_id = columns.UUID(partition_key=True)
|
|
24
|
-
name = columns.Text(required=True, primary_key=True)
|
|
25
|
-
description = columns.Text()
|
|
26
|
-
columns_meta = columns.List(value_type=columns.UserDefinedType(ColumnMetadata))
|
|
27
|
-
validation_rules = columns.Map(key_type=columns.Ascii(), value_type=columns.List(columns.UserDefinedType(ValidationRules)))
|
|
28
|
-
rows_meta = columns.List(value_type=columns.Ascii())
|
|
29
|
-
|
|
30
|
-
def __init__(self, **kwargs):
|
|
31
|
-
kwargs["columns_meta"] = [ColumnMetadata(**col) for col in kwargs.pop('columns_meta', [])]
|
|
32
|
-
validation_rules = kwargs.pop('validation_rules', {})
|
|
33
|
-
|
|
34
|
-
if validation_rules:
|
|
35
|
-
for column, rule in validation_rules.items():
|
|
36
|
-
if not isinstance(rule, list):
|
|
37
|
-
rule['valid_from'] = datetime.now(timezone.utc)
|
|
38
|
-
validation_rules[column] = [rule]
|
|
39
|
-
kwargs["validation_rules"] = {k: [ValidationRules(**rules) for rules in v] for k, v in validation_rules.items()}
|
|
40
|
-
super().__init__(**kwargs)
|
|
41
|
-
|
|
42
|
-
def update_validation_rules(self, key: str, new_rule_dict: dict) -> bool:
|
|
43
|
-
"""
|
|
44
|
-
Checks if the most recent ValidationRule for the given key matches the new_rule_dict.
|
|
45
|
-
If not, adds the new rule to the list with the current timestamp.
|
|
46
|
-
|
|
47
|
-
:param key: The key (column name) in the validation_rules map to update.
|
|
48
|
-
:param new_rule_dict: A dictionary containing the new validation rule values.
|
|
49
|
-
:return: True if a new rule was added, False if the existing rule matches.
|
|
50
|
-
"""
|
|
51
|
-
rules_list = self.validation_rules.get(key, [])
|
|
52
|
-
most_recent_rule = None
|
|
53
|
-
|
|
54
|
-
if rules_list:
|
|
55
|
-
most_recent_rule = rules_list[-1]
|
|
56
|
-
|
|
57
|
-
fields_to_compare = [field for field in ValidationRules._fields if field != 'valid_from']
|
|
58
|
-
rules_match = True
|
|
59
|
-
if most_recent_rule:
|
|
60
|
-
for field in fields_to_compare:
|
|
61
|
-
db_value = getattr(most_recent_rule, field)
|
|
62
|
-
new_value = new_rule_dict.get(field)
|
|
63
|
-
if db_value is None and new_value is None:
|
|
64
|
-
continue
|
|
65
|
-
if db_value is None or new_value is None:
|
|
66
|
-
rules_match = False
|
|
67
|
-
break
|
|
68
|
-
if not math.isclose(db_value, new_value, rel_tol=1e-9, abs_tol=0.0):
|
|
69
|
-
rules_match = False
|
|
70
|
-
break
|
|
71
|
-
else:
|
|
72
|
-
rules_match = False
|
|
73
|
-
|
|
74
|
-
if not rules_match:
|
|
75
|
-
new_rule = ValidationRules(
|
|
76
|
-
valid_from=datetime.now(timezone.utc),
|
|
77
|
-
best_pct=new_rule_dict.get('best_pct'),
|
|
78
|
-
best_abs=new_rule_dict.get('best_abs'),
|
|
79
|
-
fixed_limit=new_rule_dict.get('fixed_limit')
|
|
80
|
-
)
|
|
81
|
-
rules_list.append(new_rule)
|
|
82
|
-
self.validation_rules = self.validation_rules or {}
|
|
83
|
-
self.validation_rules.update({key: rules_list})
|
|
84
|
-
return True
|
|
85
|
-
|
|
86
|
-
return False # Existing rule matches
|
|
87
|
-
|
|
88
|
-
def update_if_changed(self, new_data: dict) -> "ArgusGenericResultMetadata":
|
|
89
|
-
"""
|
|
90
|
-
Updates table metadata if changed column/description or new rows were added.
|
|
91
|
-
See that rows can only be added, not removed once was sent.
|
|
92
|
-
Columns may be removed, but data in results table persists.
|
|
93
|
-
"""
|
|
94
|
-
updated = False
|
|
95
|
-
for field, value in new_data.items():
|
|
96
|
-
if field == "columns_meta":
|
|
97
|
-
value = [ColumnMetadata(**col) for col in value]
|
|
98
|
-
if self.columns_meta != value:
|
|
99
|
-
self.columns_meta = value
|
|
100
|
-
updated = True
|
|
101
|
-
elif field == "rows_meta":
|
|
102
|
-
added_rows = []
|
|
103
|
-
for row in value:
|
|
104
|
-
if row not in self.rows_meta:
|
|
105
|
-
added_rows.append(row)
|
|
106
|
-
updated = True
|
|
107
|
-
self.rows_meta += added_rows
|
|
108
|
-
elif field == "validation_rules":
|
|
109
|
-
if any([self.update_validation_rules(key, rules) for key, rules in value.items()]):
|
|
110
|
-
updated = True
|
|
111
|
-
elif getattr(self, field) != value:
|
|
112
|
-
setattr(self, field, value)
|
|
113
|
-
updated = True
|
|
114
|
-
|
|
115
|
-
if updated:
|
|
116
|
-
self.save()
|
|
117
|
-
return self
|
|
118
|
-
|
|
119
|
-
class ArgusGenericResultData(Model):
|
|
120
|
-
__table_name__ = "generic_result_data_v1"
|
|
121
|
-
test_id = columns.UUID(partition_key=True)
|
|
122
|
-
name = columns.Text(partition_key=True)
|
|
123
|
-
run_id = columns.UUID(primary_key=True)
|
|
124
|
-
column = columns.Ascii(primary_key=True, index=True)
|
|
125
|
-
row = columns.Ascii(primary_key=True, index=True)
|
|
126
|
-
sut_timestamp = columns.DateTime() # for sorting
|
|
127
|
-
value = columns.Double()
|
|
128
|
-
value_text = columns.Text()
|
|
129
|
-
status = columns.Ascii()
|
|
130
|
-
|
|
131
|
-
class ArgusBestResultData(Model):
|
|
132
|
-
__table_name__ = "generic_result_best_v1"
|
|
133
|
-
test_id = columns.UUID(partition_key=True)
|
|
134
|
-
name = columns.Text(partition_key=True)
|
|
135
|
-
key = columns.Ascii(primary_key=True) # represents pair column:row
|
|
136
|
-
result_date = columns.DateTime(primary_key=True, clustering_order="DESC")
|
|
137
|
-
value = columns.Double()
|
|
138
|
-
run_id = columns.UUID()
|
argus/backend/models/web.py
DELETED
|
@@ -1,389 +0,0 @@
|
|
|
1
|
-
from uuid import UUID, uuid1, uuid4
|
|
2
|
-
from datetime import datetime
|
|
3
|
-
from enum import Enum, IntEnum, auto
|
|
4
|
-
from cassandra.cqlengine.models import Model
|
|
5
|
-
from cassandra.cqlengine.usertype import UserType
|
|
6
|
-
from cassandra.cqlengine import columns
|
|
7
|
-
from cassandra.util import uuid_from_time, unix_time_from_uuid1 # pylint: disable=no-name-in-module
|
|
8
|
-
|
|
9
|
-
from argus.backend.models.result import ArgusGenericResultMetadata, ArgusGenericResultData, ArgusBestResultData
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
def uuid_now():
|
|
13
|
-
return uuid_from_time(datetime.utcnow())
|
|
14
|
-
|
|
15
|
-
# pylint: disable=invalid-name
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
class ArgusTestException(Exception):
|
|
19
|
-
pass
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
class UserRoles(str, Enum):
|
|
23
|
-
User = "ROLE_USER"
|
|
24
|
-
Manager = "ROLE_MANAGER"
|
|
25
|
-
Admin = "ROLE_ADMIN"
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
class User(Model):
|
|
29
|
-
id = columns.UUID(primary_key=True, default=uuid4)
|
|
30
|
-
username = columns.Text(index=True)
|
|
31
|
-
full_name = columns.Text()
|
|
32
|
-
password = columns.Text()
|
|
33
|
-
email = columns.Text(index=True)
|
|
34
|
-
registration_date = columns.DateTime()
|
|
35
|
-
roles = columns.List(value_type=columns.Text)
|
|
36
|
-
picture_id = columns.UUID(default=None)
|
|
37
|
-
api_token = columns.Text(index=True)
|
|
38
|
-
|
|
39
|
-
def __hash__(self) -> int:
|
|
40
|
-
return hash(self.id)
|
|
41
|
-
|
|
42
|
-
def is_manager(self) -> bool:
|
|
43
|
-
# pylint: disable=unsupported-membership-test
|
|
44
|
-
return UserRoles.Manager in self.roles
|
|
45
|
-
|
|
46
|
-
def is_admin(self) -> bool:
|
|
47
|
-
# pylint: disable=unsupported-membership-test
|
|
48
|
-
return UserRoles.Admin in self.roles
|
|
49
|
-
|
|
50
|
-
def set_as_admin(self) -> None:
|
|
51
|
-
# pylint: disable=unsupported-membership-test
|
|
52
|
-
if UserRoles.Admin not in self.roles:
|
|
53
|
-
self.roles.append(UserRoles.Admin.value)
|
|
54
|
-
|
|
55
|
-
def set_as_manager(self) -> None:
|
|
56
|
-
# pylint: disable=unsupported-membership-test
|
|
57
|
-
if UserRoles.Manager not in self.roles:
|
|
58
|
-
self.roles.append(UserRoles.Manager.value)
|
|
59
|
-
|
|
60
|
-
def get_id(self):
|
|
61
|
-
return str(self.id)
|
|
62
|
-
|
|
63
|
-
@classmethod
|
|
64
|
-
def exists(cls, user_id: UUID):
|
|
65
|
-
try:
|
|
66
|
-
user = cls.get(id=user_id)
|
|
67
|
-
if user:
|
|
68
|
-
return user
|
|
69
|
-
except cls.DoesNotExist:
|
|
70
|
-
pass
|
|
71
|
-
return None
|
|
72
|
-
|
|
73
|
-
@classmethod
|
|
74
|
-
def exists_by_name(cls, name: str):
|
|
75
|
-
try:
|
|
76
|
-
user = cls.get(username=name)
|
|
77
|
-
if user:
|
|
78
|
-
return user
|
|
79
|
-
except cls.DoesNotExist:
|
|
80
|
-
pass
|
|
81
|
-
return None
|
|
82
|
-
|
|
83
|
-
def __str__(self):
|
|
84
|
-
return f"User('{self.id}','{self.username}')"
|
|
85
|
-
|
|
86
|
-
def to_json(self):
|
|
87
|
-
return {
|
|
88
|
-
"id": str(self.id),
|
|
89
|
-
"username": self.username,
|
|
90
|
-
"full_name": self.full_name,
|
|
91
|
-
"picture_id": self.picture_id
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
class Team(Model):
|
|
96
|
-
id = columns.UUID(primary_key=True, default=uuid4)
|
|
97
|
-
name = columns.Text(required=True)
|
|
98
|
-
leader = columns.UUID(index=True, required=True)
|
|
99
|
-
members = columns.List(value_type=columns.UUID)
|
|
100
|
-
motd = columns.Text()
|
|
101
|
-
|
|
102
|
-
class UserOauthToken(Model):
|
|
103
|
-
id = columns.UUID(primary_key=True, default=uuid4)
|
|
104
|
-
user_id = columns.UUID(index=True, required=True)
|
|
105
|
-
kind = columns.Text(required=True, index=True)
|
|
106
|
-
token = columns.Text(required=True)
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
class ArgusRelease(Model):
|
|
110
|
-
__table_name__ = "argus_release_v2"
|
|
111
|
-
id = columns.UUID(primary_key=True, default=uuid4)
|
|
112
|
-
name = columns.Text(index=True, required=True)
|
|
113
|
-
pretty_name = columns.Text()
|
|
114
|
-
description = columns.Text()
|
|
115
|
-
github_repo_url = columns.Text()
|
|
116
|
-
valid_version_regex = columns.Text()
|
|
117
|
-
assignee = columns.List(value_type=columns.UUID)
|
|
118
|
-
picture_id = columns.UUID()
|
|
119
|
-
enabled = columns.Boolean(default=lambda: True)
|
|
120
|
-
perpetual = columns.Boolean(default=lambda: False)
|
|
121
|
-
dormant = columns.Boolean(default=lambda: False)
|
|
122
|
-
|
|
123
|
-
def __eq__(self, other):
|
|
124
|
-
if isinstance(other, ArgusRelease):
|
|
125
|
-
return self.name == other.name
|
|
126
|
-
else:
|
|
127
|
-
return super().__eq__(other)
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
class ArgusGroup(Model):
|
|
131
|
-
__table_name__ = "argus_group_v2"
|
|
132
|
-
id = columns.UUID(primary_key=True, default=uuid4)
|
|
133
|
-
release_id = columns.UUID(required=True, index=True)
|
|
134
|
-
name = columns.Text(required=True, index=True)
|
|
135
|
-
pretty_name = columns.Text()
|
|
136
|
-
description = columns.Text()
|
|
137
|
-
assignee = columns.List(value_type=columns.UUID)
|
|
138
|
-
build_system_id = columns.Text()
|
|
139
|
-
enabled = columns.Boolean(default=lambda: True)
|
|
140
|
-
|
|
141
|
-
def __hash__(self) -> int:
|
|
142
|
-
return hash((self.id, self.release_id))
|
|
143
|
-
|
|
144
|
-
def __eq__(self, other):
|
|
145
|
-
if isinstance(other, ArgusGroup):
|
|
146
|
-
return self.name == other.name and self.release_id == other.release_id
|
|
147
|
-
else:
|
|
148
|
-
return super().__eq__(other)
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
class ArgusUserView(Model):
|
|
152
|
-
id = columns.UUID(primary_key=True, partition_key=True, default=uuid4)
|
|
153
|
-
name = columns.Text(required=True, index=True)
|
|
154
|
-
display_name = columns.Text()
|
|
155
|
-
description = columns.Text()
|
|
156
|
-
user_id = columns.UUID(required=True, index=True)
|
|
157
|
-
tests = columns.List(value_type=columns.UUID, default=lambda: [])
|
|
158
|
-
release_ids = columns.List(value_type=columns.UUID, default=lambda: [])
|
|
159
|
-
group_ids = columns.List(value_type=columns.UUID, default=lambda: [])
|
|
160
|
-
created = columns.DateTime(default=datetime.utcnow)
|
|
161
|
-
last_updated = columns.DateTime(default=datetime.utcnow)
|
|
162
|
-
widget_settings = columns.Text(required=True)
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
class ArgusTest(Model):
|
|
166
|
-
__table_name__ = "argus_test_v2"
|
|
167
|
-
id = columns.UUID(primary_key=True, default=uuid4)
|
|
168
|
-
group_id = columns.UUID(required=True, index=True)
|
|
169
|
-
release_id = columns.UUID(required=True, index=True)
|
|
170
|
-
name = columns.Text(required=True, index=True)
|
|
171
|
-
pretty_name = columns.Text()
|
|
172
|
-
description = columns.Text()
|
|
173
|
-
assignee = columns.List(value_type=columns.UUID)
|
|
174
|
-
build_system_id = columns.Text(index=True)
|
|
175
|
-
enabled = columns.Boolean(default=lambda: True)
|
|
176
|
-
build_system_url = columns.Text()
|
|
177
|
-
plugin_name = columns.Text()
|
|
178
|
-
|
|
179
|
-
def __eq__(self, other):
|
|
180
|
-
if isinstance(other, ArgusTest):
|
|
181
|
-
return self.name == other.name and self.group_id == other.group_id and self.release_id == other.release_id
|
|
182
|
-
else:
|
|
183
|
-
return super().__eq__(other)
|
|
184
|
-
|
|
185
|
-
def validate_build_system_id(self):
|
|
186
|
-
try:
|
|
187
|
-
t = ArgusTest.get(build_system_id=self.build_system_id)
|
|
188
|
-
if t.id != self.id:
|
|
189
|
-
raise ArgusTestException("Build Id is already used by another test", t.id, self.id)
|
|
190
|
-
except ArgusTest.DoesNotExist:
|
|
191
|
-
pass
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
class ArgusTestRunComment(Model):
|
|
195
|
-
id = columns.UUID(primary_key=True, default=uuid4, partition_key=True)
|
|
196
|
-
test_run_id = columns.UUID(required=True, index=True)
|
|
197
|
-
user_id = columns.UUID(required=True, index=True)
|
|
198
|
-
release_id = columns.UUID(required=True, index=True)
|
|
199
|
-
test_id = columns.UUID(required=True, index=True)
|
|
200
|
-
posted_at = columns.Integer(
|
|
201
|
-
required=True, clustering_order="desc", primary_key=True)
|
|
202
|
-
message = columns.Text(min_length=1, max_length=65535)
|
|
203
|
-
mentions = columns.List(value_type=columns.UUID, default=[])
|
|
204
|
-
reactions = columns.Map(key_type=columns.Text, value_type=columns.Integer)
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
class ArgusEventTypes(str, Enum):
|
|
208
|
-
AssigneeChanged = "ARGUS_ASSIGNEE_CHANGE"
|
|
209
|
-
TestRunStatusChanged = "ARGUS_TEST_RUN_STATUS_CHANGE"
|
|
210
|
-
TestRunInvestigationStatusChanged = "ARGUS_TEST_RUN_INVESTIGATION_STATUS_CHANGE"
|
|
211
|
-
TestRunBatchInvestigationStatusChange = "ARGUS_TEST_RUN_INVESTIGATION_BATCH_STATUS_CHANGE"
|
|
212
|
-
TestRunCommentPosted = "ARGUS_TEST_RUN_COMMENT_POSTED"
|
|
213
|
-
TestRunCommentUpdated = "ARGUS_TEST_RUN_COMMENT_UPDATED"
|
|
214
|
-
TestRunCommentDeleted = "ARGUS_TEST_RUN_COMMENT_DELETED"
|
|
215
|
-
TestRunIssueAdded = "ARGUS_TEST_RUN_ISSUE_ADDED"
|
|
216
|
-
TestRunIssueRemoved = "ARGUS_TEST_RUN_ISSUE_REMOVED"
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
class ArgusEvent(Model):
|
|
220
|
-
id = columns.UUID(primary_key=True, default=uuid4, partition_key=True)
|
|
221
|
-
release_id = columns.UUID(index=True)
|
|
222
|
-
group_id = columns.UUID(index=True)
|
|
223
|
-
test_id = columns.UUID(index=True)
|
|
224
|
-
run_id = columns.UUID(index=True)
|
|
225
|
-
user_id = columns.UUID(index=True)
|
|
226
|
-
kind = columns.Text(required=True, index=True)
|
|
227
|
-
body = columns.Text(required=True)
|
|
228
|
-
created_at = columns.DateTime(required=True)
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
class ArgusNotificationTypes(str, Enum):
|
|
232
|
-
Mention = "TYPE_MENTION"
|
|
233
|
-
StatusChange = "TYPE_STATUS_CHANGE"
|
|
234
|
-
AssigneeChange = "TYPE_ASSIGNEE_CHANGE"
|
|
235
|
-
ScheduleChange = "TYPE_SCHEDULE_CHANGE"
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
class ArgusNotificationSourceTypes(str, Enum):
|
|
239
|
-
TestRun = "TEST_RUN"
|
|
240
|
-
Schedule = "SCHEDULE"
|
|
241
|
-
Comment = "COMMENT"
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
class ArgusNotificationState(IntEnum):
|
|
245
|
-
UNREAD = auto()
|
|
246
|
-
READ = auto()
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
class ArgusNotification(Model):
|
|
250
|
-
receiver = columns.UUID(primary_key=True, partition_key=True)
|
|
251
|
-
id = columns.TimeUUID(primary_key=True, clustering_order="DESC", default=uuid_now)
|
|
252
|
-
type = columns.Text(required=True)
|
|
253
|
-
state = columns.SmallInt(required=True, default=lambda: ArgusNotificationState.UNREAD)
|
|
254
|
-
sender = columns.UUID(required=True)
|
|
255
|
-
source_type = columns.Text(required=True)
|
|
256
|
-
source_id = columns.UUID(required=True)
|
|
257
|
-
title = columns.Text(required=True, max_length=1024)
|
|
258
|
-
content = columns.Text(required=True, max_length=65535)
|
|
259
|
-
|
|
260
|
-
def to_dict_short_summary(self) -> dict:
|
|
261
|
-
return {
|
|
262
|
-
"receiver": self.receiver,
|
|
263
|
-
"sender": self.sender,
|
|
264
|
-
"id": self.id,
|
|
265
|
-
"created": unix_time_from_uuid1(self.id) * 1000,
|
|
266
|
-
"title": self.title,
|
|
267
|
-
"state": self.state,
|
|
268
|
-
}
|
|
269
|
-
|
|
270
|
-
def to_dict(self) -> dict:
|
|
271
|
-
return {
|
|
272
|
-
"receiver": self.receiver,
|
|
273
|
-
"sender": self.sender,
|
|
274
|
-
"id": self.id,
|
|
275
|
-
"created": unix_time_from_uuid1(self.id) * 1000,
|
|
276
|
-
"title": self.title,
|
|
277
|
-
"type": self.type,
|
|
278
|
-
"content": self.content,
|
|
279
|
-
"source": self.source_type,
|
|
280
|
-
"source_id": self.source_id,
|
|
281
|
-
"state": self.state,
|
|
282
|
-
}
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
class ArgusGithubIssue(Model):
|
|
286
|
-
# pylint: disable=too-many-instance-attributes
|
|
287
|
-
id = columns.UUID(primary_key=True, default=uuid4, partition_key=True)
|
|
288
|
-
added_on = columns.DateTime(default=datetime.utcnow)
|
|
289
|
-
release_id = columns.UUID(index=True)
|
|
290
|
-
group_id = columns.UUID(index=True)
|
|
291
|
-
test_id = columns.UUID(index=True)
|
|
292
|
-
run_id = columns.UUID(index=True)
|
|
293
|
-
user_id = columns.UUID(index=True)
|
|
294
|
-
type = columns.Text()
|
|
295
|
-
owner = columns.Text()
|
|
296
|
-
repo = columns.Text()
|
|
297
|
-
issue_number = columns.Integer()
|
|
298
|
-
last_status = columns.Text()
|
|
299
|
-
title = columns.Text()
|
|
300
|
-
url = columns.Text()
|
|
301
|
-
|
|
302
|
-
def __hash__(self) -> int:
|
|
303
|
-
return hash((self.owner, self.repo, self.issue_number))
|
|
304
|
-
|
|
305
|
-
def __eq__(self, other):
|
|
306
|
-
if isinstance(other, ArgusGithubIssue):
|
|
307
|
-
return self.owner == other.owner and self.repo == other.repo and self.issue_number == other.issue_number
|
|
308
|
-
return super().__eq__(other)
|
|
309
|
-
|
|
310
|
-
def __ne__(self, other):
|
|
311
|
-
return not self == other
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
class ArgusSchedule(Model):
|
|
315
|
-
__table_name__ = "argus_schedule_v4"
|
|
316
|
-
release_id = columns.UUID(primary_key=True, required=True)
|
|
317
|
-
id = columns.TimeUUID(primary_key=True, default=uuid1, clustering_order="DESC")
|
|
318
|
-
period_start = columns.DateTime(required=True, default=datetime.utcnow)
|
|
319
|
-
period_end = columns.DateTime(required=True, primary_key=True, clustering_order="DESC")
|
|
320
|
-
tag = columns.Text(default="")
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
class ArgusScheduleAssignee(Model):
|
|
324
|
-
__table_name__ = "argus_schedule_user_v3"
|
|
325
|
-
assignee = columns.UUID(primary_key=True)
|
|
326
|
-
id = columns.TimeUUID(primary_key=True, default=uuid1,
|
|
327
|
-
clustering_order="DESC")
|
|
328
|
-
schedule_id = columns.TimeUUID(required=True, index=True)
|
|
329
|
-
release_id = columns.UUID(required=True)
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
class ArgusScheduleTest(Model):
|
|
333
|
-
__table_name__ = "argus_schedule_test_v5"
|
|
334
|
-
test_id = columns.UUID(primary_key=True, required=True)
|
|
335
|
-
id = columns.TimeUUID(primary_key=True, default=uuid1,
|
|
336
|
-
clustering_order="DESC")
|
|
337
|
-
schedule_id = columns.TimeUUID(required=True, index=True)
|
|
338
|
-
release_id = columns.UUID(partition_key=True)
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
class ArgusScheduleGroup(Model):
|
|
342
|
-
__table_name__ = "argus_schedule_group_v3"
|
|
343
|
-
group_id = columns.UUID(partition_key=True, required=True)
|
|
344
|
-
id = columns.TimeUUID(primary_key=True, default=uuid1,
|
|
345
|
-
clustering_order="DESC")
|
|
346
|
-
schedule_id = columns.TimeUUID(required=True, index=True)
|
|
347
|
-
release_id = columns.UUID(partition_key=True)
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
class ReleasePlannerComment(Model):
|
|
351
|
-
__table_name__ = "argus_planner_comment_v2"
|
|
352
|
-
release = columns.UUID(primary_key=True)
|
|
353
|
-
group = columns.UUID(primary_key=True)
|
|
354
|
-
test = columns.UUID(primary_key=True)
|
|
355
|
-
comment = columns.Text(default=lambda: "")
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
class WebFileStorage(Model):
|
|
359
|
-
id = columns.UUID(primary_key=True, default=uuid4)
|
|
360
|
-
filepath = columns.Text(min_length=1)
|
|
361
|
-
filename = columns.Text(min_length=1)
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
USED_MODELS: list[Model] = [
|
|
365
|
-
User,
|
|
366
|
-
UserOauthToken,
|
|
367
|
-
Team,
|
|
368
|
-
WebFileStorage,
|
|
369
|
-
ArgusRelease,
|
|
370
|
-
ArgusUserView,
|
|
371
|
-
ArgusGroup,
|
|
372
|
-
ArgusTest,
|
|
373
|
-
ArgusTestRunComment,
|
|
374
|
-
ArgusEvent,
|
|
375
|
-
ArgusGithubIssue,
|
|
376
|
-
ReleasePlannerComment,
|
|
377
|
-
ArgusNotification,
|
|
378
|
-
ArgusSchedule,
|
|
379
|
-
ArgusScheduleAssignee,
|
|
380
|
-
ArgusScheduleGroup,
|
|
381
|
-
ArgusScheduleTest,
|
|
382
|
-
ArgusGenericResultMetadata,
|
|
383
|
-
ArgusGenericResultData,
|
|
384
|
-
ArgusBestResultData,
|
|
385
|
-
]
|
|
386
|
-
|
|
387
|
-
USED_TYPES: list[UserType] = [
|
|
388
|
-
|
|
389
|
-
]
|
|
File without changes
|