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.
Files changed (47) hide show
  1. {clear_skies_cortex-2.0.1 → clear_skies_cortex-2.0.2}/CHANGELOG.md +14 -0
  2. clear_skies_cortex-2.0.2/LATEST_CHANGELOG.md +11 -0
  3. {clear_skies_cortex-2.0.1 → clear_skies_cortex-2.0.2}/PKG-INFO +1 -1
  4. {clear_skies_cortex-2.0.1 → clear_skies_cortex-2.0.2}/pyproject.toml +2 -2
  5. clear_skies_cortex-2.0.2/src/clearskies_cortex/backends/cortex_backend.py +100 -0
  6. {clear_skies_cortex-2.0.1 → clear_skies_cortex-2.0.2}/src/clearskies_cortex/backends/cortex_team_relationship_backend.py +15 -24
  7. {clear_skies_cortex-2.0.1 → clear_skies_cortex-2.0.2}/src/clearskies_cortex/dataclasses.py +2 -2
  8. {clear_skies_cortex-2.0.1 → clear_skies_cortex-2.0.2}/src/clearskies_cortex/models/__init__.py +2 -0
  9. {clear_skies_cortex-2.0.1 → clear_skies_cortex-2.0.2}/src/clearskies_cortex/models/cortex_catalog_entity.py +31 -3
  10. clear_skies_cortex-2.0.2/src/clearskies_cortex/models/cortex_catalog_entity_domain.py +38 -0
  11. clear_skies_cortex-2.0.2/src/clearskies_cortex/models/cortex_catalog_entity_service.py +76 -0
  12. clear_skies_cortex-2.0.2/src/clearskies_cortex/models/cortex_catalog_entity_team.py +38 -0
  13. {clear_skies_cortex-2.0.1 → clear_skies_cortex-2.0.2}/src/clearskies_cortex/models/cortex_team.py +10 -3
  14. {clear_skies_cortex-2.0.1 → clear_skies_cortex-2.0.2}/uv.lock +242 -174
  15. clear_skies_cortex-2.0.1/LATEST_CHANGELOG.md +0 -16
  16. clear_skies_cortex-2.0.1/src/clearskies_cortex/backends/cortex_backend.py +0 -45
  17. clear_skies_cortex-2.0.1/src/clearskies_cortex/models/cortex_catalog_entity_domain.py +0 -25
  18. clear_skies_cortex-2.0.1/src/clearskies_cortex/models/cortex_catalog_entity_service.py +0 -92
  19. {clear_skies_cortex-2.0.1 → clear_skies_cortex-2.0.2}/.copier-answers.yml +0 -0
  20. {clear_skies_cortex-2.0.1 → clear_skies_cortex-2.0.2}/.editorconfig +0 -0
  21. {clear_skies_cortex-2.0.1 → clear_skies_cortex-2.0.2}/.github/workflows/create-version.yaml +0 -0
  22. {clear_skies_cortex-2.0.1 → clear_skies_cortex-2.0.2}/.github/workflows/docs.yaml +0 -0
  23. {clear_skies_cortex-2.0.1 → clear_skies_cortex-2.0.2}/.github/workflows/run-tests.yml +0 -0
  24. {clear_skies_cortex-2.0.1 → clear_skies_cortex-2.0.2}/.github/workflows/tests-matrix.yaml +0 -0
  25. {clear_skies_cortex-2.0.1 → clear_skies_cortex-2.0.2}/.github/workflows/tests.yaml +0 -0
  26. {clear_skies_cortex-2.0.1 → clear_skies_cortex-2.0.2}/.gitignore +0 -0
  27. {clear_skies_cortex-2.0.1 → clear_skies_cortex-2.0.2}/.pre-commit-config.yaml +0 -0
  28. {clear_skies_cortex-2.0.1 → clear_skies_cortex-2.0.2}/.python-version +0 -0
  29. {clear_skies_cortex-2.0.1 → clear_skies_cortex-2.0.2}/LICENSE +0 -0
  30. {clear_skies_cortex-2.0.1 → clear_skies_cortex-2.0.2}/README.md +0 -0
  31. {clear_skies_cortex-2.0.1 → clear_skies_cortex-2.0.2}/cliff.toml +0 -0
  32. {clear_skies_cortex-2.0.1 → clear_skies_cortex-2.0.2}/ruff.toml +0 -0
  33. {clear_skies_cortex-2.0.1 → clear_skies_cortex-2.0.2}/src/clearskies_cortex/__init__.py +0 -0
  34. {clear_skies_cortex-2.0.1 → clear_skies_cortex-2.0.2}/src/clearskies_cortex/backends/__init__.py +0 -0
  35. {clear_skies_cortex-2.0.1 → clear_skies_cortex-2.0.2}/src/clearskies_cortex/columns/__init__.py +0 -0
  36. {clear_skies_cortex-2.0.1 → clear_skies_cortex-2.0.2}/src/clearskies_cortex/columns/string_list.py +0 -0
  37. {clear_skies_cortex-2.0.1 → clear_skies_cortex-2.0.2}/src/clearskies_cortex/defaults/__init__.py +0 -0
  38. {clear_skies_cortex-2.0.1 → clear_skies_cortex-2.0.2}/src/clearskies_cortex/defaults/default_cortex_auth.py +0 -0
  39. {clear_skies_cortex-2.0.1 → clear_skies_cortex-2.0.2}/src/clearskies_cortex/defaults/default_cortex_url.py +0 -0
  40. {clear_skies_cortex-2.0.1 → clear_skies_cortex-2.0.2}/src/clearskies_cortex/models/cortex_catalog_entity_group.py +0 -0
  41. {clear_skies_cortex-2.0.1 → clear_skies_cortex-2.0.2}/src/clearskies_cortex/models/cortex_catalog_entity_scorecard.py +0 -0
  42. {clear_skies_cortex-2.0.1 → clear_skies_cortex-2.0.2}/src/clearskies_cortex/models/cortex_catalog_entity_types.py +0 -0
  43. {clear_skies_cortex-2.0.1 → clear_skies_cortex-2.0.2}/src/clearskies_cortex/models/cortex_entity_relationships.py +0 -0
  44. {clear_skies_cortex-2.0.1 → clear_skies_cortex-2.0.2}/src/clearskies_cortex/models/cortex_model.py +0 -0
  45. {clear_skies_cortex-2.0.1 → clear_skies_cortex-2.0.2}/src/clearskies_cortex/models/cortex_scorecard.py +0 -0
  46. {clear_skies_cortex-2.0.1 → clear_skies_cortex-2.0.2}/src/clearskies_cortex/models/cortex_team_category_tree.py +0 -0
  47. {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 -->
@@ -0,0 +1,11 @@
1
+ ## [2.0.2] - 2026-01-06
2
+
3
+ ### Added
4
+ - Add teams
5
+
6
+ ### Changed
7
+ - Make it all work with the api
8
+
9
+ ### Fixed
10
+ - Use the built-in functions of clearskies now
11
+
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: clear-skies-cortex
3
- Version: 2.0.1
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.1"
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
- "app"
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.query import 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 relationship_data["edges"]:
93
- child_category = relationship["childTeamTag"]
94
- parent_category = relationship["parentTeamTag"]
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("isArchived")
119
- or self.all_teams().get(ancestor, {}).get("isArchived")
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
- team_result = self._get_cortex_backend().records(
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
- )[0]
171
- for team in team_result["teams"]:
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
@@ -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 typing import Self
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 cortex_catalog_entity_group, cortex_catalog_entity_scorecard
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
- ownersV2 = Json()
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()
@@ -1,4 +1,4 @@
1
- from typing import Self, cast
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
- cortex_team = Json()
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."""