clear-skies-cortex 2.0.1__tar.gz → 2.0.2__tar.gz
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.
- {clear_skies_cortex-2.0.1 → clear_skies_cortex-2.0.2}/CHANGELOG.md +14 -0
- clear_skies_cortex-2.0.2/LATEST_CHANGELOG.md +11 -0
- {clear_skies_cortex-2.0.1 → clear_skies_cortex-2.0.2}/PKG-INFO +1 -1
- {clear_skies_cortex-2.0.1 → clear_skies_cortex-2.0.2}/pyproject.toml +2 -2
- clear_skies_cortex-2.0.2/src/clearskies_cortex/backends/cortex_backend.py +100 -0
- {clear_skies_cortex-2.0.1 → clear_skies_cortex-2.0.2}/src/clearskies_cortex/backends/cortex_team_relationship_backend.py +15 -24
- {clear_skies_cortex-2.0.1 → clear_skies_cortex-2.0.2}/src/clearskies_cortex/dataclasses.py +2 -2
- {clear_skies_cortex-2.0.1 → clear_skies_cortex-2.0.2}/src/clearskies_cortex/models/__init__.py +2 -0
- {clear_skies_cortex-2.0.1 → clear_skies_cortex-2.0.2}/src/clearskies_cortex/models/cortex_catalog_entity.py +31 -3
- clear_skies_cortex-2.0.2/src/clearskies_cortex/models/cortex_catalog_entity_domain.py +38 -0
- clear_skies_cortex-2.0.2/src/clearskies_cortex/models/cortex_catalog_entity_service.py +76 -0
- clear_skies_cortex-2.0.2/src/clearskies_cortex/models/cortex_catalog_entity_team.py +38 -0
- {clear_skies_cortex-2.0.1 → clear_skies_cortex-2.0.2}/src/clearskies_cortex/models/cortex_team.py +10 -3
- {clear_skies_cortex-2.0.1 → clear_skies_cortex-2.0.2}/uv.lock +242 -174
- clear_skies_cortex-2.0.1/LATEST_CHANGELOG.md +0 -16
- clear_skies_cortex-2.0.1/src/clearskies_cortex/backends/cortex_backend.py +0 -45
- clear_skies_cortex-2.0.1/src/clearskies_cortex/models/cortex_catalog_entity_domain.py +0 -25
- clear_skies_cortex-2.0.1/src/clearskies_cortex/models/cortex_catalog_entity_service.py +0 -92
- {clear_skies_cortex-2.0.1 → clear_skies_cortex-2.0.2}/.copier-answers.yml +0 -0
- {clear_skies_cortex-2.0.1 → clear_skies_cortex-2.0.2}/.editorconfig +0 -0
- {clear_skies_cortex-2.0.1 → clear_skies_cortex-2.0.2}/.github/workflows/create-version.yaml +0 -0
- {clear_skies_cortex-2.0.1 → clear_skies_cortex-2.0.2}/.github/workflows/docs.yaml +0 -0
- {clear_skies_cortex-2.0.1 → clear_skies_cortex-2.0.2}/.github/workflows/run-tests.yml +0 -0
- {clear_skies_cortex-2.0.1 → clear_skies_cortex-2.0.2}/.github/workflows/tests-matrix.yaml +0 -0
- {clear_skies_cortex-2.0.1 → clear_skies_cortex-2.0.2}/.github/workflows/tests.yaml +0 -0
- {clear_skies_cortex-2.0.1 → clear_skies_cortex-2.0.2}/.gitignore +0 -0
- {clear_skies_cortex-2.0.1 → clear_skies_cortex-2.0.2}/.pre-commit-config.yaml +0 -0
- {clear_skies_cortex-2.0.1 → clear_skies_cortex-2.0.2}/.python-version +0 -0
- {clear_skies_cortex-2.0.1 → clear_skies_cortex-2.0.2}/LICENSE +0 -0
- {clear_skies_cortex-2.0.1 → clear_skies_cortex-2.0.2}/README.md +0 -0
- {clear_skies_cortex-2.0.1 → clear_skies_cortex-2.0.2}/cliff.toml +0 -0
- {clear_skies_cortex-2.0.1 → clear_skies_cortex-2.0.2}/ruff.toml +0 -0
- {clear_skies_cortex-2.0.1 → clear_skies_cortex-2.0.2}/src/clearskies_cortex/__init__.py +0 -0
- {clear_skies_cortex-2.0.1 → clear_skies_cortex-2.0.2}/src/clearskies_cortex/backends/__init__.py +0 -0
- {clear_skies_cortex-2.0.1 → clear_skies_cortex-2.0.2}/src/clearskies_cortex/columns/__init__.py +0 -0
- {clear_skies_cortex-2.0.1 → clear_skies_cortex-2.0.2}/src/clearskies_cortex/columns/string_list.py +0 -0
- {clear_skies_cortex-2.0.1 → clear_skies_cortex-2.0.2}/src/clearskies_cortex/defaults/__init__.py +0 -0
- {clear_skies_cortex-2.0.1 → clear_skies_cortex-2.0.2}/src/clearskies_cortex/defaults/default_cortex_auth.py +0 -0
- {clear_skies_cortex-2.0.1 → clear_skies_cortex-2.0.2}/src/clearskies_cortex/defaults/default_cortex_url.py +0 -0
- {clear_skies_cortex-2.0.1 → clear_skies_cortex-2.0.2}/src/clearskies_cortex/models/cortex_catalog_entity_group.py +0 -0
- {clear_skies_cortex-2.0.1 → clear_skies_cortex-2.0.2}/src/clearskies_cortex/models/cortex_catalog_entity_scorecard.py +0 -0
- {clear_skies_cortex-2.0.1 → clear_skies_cortex-2.0.2}/src/clearskies_cortex/models/cortex_catalog_entity_types.py +0 -0
- {clear_skies_cortex-2.0.1 → clear_skies_cortex-2.0.2}/src/clearskies_cortex/models/cortex_entity_relationships.py +0 -0
- {clear_skies_cortex-2.0.1 → clear_skies_cortex-2.0.2}/src/clearskies_cortex/models/cortex_model.py +0 -0
- {clear_skies_cortex-2.0.1 → clear_skies_cortex-2.0.2}/src/clearskies_cortex/models/cortex_scorecard.py +0 -0
- {clear_skies_cortex-2.0.1 → clear_skies_cortex-2.0.2}/src/clearskies_cortex/models/cortex_team_category_tree.py +0 -0
- {clear_skies_cortex-2.0.1 → clear_skies_cortex-2.0.2}/src/clearskies_cortex/models/cortex_team_department.py +0 -0
|
@@ -5,12 +5,24 @@ All notable changes to this project will be documented in this file.
|
|
|
5
5
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
|
6
6
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
7
|
|
|
8
|
+
## [2.0.2] - 2026-01-06
|
|
9
|
+
|
|
10
|
+
### Added
|
|
11
|
+
- Add teams
|
|
12
|
+
|
|
13
|
+
### Changed
|
|
14
|
+
- Make it all work with the api
|
|
15
|
+
|
|
16
|
+
### Fixed
|
|
17
|
+
- Use the built-in functions of clearskies now
|
|
18
|
+
|
|
8
19
|
## [2.0.1] - 2025-11-27
|
|
9
20
|
|
|
10
21
|
### Added
|
|
11
22
|
- Add classes
|
|
12
23
|
|
|
13
24
|
### Changed
|
|
25
|
+
- Bump version to v2.0.1 by @github-actions[bot]
|
|
14
26
|
- Merge pull request #1 from clearskies-py/di-fix by @tnijboer in [#1](https://github.com/clearskies-py/cortex/pull/1)
|
|
15
27
|
- Initial project setup
|
|
16
28
|
|
|
@@ -18,8 +30,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
18
30
|
- Pass dependencies and build the tree by @cmancone
|
|
19
31
|
|
|
20
32
|
## New Contributors
|
|
33
|
+
* @github-actions[bot] made their first contribution
|
|
21
34
|
* @tnijboer made their first contribution in [#1](https://github.com/clearskies-py/cortex/pull/1)
|
|
22
35
|
* @cmancone made their first contribution
|
|
23
36
|
* @ made their first contribution
|
|
37
|
+
[2.0.2]: https://github.com/clearskies-py/cortex/compare/v2.0.1..v2.0.2
|
|
24
38
|
|
|
25
39
|
<!-- generated by git-cliff -->
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: clear-skies-cortex
|
|
3
|
-
Version: 2.0.
|
|
3
|
+
Version: 2.0.2
|
|
4
4
|
Summary: Cortex module for Clearskies
|
|
5
5
|
Project-URL: Docs, https://https://clearskies.info/modules/clear-skies-cortex
|
|
6
6
|
Project-URL: Repository, https://github.com/clearskies-py/cortex
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "clear-skies-cortex"
|
|
3
3
|
description = "Cortex module for Clearskies"
|
|
4
|
-
version = "2.0.
|
|
4
|
+
version = "2.0.2"
|
|
5
5
|
license = "MIT"
|
|
6
6
|
readme = "./README.md"
|
|
7
7
|
authors = [{name = "Tom Nijboer", email = "tom.nijboer@cimpress.com"}]
|
|
@@ -65,7 +65,7 @@ testpaths = [
|
|
|
65
65
|
"integration",
|
|
66
66
|
]
|
|
67
67
|
pythonpath = [
|
|
68
|
-
"
|
|
68
|
+
"src"
|
|
69
69
|
]
|
|
70
70
|
|
|
71
71
|
# This is the dedicated section for uv"s configuration
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
from typing import Any
|
|
2
|
+
|
|
3
|
+
import clearskies
|
|
4
|
+
import requests
|
|
5
|
+
from clearskies import Column, configs
|
|
6
|
+
from clearskies.authentication import Authentication
|
|
7
|
+
from clearskies.decorators import parameters_to_properties
|
|
8
|
+
from clearskies.di import inject
|
|
9
|
+
from clearskies.query import Query
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class CortexBackend(clearskies.backends.ApiBackend):
|
|
13
|
+
"""Backend for Cortex.io."""
|
|
14
|
+
|
|
15
|
+
base_url = configs.String(default="https://api.getcortexapp.com/api/v1/")
|
|
16
|
+
authentication = inject.ByName("cortex_auth") # type: ignore[assignment]
|
|
17
|
+
requests = inject.Requests()
|
|
18
|
+
api_casing = configs.Select(["snake_case", "camelCase", "TitleCase"], default="camelCase")
|
|
19
|
+
|
|
20
|
+
_auth_headers: dict[str, str] = {}
|
|
21
|
+
|
|
22
|
+
api_to_model_map = configs.AnyDict(default={})
|
|
23
|
+
pagination_parameter_name = configs.String(default="page")
|
|
24
|
+
limit_parameter_name = configs.String(default="pageSize")
|
|
25
|
+
|
|
26
|
+
can_count = True
|
|
27
|
+
|
|
28
|
+
@parameters_to_properties
|
|
29
|
+
def __init__(
|
|
30
|
+
self,
|
|
31
|
+
base_url: str | None = "https://api.getcortexapp.com/api/v1/",
|
|
32
|
+
authentication: Authentication | None = None,
|
|
33
|
+
model_casing: str = "snake_case",
|
|
34
|
+
api_casing: str = "camelCase",
|
|
35
|
+
api_to_model_map: dict[str, str | list[str]] = {},
|
|
36
|
+
pagination_parameter_name: str = "page",
|
|
37
|
+
pagination_parameter_type: str = "int",
|
|
38
|
+
limit_parameter_name: str = "pageSize",
|
|
39
|
+
):
|
|
40
|
+
self.finalize_and_validate_configuration()
|
|
41
|
+
|
|
42
|
+
def count(self, query: Query) -> int:
|
|
43
|
+
"""Return count of records matching query."""
|
|
44
|
+
self.check_query(query)
|
|
45
|
+
(url, method, body, headers) = self.build_records_request(query)
|
|
46
|
+
response = self.execute_request(url, method, json=body, headers=headers)
|
|
47
|
+
response.raise_for_status()
|
|
48
|
+
data = response.json()
|
|
49
|
+
if "total" in data:
|
|
50
|
+
return data["total"]
|
|
51
|
+
data = self.map_records_response(data, query)
|
|
52
|
+
return len(data)
|
|
53
|
+
|
|
54
|
+
def map_records_response(
|
|
55
|
+
self, response_data: Any, query: Query, query_data: dict[str, Any] | None = None
|
|
56
|
+
) -> list[dict[str, Any]]:
|
|
57
|
+
"""Map api response to model fields."""
|
|
58
|
+
if isinstance(response_data, dict):
|
|
59
|
+
if "page" in response_data:
|
|
60
|
+
del response_data["page"]
|
|
61
|
+
del response_data["totalPages"]
|
|
62
|
+
del response_data["total"]
|
|
63
|
+
first_item = next(iter(response_data))
|
|
64
|
+
if isinstance(response_data[first_item], list) and all(
|
|
65
|
+
isinstance(item, dict) for item in response_data[first_item]
|
|
66
|
+
):
|
|
67
|
+
return super().map_records_response(response_data[first_item], query, query_data)
|
|
68
|
+
return super().map_records_response(response_data, query, query_data)
|
|
69
|
+
|
|
70
|
+
def set_next_page_data_from_response(
|
|
71
|
+
self,
|
|
72
|
+
next_page_data: dict[str, Any],
|
|
73
|
+
query: Query,
|
|
74
|
+
response: "requests.Response", # type: ignore
|
|
75
|
+
) -> None:
|
|
76
|
+
"""
|
|
77
|
+
Update the next_page_data dictionary with the appropriate data needed to fetch the next page of records.
|
|
78
|
+
|
|
79
|
+
This method has a very important job, which is to inform clearskies about how to make another API call to fetch the next
|
|
80
|
+
page of records. The way this happens is by updating the `next_page_data` dictionary in place with whatever pagination
|
|
81
|
+
information is necessary. Note that this relies on next_page_data being passed by reference, hence the need to update
|
|
82
|
+
it in place. That means that you can do this:
|
|
83
|
+
|
|
84
|
+
```python
|
|
85
|
+
next_page_data["some_key"] = "some_value"
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
but if you do this:
|
|
89
|
+
|
|
90
|
+
```python
|
|
91
|
+
next_page_data = {"some_key": "some_value"}
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
Then things simply won't work.
|
|
95
|
+
"""
|
|
96
|
+
if isinstance(response.json(), dict):
|
|
97
|
+
page = response.json().get("page", None)
|
|
98
|
+
total_pages = response.json().get("totalPages", None)
|
|
99
|
+
if page is not None and total_pages is not None and page < total_pages:
|
|
100
|
+
next_page_data[self.pagination_parameter_name] = page + 1
|
|
@@ -8,7 +8,7 @@ from clearskies import Configurable, Model, configs
|
|
|
8
8
|
from clearskies.backends.memory_backend import MemoryBackend, MemoryTable
|
|
9
9
|
from clearskies.columns import String, Uuid
|
|
10
10
|
from clearskies.di import inject
|
|
11
|
-
from clearskies.query
|
|
11
|
+
from clearskies.query import Condition, Query
|
|
12
12
|
|
|
13
13
|
from clearskies_cortex.backends import cortex_backend as rest_backend
|
|
14
14
|
|
|
@@ -61,20 +61,6 @@ class CortexTeamRelationshipBackend(MemoryBackend, Configurable):
|
|
|
61
61
|
def destination_name(cls) -> str:
|
|
62
62
|
return "teams/relationships"
|
|
63
63
|
|
|
64
|
-
try:
|
|
65
|
-
relationship_data = self._get_cortex_backend().records(
|
|
66
|
-
Query(
|
|
67
|
-
model_class=RelationshipModel,
|
|
68
|
-
),
|
|
69
|
-
{},
|
|
70
|
-
)[0]
|
|
71
|
-
|
|
72
|
-
except IndexError:
|
|
73
|
-
relationship_data = {"edges": []}
|
|
74
|
-
|
|
75
|
-
# this should match up to exactly what backend.records() will return
|
|
76
|
-
# relationship_data = example_data["edges"]
|
|
77
|
-
|
|
78
64
|
# we need to map this to the kind of row structure expected by the category_tree column
|
|
79
65
|
# (see https://github.com/clearskies-py/clearskies/blob/main/src/clearskies/columns/category_tree.py)
|
|
80
66
|
# This takes slightly more time up front but makes for quick lookups in both directions (and we'll
|
|
@@ -89,9 +75,14 @@ class CortexTeamRelationshipBackend(MemoryBackend, Configurable):
|
|
|
89
75
|
root_categories: dict[str, str] = {}
|
|
90
76
|
known_children: dict[str, str] = {}
|
|
91
77
|
relationships: dict[str, set[str]] = {}
|
|
92
|
-
for relationship in
|
|
93
|
-
|
|
94
|
-
|
|
78
|
+
for relationship in self._get_cortex_backend().records(
|
|
79
|
+
Query(
|
|
80
|
+
model_class=RelationshipModel,
|
|
81
|
+
),
|
|
82
|
+
{},
|
|
83
|
+
):
|
|
84
|
+
child_category = relationship["child_team_tag"]
|
|
85
|
+
parent_category = relationship["parent_team_tag"]
|
|
95
86
|
# Skip if either parent or child is archived
|
|
96
87
|
if parent_category not in relationships:
|
|
97
88
|
relationships[parent_category] = set()
|
|
@@ -115,8 +106,8 @@ class CortexTeamRelationshipBackend(MemoryBackend, Configurable):
|
|
|
115
106
|
for idx, ancestor in enumerate(ancestors):
|
|
116
107
|
if (
|
|
117
108
|
not self.all_teams().get(node_name)
|
|
118
|
-
or self.all_teams().get(node_name, {}).get("
|
|
119
|
-
or self.all_teams().get(ancestor, {}).get("
|
|
109
|
+
# or self.all_teams().get(node_name, {}).get("is_archived")
|
|
110
|
+
# or self.all_teams().get(ancestor, {}).get("is_archived")
|
|
120
111
|
):
|
|
121
112
|
continue
|
|
122
113
|
mapped.append(
|
|
@@ -162,13 +153,13 @@ class CortexTeamRelationshipBackend(MemoryBackend, Configurable):
|
|
|
162
153
|
from clearskies_cortex.models.cortex_team import CortexTeam
|
|
163
154
|
|
|
164
155
|
teams: dict[str, dict[str, Any]] = {}
|
|
165
|
-
|
|
156
|
+
for team in self._get_cortex_backend().records(
|
|
166
157
|
Query(
|
|
167
158
|
model_class=CortexTeam,
|
|
159
|
+
conditions=[Condition("include_teams_without_members=true")],
|
|
168
160
|
),
|
|
169
161
|
{},
|
|
170
|
-
)
|
|
171
|
-
|
|
172
|
-
teams[team["teamTag"]] = team
|
|
162
|
+
):
|
|
163
|
+
teams[team["team_tag"]] = team
|
|
173
164
|
self._cached_teams = teams
|
|
174
165
|
return teams
|
|
@@ -20,7 +20,7 @@ class ServiceEntityHierarchyParent:
|
|
|
20
20
|
description: str | None
|
|
21
21
|
definition: None | dict[str, Any]
|
|
22
22
|
parents: list["ServiceEntityHierarchyParent"]
|
|
23
|
-
groups: list[str]
|
|
23
|
+
groups: list[str] | None
|
|
24
24
|
|
|
25
25
|
|
|
26
26
|
@dataclass
|
|
@@ -33,7 +33,7 @@ class ServiceEntityHierarchyChild:
|
|
|
33
33
|
description: str | None
|
|
34
34
|
definition: None | dict[str, Any]
|
|
35
35
|
children: list["ServiceEntityHierarchyChild"]
|
|
36
|
-
groups: list[str]
|
|
36
|
+
groups: list[str] | None
|
|
37
37
|
|
|
38
38
|
|
|
39
39
|
@dataclass
|
{clear_skies_cortex-2.0.1 → clear_skies_cortex-2.0.2}/src/clearskies_cortex/models/__init__.py
RENAMED
|
@@ -3,6 +3,7 @@ from clearskies_cortex.models.cortex_catalog_entity_domain import CortexCatalogE
|
|
|
3
3
|
from clearskies_cortex.models.cortex_catalog_entity_group import CortexCatalogEntityGroup
|
|
4
4
|
from clearskies_cortex.models.cortex_catalog_entity_scorecard import CortexCatalogEntityScorecard
|
|
5
5
|
from clearskies_cortex.models.cortex_catalog_entity_service import CortexCatalogEntityService
|
|
6
|
+
from clearskies_cortex.models.cortex_catalog_entity_team import CortexCatalogEntityTeam
|
|
6
7
|
from clearskies_cortex.models.cortex_scorecard import CortexScorecard
|
|
7
8
|
from clearskies_cortex.models.cortex_team import CortexTeam
|
|
8
9
|
from clearskies_cortex.models.cortex_team_category_tree import CortexTeamCategoryTree
|
|
@@ -14,6 +15,7 @@ __all__ = [
|
|
|
14
15
|
"CortexCatalogEntityGroup",
|
|
15
16
|
"CortexCatalogEntityScorecard",
|
|
16
17
|
"CortexCatalogEntityService",
|
|
18
|
+
"CortexCatalogEntityTeam",
|
|
17
19
|
"CortexScorecard",
|
|
18
20
|
"CortexTeam",
|
|
19
21
|
"CortexTeamCategoryTree",
|
|
@@ -1,11 +1,19 @@
|
|
|
1
|
-
from
|
|
1
|
+
from collections.abc import Iterator
|
|
2
|
+
from typing import Any, Self
|
|
2
3
|
|
|
3
4
|
from clearskies import Model
|
|
4
5
|
from clearskies.columns import Boolean, Datetime, HasMany, Json, String
|
|
6
|
+
from clearskies.di import inject
|
|
7
|
+
from clearskies.query import Query
|
|
8
|
+
from dacite import from_dict
|
|
5
9
|
|
|
10
|
+
from clearskies_cortex import dataclasses
|
|
6
11
|
from clearskies_cortex.backends import CortexBackend
|
|
7
12
|
from clearskies_cortex.columns import StringList
|
|
8
|
-
from clearskies_cortex.models import
|
|
13
|
+
from clearskies_cortex.models import (
|
|
14
|
+
cortex_catalog_entity_group,
|
|
15
|
+
cortex_catalog_entity_scorecard,
|
|
16
|
+
)
|
|
9
17
|
|
|
10
18
|
|
|
11
19
|
class CortexCatalogEntity(Model):
|
|
@@ -25,7 +33,7 @@ class CortexCatalogEntity(Model):
|
|
|
25
33
|
groups = StringList("groups")
|
|
26
34
|
owners = Json()
|
|
27
35
|
ownership = Json()
|
|
28
|
-
|
|
36
|
+
owners_v2 = Json()
|
|
29
37
|
description = String()
|
|
30
38
|
git = Json()
|
|
31
39
|
hierarchy = Json()
|
|
@@ -46,6 +54,22 @@ class CortexCatalogEntity(Model):
|
|
|
46
54
|
foreign_column_name="entity_tag",
|
|
47
55
|
)
|
|
48
56
|
|
|
57
|
+
# search columns
|
|
58
|
+
hierarchy_depth = String(is_searchable=True, is_temporary=True)
|
|
59
|
+
git_repositories = StringList(is_searchable=True, is_temporary=True)
|
|
60
|
+
types = StringList(is_searchable=True, is_temporary=True)
|
|
61
|
+
query = String(is_searchable=True, is_temporary=True)
|
|
62
|
+
include_archived = Boolean(is_searchable=True, is_temporary=True)
|
|
63
|
+
include_metadata = Boolean(is_searchable=True, is_temporary=True)
|
|
64
|
+
include_links = Boolean(is_searchable=True, is_temporary=True)
|
|
65
|
+
include_owners = Boolean(is_searchable=True)
|
|
66
|
+
include_nested_fields = StringList(is_searchable=True, is_temporary=True)
|
|
67
|
+
include_hierarchy_fields = StringList(is_searchable=True, is_temporary=True)
|
|
68
|
+
|
|
69
|
+
def parse_hierarchy(self) -> dataclasses.ServiceEntityHierarchy:
|
|
70
|
+
"""Parse the hierarchy column into a dictionary."""
|
|
71
|
+
return from_dict(dataclasses.ServiceEntityHierarchy, data=self.hierarchy)
|
|
72
|
+
|
|
49
73
|
def parse_groups(self) -> dict[str, str]:
|
|
50
74
|
"""
|
|
51
75
|
Parse the strings of groups.
|
|
@@ -60,3 +84,7 @@ class CortexCatalogEntity(Model):
|
|
|
60
84
|
if len(splitted) > 1:
|
|
61
85
|
parsed[splitted[0]] = splitted[1]
|
|
62
86
|
return parsed
|
|
87
|
+
|
|
88
|
+
def parse_owners(self) -> dataclasses.EntityTeamOwner:
|
|
89
|
+
"""Parse the owners column into a dictionary."""
|
|
90
|
+
return from_dict(dataclasses.EntityTeamOwner, data=self.owners)
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
from typing import Any, Self
|
|
2
|
+
|
|
3
|
+
from clearskies import Column
|
|
4
|
+
from clearskies.query import Condition, Query
|
|
5
|
+
|
|
6
|
+
from clearskies_cortex.models import cortex_catalog_entity
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class CortexCatalogEntityDomain(cortex_catalog_entity.CortexCatalogEntity):
|
|
10
|
+
"""Model for domain entities."""
|
|
11
|
+
|
|
12
|
+
def get_final_query(self) -> Query:
|
|
13
|
+
return (
|
|
14
|
+
self.get_query()
|
|
15
|
+
.add_where(Condition("types=domain"))
|
|
16
|
+
.add_where(Condition("include_nested_fields=team:members"))
|
|
17
|
+
.add_where(Condition("include_owners=true"))
|
|
18
|
+
.add_where(Condition("include_metadata=true"))
|
|
19
|
+
.add_where(Condition("include_hierarchy_fields=groups"))
|
|
20
|
+
)
|
|
21
|
+
|
|
22
|
+
def get_top_level_domain(self: Self) -> Self:
|
|
23
|
+
"""Get the upper domain of this service if set."""
|
|
24
|
+
hierarchy = self.parse_hierarchy()
|
|
25
|
+
if hierarchy.parents:
|
|
26
|
+
parent = hierarchy.parents[0]
|
|
27
|
+
while parent.parents:
|
|
28
|
+
parent = parent.parents[0]
|
|
29
|
+
return self.as_query().find(f"tag={parent.tag}")
|
|
30
|
+
return self.empty()
|
|
31
|
+
|
|
32
|
+
def get_parent(self: Self) -> Self:
|
|
33
|
+
"""Get the first domain of this service if set."""
|
|
34
|
+
hierarchy = self.parse_hierarchy()
|
|
35
|
+
if hierarchy.parents:
|
|
36
|
+
container = hierarchy.parents[0]
|
|
37
|
+
return self.as_query().find(f"tag={container.tag}")
|
|
38
|
+
return self.empty()
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import logging
|
|
2
|
+
from typing import Any, Iterator, Self, cast
|
|
3
|
+
|
|
4
|
+
from clearskies import Column
|
|
5
|
+
from clearskies.di import inject
|
|
6
|
+
from clearskies.query import Condition, Query
|
|
7
|
+
from dacite import from_dict
|
|
8
|
+
|
|
9
|
+
from clearskies_cortex import dataclasses
|
|
10
|
+
from clearskies_cortex.backends import CortexBackend
|
|
11
|
+
from clearskies_cortex.models import (
|
|
12
|
+
cortex_catalog_entity,
|
|
13
|
+
cortex_catalog_entity_domain,
|
|
14
|
+
cortex_team,
|
|
15
|
+
)
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
class CortexCatalogEntityService(cortex_catalog_entity.CortexCatalogEntity):
|
|
19
|
+
"""Model for domain entities."""
|
|
20
|
+
|
|
21
|
+
backend = CortexBackend()
|
|
22
|
+
|
|
23
|
+
teams = inject.ByClass(cortex_team.CortexTeam)
|
|
24
|
+
entity_domains = inject.ByClass(cortex_catalog_entity_domain.CortexCatalogEntityDomain)
|
|
25
|
+
|
|
26
|
+
def get_final_query(self) -> Query:
|
|
27
|
+
return (
|
|
28
|
+
self.get_query()
|
|
29
|
+
.add_where(Condition("types=service"))
|
|
30
|
+
.add_where(Condition("include_nested_fields=team:members"))
|
|
31
|
+
.add_where(Condition("include_owners=true"))
|
|
32
|
+
.add_where(Condition("include_metadata=true"))
|
|
33
|
+
.add_where(Condition("include_hierarchy_fields=groups"))
|
|
34
|
+
)
|
|
35
|
+
|
|
36
|
+
def get_top_level_team(self: Self) -> cortex_team.CortexTeam:
|
|
37
|
+
"""Find the top level team based on the team ownership."""
|
|
38
|
+
team = self.get_team()
|
|
39
|
+
if team:
|
|
40
|
+
return team.find_top_level_team()
|
|
41
|
+
|
|
42
|
+
return team
|
|
43
|
+
|
|
44
|
+
def get_team(self: Self) -> cortex_team.CortexTeam:
|
|
45
|
+
"""Find the team based on the team ownership."""
|
|
46
|
+
team = self.teams.empty()
|
|
47
|
+
self.logger.debug(f"EntityService: owners {self.owners}")
|
|
48
|
+
if not self.owners:
|
|
49
|
+
return team
|
|
50
|
+
owners = self.parse_owners()
|
|
51
|
+
self.logger.debug(f"Parsed owners: {owners}")
|
|
52
|
+
if not owners.teams:
|
|
53
|
+
return team
|
|
54
|
+
|
|
55
|
+
entity_team = owners.teams[0]
|
|
56
|
+
self.logger.debug(f"Found entity team: {entity_team}")
|
|
57
|
+
|
|
58
|
+
return self.teams.find(f"team_tag={entity_team.tag}")
|
|
59
|
+
|
|
60
|
+
def get_top_level_domain(self: Self) -> cortex_catalog_entity_domain.CortexCatalogEntityDomain:
|
|
61
|
+
"""Get the upper domain of this service if set."""
|
|
62
|
+
hierarchy = self.parse_hierarchy()
|
|
63
|
+
if hierarchy.parents:
|
|
64
|
+
parent = hierarchy.parents[0]
|
|
65
|
+
while parent.parents:
|
|
66
|
+
parent = parent.parents[0]
|
|
67
|
+
return self.entity_domains.find(f"tag={parent.tag}")
|
|
68
|
+
return self.entity_domains.empty()
|
|
69
|
+
|
|
70
|
+
def get_parent_domain(self: Self) -> cortex_catalog_entity_domain.CortexCatalogEntityDomain:
|
|
71
|
+
"""Get the first domain of this service if set."""
|
|
72
|
+
hierarchy = self.parse_hierarchy()
|
|
73
|
+
if hierarchy.parents:
|
|
74
|
+
container = hierarchy.parents[0]
|
|
75
|
+
return self.entity_domains.find(f"tag={container.tag}")
|
|
76
|
+
return self.entity_domains.empty()
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
from typing import Any, Self
|
|
2
|
+
|
|
3
|
+
from clearskies import Column
|
|
4
|
+
from clearskies.query import Condition, Query
|
|
5
|
+
|
|
6
|
+
from clearskies_cortex.models import cortex_catalog_entity
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class CortexCatalogEntityTeam(cortex_catalog_entity.CortexCatalogEntity):
|
|
10
|
+
"""Model for team entities."""
|
|
11
|
+
|
|
12
|
+
def get_final_query(self) -> Query:
|
|
13
|
+
return (
|
|
14
|
+
self.get_query()
|
|
15
|
+
.add_where(Condition("types=team"))
|
|
16
|
+
.add_where(Condition("include_nested_fields=team:members"))
|
|
17
|
+
.add_where(Condition("include_owners=true"))
|
|
18
|
+
.add_where(Condition("include_metadata=true"))
|
|
19
|
+
.add_where(Condition("include_hierarchy_fields=groups"))
|
|
20
|
+
)
|
|
21
|
+
|
|
22
|
+
def get_top_level_team(self: Self) -> Self:
|
|
23
|
+
"""Get the upper team of this service if set."""
|
|
24
|
+
hierarchy = self.parse_hierarchy()
|
|
25
|
+
if hierarchy.parents:
|
|
26
|
+
parent = hierarchy.parents[0]
|
|
27
|
+
while parent.parents:
|
|
28
|
+
parent = parent.parents[0]
|
|
29
|
+
return self.as_query().find(f"tag={parent.tag}")
|
|
30
|
+
return self.empty()
|
|
31
|
+
|
|
32
|
+
def get_parent(self: Self) -> Self:
|
|
33
|
+
"""Get the first team of this service if set."""
|
|
34
|
+
hierarchy = self.parse_hierarchy()
|
|
35
|
+
if hierarchy.parents:
|
|
36
|
+
team = hierarchy.parents[0]
|
|
37
|
+
return self.as_query().find(f"tag={team.tag}")
|
|
38
|
+
return self.empty()
|
{clear_skies_cortex-2.0.1 → clear_skies_cortex-2.0.2}/src/clearskies_cortex/models/cortex_team.py
RENAMED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
from typing import Self
|
|
1
|
+
from typing import Self
|
|
2
2
|
|
|
3
3
|
from clearskies import Model
|
|
4
4
|
from clearskies.columns import (
|
|
@@ -8,6 +8,7 @@ from clearskies.columns import (
|
|
|
8
8
|
CategoryTreeAncestors,
|
|
9
9
|
CategoryTreeChildren,
|
|
10
10
|
CategoryTreeDescendants,
|
|
11
|
+
Datetime,
|
|
11
12
|
Json,
|
|
12
13
|
String,
|
|
13
14
|
)
|
|
@@ -21,7 +22,11 @@ class CortexTeam(Model):
|
|
|
21
22
|
|
|
22
23
|
id_column_name: str = "team_tag"
|
|
23
24
|
|
|
24
|
-
backend = CortexBackend(
|
|
25
|
+
backend = CortexBackend(
|
|
26
|
+
api_to_model_map={
|
|
27
|
+
"cortexTeam.members": "members",
|
|
28
|
+
}
|
|
29
|
+
)
|
|
25
30
|
|
|
26
31
|
@classmethod
|
|
27
32
|
def destination_name(cls: type[Self]) -> str:
|
|
@@ -45,8 +50,10 @@ class CortexTeam(Model):
|
|
|
45
50
|
metadata = Json()
|
|
46
51
|
slack_channels = Json()
|
|
47
52
|
type = String()
|
|
48
|
-
|
|
53
|
+
members = Json()
|
|
49
54
|
id = String()
|
|
55
|
+
last_updated = Datetime()
|
|
56
|
+
include_teams_without_members = Boolean(is_searchable=True, is_temporary=True)
|
|
50
57
|
|
|
51
58
|
def get_name(self) -> str:
|
|
52
59
|
"""Retrieve name from metadata."""
|