buildzr 0.0.13__py3-none-any.whl → 0.0.14__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.
buildzr/__about__.py CHANGED
@@ -1 +1 @@
1
- VERSION = "0.0.13"
1
+ VERSION = "0.0.14"
buildzr/dsl/__init__.py CHANGED
@@ -5,10 +5,17 @@ from .dsl import (
5
5
  Container,
6
6
  Component,
7
7
  Group,
8
+ DeploymentEnvironment,
9
+ DeploymentNode,
10
+ InfrastructureNode,
11
+ DeploymentGroup,
12
+ SoftwareSystemInstance,
13
+ ContainerInstance,
8
14
  SystemLandscapeView,
9
15
  SystemContextView,
10
16
  ContainerView,
11
17
  ComponentView,
18
+ DeploymentView,
12
19
  StyleElements,
13
20
  StyleRelationships,
14
21
  )
buildzr/dsl/dsl.py CHANGED
@@ -29,6 +29,10 @@ from buildzr.dsl.interfaces import (
29
29
  DslWorkspaceElement,
30
30
  DslElement,
31
31
  DslViewElement,
32
+ DslDeploymentEnvironment,
33
+ DslInfrastructureNodeElement,
34
+ DslDeploymentNodeElement,
35
+ DslElementInstance,
32
36
  )
33
37
  from buildzr.dsl.relations import (
34
38
  DslElementRelationOverrides,
@@ -53,6 +57,8 @@ _current_workspace: ContextVar[Optional['Workspace']] = ContextVar('current_work
53
57
  _current_group_stack: ContextVar[List['Group']] = ContextVar('current_group', default=[])
54
58
  _current_software_system: ContextVar[Optional['SoftwareSystem']] = ContextVar('current_software_system', default=None)
55
59
  _current_container: ContextVar[Optional['Container']] = ContextVar('current_container', default=None)
60
+ _current_deployment_environment: ContextVar[Optional['DeploymentEnvironment']] = ContextVar('current_deployment_environment', default=None)
61
+ _current_deployment_node_stack: ContextVar[List['DeploymentNode']] = ContextVar('current_deployment_node', default=[])
56
62
 
57
63
  class Workspace(DslWorkspaceElement):
58
64
  """
@@ -68,7 +74,7 @@ class Workspace(DslWorkspaceElement):
68
74
  return None
69
75
 
70
76
  @property
71
- def children(self) -> Optional[List[Union['Person', 'SoftwareSystem']]]:
77
+ def children(self) -> Optional[List[Union['Person', 'SoftwareSystem', 'DeploymentNode']]]:
72
78
  return self._children
73
79
 
74
80
  def __init__(
@@ -82,7 +88,7 @@ class Workspace(DslWorkspaceElement):
82
88
 
83
89
  self._m = buildzr.models.Workspace()
84
90
  self._parent = None
85
- self._children: Optional[List[Union['Person', 'SoftwareSystem']]] = []
91
+ self._children: Optional[List[Union['Person', 'SoftwareSystem', 'DeploymentNode']]] = []
86
92
  self._dynamic_attrs: Dict[str, Union['Person', 'SoftwareSystem']] = {}
87
93
  self._use_implied_relationships = implied_relationships
88
94
  self._group_separator = group_separator
@@ -118,47 +124,53 @@ class Workspace(DslWorkspaceElement):
118
124
 
119
125
  def __exit__(self, exc_type: Optional[Type[BaseException]], exc_value: Optional[BaseException], traceback: Optional[Any]) -> None:
120
126
 
127
+ if self._use_implied_relationships:
128
+ self._imply_relationships()
129
+
130
+ _current_workspace.reset(self._token)
131
+
132
+ def _imply_relationships(
133
+ self,
134
+ ) -> None:
135
+
121
136
  from buildzr.dsl.explorer import Explorer
122
137
 
123
138
  # Process implied relationships:
124
139
  # If we have relationship s >> do >> a.b, then create s >> do >> a.
125
140
  # If we have relationship s.ss >> do >> a.b.c, then create s.ss >> do >> a.b and s.ss >> do >> a.
126
141
  # And so on...
127
- if self._use_implied_relationships:
128
- explorer = Explorer(self)
129
- relationships = list(explorer.walk_relationships())
130
- for relationship in relationships:
131
- source = relationship.source
132
- destination = relationship.destination
133
- destination_parent = destination.parent
134
-
135
- while destination_parent is not None and \
136
- isinstance(source, DslElement) and \
137
- not isinstance(source.model, buildzr.models.Workspace) and \
138
- not isinstance(destination_parent, DslWorkspaceElement):
139
-
140
- if destination_parent is source.parent:
141
- break
142
-
143
- rels = source.model.relationships
144
-
145
- if rels:
146
- already_exists = any(
147
- r.destinationId == destination_parent.model.id and
148
- r.description == relationship.model.description and
149
- r.technology == relationship.model.technology
150
- for r in rels
142
+ explorer = Explorer(self)
143
+ relationships = list(explorer.walk_relationships())
144
+ for relationship in relationships:
145
+ source = relationship.source
146
+ destination = relationship.destination
147
+ destination_parent = destination.parent
148
+
149
+ while destination_parent is not None and \
150
+ isinstance(source, DslElement) and \
151
+ not isinstance(source.model, buildzr.models.Workspace) and \
152
+ not isinstance(destination_parent, DslWorkspaceElement):
153
+
154
+ if destination_parent is source.parent:
155
+ break
156
+
157
+ rels = source.model.relationships
158
+
159
+ if rels:
160
+ already_exists = any(
161
+ r.destinationId == destination_parent.model.id and
162
+ r.description == relationship.model.description and
163
+ r.technology == relationship.model.technology
164
+ for r in rels
165
+ )
166
+ if not already_exists:
167
+ r = source.uses(
168
+ destination_parent,
169
+ description=relationship.model.description,
170
+ technology=relationship.model.technology,
151
171
  )
152
- if not already_exists:
153
- r = source.uses(
154
- destination_parent,
155
- description=relationship.model.description,
156
- technology=relationship.model.technology,
157
- )
158
- r.model.linkedRelationshipId = relationship.model.id
159
- destination_parent = destination_parent.parent
160
-
161
- _current_workspace.reset(self._token)
172
+ r.model.linkedRelationshipId = relationship.model.id
173
+ destination_parent = destination_parent.parent
162
174
 
163
175
  def person(self) -> TypedDynamicAttribute['Person']:
164
176
  return TypedDynamicAttribute['Person'](self._dynamic_attrs)
@@ -166,7 +178,12 @@ class Workspace(DslWorkspaceElement):
166
178
  def software_system(self) -> TypedDynamicAttribute['SoftwareSystem']:
167
179
  return TypedDynamicAttribute['SoftwareSystem'](self._dynamic_attrs)
168
180
 
169
- def add_model(self, model: Union['Person', 'SoftwareSystem']) -> None:
181
+ def add_model(
182
+ self, model: Union[
183
+ 'Person',
184
+ 'SoftwareSystem',
185
+ 'DeploymentNode',
186
+ ]) -> None:
170
187
  if isinstance(model, Person):
171
188
  self._m.model.people.append(model._m)
172
189
  model._parent = self
@@ -177,6 +194,10 @@ class Workspace(DslWorkspaceElement):
177
194
  model._parent = self
178
195
  self._add_dynamic_attr(model.model.name, model)
179
196
  self._children.append(model)
197
+ elif isinstance(model, DeploymentNode):
198
+ self._m.model.deploymentNodes.append(model._m)
199
+ model._parent = self
200
+ self._children.append(model)
180
201
  else:
181
202
  raise ValueError('Invalid element type: Trying to add an element of type {} to a workspace.'.format(type(model)))
182
203
 
@@ -187,6 +208,7 @@ class Workspace(DslWorkspaceElement):
187
208
  'SystemContextView',
188
209
  'ContainerView',
189
210
  'ComponentView',
211
+ 'DeploymentView',
190
212
  ]
191
213
  ) -> None:
192
214
 
@@ -215,6 +237,11 @@ class Workspace(DslWorkspaceElement):
215
237
  self.model.views.componentViews = [view.model]
216
238
  else:
217
239
  self.model.views.componentViews.append(view.model)
240
+ elif isinstance(view, DeploymentView):
241
+ if not self.model.views.deploymentViews:
242
+ self.model.views.deploymentViews = [view.model]
243
+ else:
244
+ self.model.views.deploymentViews.append(view.model)
218
245
  else:
219
246
  raise NotImplementedError("The view {0} is currently not supported", type(view))
220
247
 
@@ -708,6 +735,500 @@ _AutoLayout = Optional[
708
735
  ]
709
736
  ]
710
737
 
738
+ class DeploymentEnvironment(DslDeploymentEnvironment):
739
+
740
+ def __init__(self, name: str) -> None:
741
+ self._name = name
742
+ self._parent: Optional[Workspace] = None
743
+ self._children: Optional[List['DeploymentNode']] = []
744
+
745
+ workspace = _current_workspace.get()
746
+ if workspace is not None:
747
+ self._parent = workspace
748
+
749
+ @property
750
+ def name(self) -> str:
751
+ return self._name
752
+
753
+ @property
754
+ def parent(self) -> Optional[Workspace]:
755
+ return self._parent
756
+
757
+ @property
758
+ def children(self) -> Optional[List['DeploymentNode']]:
759
+ return self._children
760
+
761
+ def add_deployment_node(self, node: 'DeploymentNode') -> None:
762
+ node._m.environment = self._name
763
+
764
+ def __enter__(self) -> Self:
765
+ self._token = _current_deployment_environment.set(self)
766
+ return self
767
+
768
+ def __exit__(self, exc_type: Optional[Type[BaseException]], exc_value: Optional[BaseException], traceback: Optional[Any]) -> None:
769
+ _current_deployment_environment.reset(self._token)
770
+
771
+ if self._parent is not None:
772
+ self._imply_software_system_instance_relationships(self._parent)
773
+ self._imply_container_instance_relationships(self._parent)
774
+
775
+ def _imply_software_system_instance_relationships(self, workspace: Workspace) -> None:
776
+
777
+ from buildzr.dsl.expression import Expression
778
+
779
+ """
780
+ Process implied instance relationships. For example, if we have a
781
+ relationship between two software systems, and the software system
782
+ instances of those software systems exists, then we need to create a
783
+ new relationship between those software system instances.
784
+
785
+ These implied relationships are used in `DeploymentView`.
786
+ """
787
+
788
+ software_instances = [
789
+ cast('SoftwareSystemInstance', e) for e in Expression(include_elements=[
790
+ lambda w, e: e.type == SoftwareSystemInstance,
791
+ ]).elements(workspace)
792
+ ]
793
+
794
+ software_instance_map: Dict[str, List['SoftwareSystemInstance']] = {}
795
+ for software_instance in software_instances:
796
+ software_id = software_instance.model.softwareSystemId
797
+ if software_id not in software_instance_map:
798
+ software_instance_map[software_id] = []
799
+ software_instance_map[software_id].append(software_instance)
800
+
801
+ softwares = [
802
+ cast('SoftwareSystem', e) for e in Expression(include_elements=[
803
+ lambda w, e: e.type == SoftwareSystem,
804
+ ]).elements(workspace)
805
+ ]
806
+
807
+ for software in softwares:
808
+
809
+ other_softwares_ids = {
810
+ s.model.id for s in softwares
811
+ if s.model.id != software.model.id
812
+ }
813
+
814
+ if not software.model.relationships:
815
+ continue
816
+
817
+ for relationship in software.model.relationships:
818
+ if not relationship.destinationId in other_softwares_ids:
819
+ continue
820
+
821
+ this_software_instances = software_instance_map[software.model.id]
822
+ other_software_instances = software_instance_map[relationship.destinationId]
823
+
824
+ for this_software_instance in this_software_instances:
825
+ for other_software_instance in other_software_instances:
826
+
827
+ already_exists = this_software_instance.model.relationships is not None and any(
828
+ r.sourceId == this_software_instance.model.id and
829
+ r.destinationId == other_software_instance.model.id and
830
+ r.description == relationship.description and
831
+ r.technology == relationship.technology
832
+ for r in this_software_instance.model.relationships
833
+ )
834
+
835
+ if not already_exists:
836
+ # Note: tags aren't carried over.
837
+ r = this_software_instance.uses(
838
+ other_software_instance,
839
+ description=relationship.description,
840
+ technology=relationship.technology,
841
+ )
842
+ r.model.linkedRelationshipId = relationship.id
843
+
844
+ def _imply_container_instance_relationships(self, workspace: Workspace) -> None:
845
+
846
+ """
847
+ Process implied instance relationships. For example, if we have a
848
+ relationship between two containers, and the container instances of
849
+ those containers exists, then we need to create a new relationship
850
+ between those container instances.
851
+
852
+ These implied relationships are used in `DeploymentView`.
853
+ """
854
+
855
+ from buildzr.dsl.expression import Expression
856
+
857
+ container_instances = [
858
+ cast('ContainerInstance', e) for e in Expression(include_elements=[
859
+ lambda w, e: e.type == ContainerInstance,
860
+ ]).elements(workspace)]
861
+
862
+ container_instance_map: Dict[str, List['ContainerInstance']] = {}
863
+ for container_instance in container_instances:
864
+ container_id = container_instance.model.containerId
865
+ if container_id not in container_instance_map:
866
+ container_instance_map[container_id] = []
867
+ container_instance_map[container_id].append(container_instance)
868
+
869
+ containers = [
870
+ cast('ContainerInstance', e) for e in Expression(include_elements=[
871
+ lambda w, e: e.type == Container,
872
+ ]).elements(workspace)]
873
+
874
+ for container in containers:
875
+
876
+ other_containers_ids = {
877
+ c.model.id for c in containers
878
+ if c.model.id != container.model.id
879
+ }
880
+
881
+ if not container.model.relationships:
882
+ continue
883
+
884
+ for relationship in container.model.relationships:
885
+
886
+ if not relationship.destinationId in other_containers_ids:
887
+ continue
888
+
889
+ this_container_instances = container_instance_map[container.model.id]
890
+ other_container_instances = container_instance_map[relationship.destinationId]
891
+
892
+ for this_container_instance in this_container_instances:
893
+ for other_container_instance in other_container_instances:
894
+
895
+ already_exists = this_container_instance.model.relationships is not None and any(
896
+ r.sourceId == this_container_instance.model.id and
897
+ r.destinationId == other_container_instance.model.id and
898
+ r.description == relationship.description and
899
+ r.technology == relationship.technology
900
+ for r in this_container_instance.model.relationships
901
+ )
902
+
903
+ if not already_exists:
904
+ # Note: tags aren't carried over.
905
+ r = this_container_instance.uses(
906
+ other_container_instance,
907
+ description=relationship.description,
908
+ technology=relationship.technology,
909
+ )
910
+ r.model.linkedRelationshipId = relationship.id
911
+
912
+
913
+ class DeploymentNode(DslDeploymentNodeElement, DslElementRelationOverrides[
914
+ 'DeploymentNode',
915
+ 'DeploymentNode'
916
+ ]):
917
+
918
+ def __init__(self, name: str, description: str="", technology: str="", tags: Set[str]=set(), instances: str="1") -> None:
919
+ self._m = buildzr.models.DeploymentNode()
920
+ self._m.instances = instances
921
+ self._m.id = GenerateId.for_element()
922
+ self._m.name = name
923
+ self._m.children = []
924
+ self._m.softwareSystemInstances = []
925
+ self._m.containerInstances = []
926
+ self._m.infrastructureNodes = []
927
+ self._m.description = description
928
+ self._m.technology = technology
929
+ self._parent: Optional[Workspace] = None
930
+ self._children: Optional[List[
931
+ Union[
932
+ 'SoftwareSystemInstance',
933
+ 'ContainerInstance',
934
+ 'InfrastructureNode',
935
+ 'DeploymentNode']]
936
+ ] = []
937
+ self._tags = {'Element', 'Deployment Node'}.union(tags)
938
+ self._m.tags = ','.join(self._tags)
939
+
940
+ self._sources: List[DslElement] = []
941
+ self._destinations: List[DslElement] = []
942
+ self._relationships: Set[DslRelationship] = set()
943
+
944
+ # If the deployment stack is not empty, then we're inside the context of
945
+ # another deployment node. Otherwise, we're at the root of the
946
+ # workspace.
947
+ stack = _current_deployment_node_stack.get()
948
+ if stack:
949
+ stack[-1].add_deployment_node(self)
950
+ else:
951
+ workspace = _current_workspace.get()
952
+ if workspace:
953
+ self._parent = workspace
954
+ workspace.add_model(self)
955
+
956
+ deployment_environment = _current_deployment_environment.get()
957
+ if deployment_environment is not None:
958
+ self._m.environment = deployment_environment.name
959
+ deployment_environment.add_deployment_node(self)
960
+
961
+ @property
962
+ def model(self) -> buildzr.models.DeploymentNode:
963
+ return self._m
964
+
965
+ @property
966
+ def tags(self) -> Set[str]:
967
+ return self._tags
968
+
969
+ @property
970
+ def parent(self) -> Optional[Workspace]:
971
+ return self._parent
972
+
973
+ @property
974
+ def children(self) -> Optional[List[Union['SoftwareSystemInstance', 'ContainerInstance', 'InfrastructureNode', 'DeploymentNode']]]:
975
+ return self._children
976
+
977
+ @property
978
+ def destinations(self) -> List[DslElement]:
979
+ return self._destinations
980
+
981
+ @property
982
+ def sources(self) -> List[DslElement]:
983
+ return self._sources
984
+
985
+ @property
986
+ def relationships(self) -> Set[DslRelationship]:
987
+ return self._relationships
988
+
989
+ def __enter__(self) -> Self:
990
+ stack = _current_deployment_node_stack.get()
991
+ stack.extend([self])
992
+ self._token = _current_deployment_node_stack.set(stack)
993
+ return self
994
+
995
+ def __exit__(
996
+ self,
997
+ exc_type: Optional[Type[BaseException]],
998
+ exc_value: Optional[BaseException],
999
+ traceback: Optional[Any]
1000
+ ) -> None:
1001
+ stack = _current_deployment_node_stack.get()
1002
+ stack.pop()
1003
+ _current_deployment_node_stack.reset(self._token)
1004
+
1005
+ def add_infrastructure_node(self, node: 'InfrastructureNode') -> None:
1006
+ self._m.infrastructureNodes.append(node.model)
1007
+ self._children.append(node)
1008
+
1009
+ def add_element_instance(self, instance: Union['SoftwareSystemInstance', 'ContainerInstance']) -> None:
1010
+ if isinstance(instance, SoftwareSystemInstance):
1011
+ self._m.softwareSystemInstances.append(instance.model)
1012
+ elif isinstance(instance, ContainerInstance):
1013
+ self._m.containerInstances.append(instance.model)
1014
+ self._children.append(instance)
1015
+
1016
+ def add_deployment_node(self, node: 'DeploymentNode') -> None:
1017
+ self._m.children.append(node.model)
1018
+ self._children.append(node)
1019
+
1020
+ class InfrastructureNode(DslInfrastructureNodeElement, DslElementRelationOverrides[
1021
+ 'InfrastructureNode',
1022
+ Union[
1023
+ 'DeploymentNode',
1024
+ 'InfrastructureNode',
1025
+ 'SoftwareSystemInstance',
1026
+ 'ContainerInstance',
1027
+ ]
1028
+ ]):
1029
+
1030
+ def __init__(self, name: str, description: str="", technology: str="", tags: Set[str]=set(), properties: Dict[str, Any]=dict()) -> None:
1031
+ self._m = buildzr.models.InfrastructureNode()
1032
+ self._m.id = GenerateId.for_element()
1033
+ self._m.name = name
1034
+ self._m.description = description
1035
+ self._m.technology = technology
1036
+ self._m.properties = properties
1037
+ self._parent: Optional[DeploymentNode] = None
1038
+ self._tags = {'Element', 'Infrastructure Node'}.union(tags)
1039
+ self._m.tags = ','.join(self._tags)
1040
+
1041
+ self._sources: List[DslElement] = []
1042
+ self._destinations: List[DslElement] = []
1043
+ self._relationships: Set[DslRelationship] = set()
1044
+
1045
+ stack = _current_deployment_node_stack.get()
1046
+ if stack:
1047
+ stack[-1].add_infrastructure_node(self)
1048
+
1049
+ deployment_environment = _current_deployment_environment.get()
1050
+ if deployment_environment is not None:
1051
+ self._m.environment = deployment_environment.name
1052
+
1053
+ @property
1054
+ def model(self) -> buildzr.models.InfrastructureNode:
1055
+ return self._m
1056
+
1057
+ @property
1058
+ def tags(self) -> Set[str]:
1059
+ return self._tags
1060
+
1061
+ @property
1062
+ def parent(self) -> Optional[DeploymentNode]:
1063
+ return self._parent
1064
+
1065
+ @property
1066
+ def children(self) -> None:
1067
+ """
1068
+ The `InfrastructureNode` element does not have any children, and will always return
1069
+ `None`.
1070
+ """
1071
+ return None
1072
+
1073
+ @property
1074
+ def sources(self) -> List[DslElement]:
1075
+ return self._sources
1076
+
1077
+ @property
1078
+ def destinations(self) -> List[DslElement]:
1079
+ return self._destinations
1080
+
1081
+ @property
1082
+ def relationships(self) -> Set[DslRelationship]:
1083
+ return self._relationships
1084
+
1085
+ class SoftwareSystemInstance(DslElementInstance, DslElementRelationOverrides[
1086
+ 'SoftwareSystemInstance',
1087
+ 'InfrastructureNode',
1088
+ ]):
1089
+
1090
+ def __init__(
1091
+ self,
1092
+ software_system: 'SoftwareSystem',
1093
+ deployment_groups: Optional[List['DeploymentGroup']]=None,
1094
+ tags: Set[str]=set(),
1095
+ ) -> None:
1096
+ self._m = buildzr.models.SoftwareSystemInstance()
1097
+ self._m.id = GenerateId.for_element()
1098
+ self._m.softwareSystemId = software_system.model.id
1099
+ self._parent: Optional[DeploymentNode] = None
1100
+ self._element = software_system
1101
+ self._m.deploymentGroups = [g.name for g in deployment_groups] if deployment_groups else ["Default"]
1102
+ self._tags = {'Software System Instance'}.union(tags)
1103
+ self._m.tags = ','.join(self._tags)
1104
+
1105
+ self._sources: List[DslElement] = []
1106
+ self._destinations: List[DslElement] = []
1107
+ self._relationships: Set[DslRelationship] = set()
1108
+
1109
+ stack = _current_deployment_node_stack.get()
1110
+ if stack:
1111
+ self._parent = stack[-1]
1112
+ self._parent.add_element_instance(self)
1113
+
1114
+ deployment_environment = _current_deployment_environment.get()
1115
+ if deployment_environment is not None:
1116
+ self._m.environment = deployment_environment.name
1117
+
1118
+ @property
1119
+ def model(self) -> buildzr.models.SoftwareSystemInstance:
1120
+ return self._m
1121
+
1122
+ @property
1123
+ def tags(self) -> Set[str]:
1124
+ return self._tags
1125
+
1126
+ @property
1127
+ def parent(self) -> Optional[DeploymentNode]:
1128
+ return self._parent
1129
+
1130
+ @property
1131
+ def children(self) -> None:
1132
+ """
1133
+ The `SoftwareSystemInstance` element does not have any children, and will always return
1134
+ `None`.
1135
+ """
1136
+ return None
1137
+
1138
+ @property
1139
+ def destinations(self) -> List[DslElement]:
1140
+ return self._destinations
1141
+
1142
+ @property
1143
+ def sources(self) -> List[DslElement]:
1144
+ return self._sources
1145
+
1146
+ @property
1147
+ def relationships(self) -> Set[DslRelationship]:
1148
+ return self._relationships
1149
+
1150
+ @property
1151
+ def element(self) -> DslElement:
1152
+ return self._element
1153
+
1154
+ class ContainerInstance(DslElementInstance, DslElementRelationOverrides[
1155
+ 'ContainerInstance',
1156
+ 'InfrastructureNode',
1157
+ ]):
1158
+
1159
+ def __init__(
1160
+ self,
1161
+ container: 'Container',
1162
+ deployment_groups: Optional[List['DeploymentGroup']]=None,
1163
+ tags: Set[str]=set(),
1164
+ ) -> None:
1165
+ self._m = buildzr.models.ContainerInstance()
1166
+ self._m.id = GenerateId.for_element()
1167
+ self._m.containerId = container.model.id
1168
+ self._parent: Optional[DeploymentNode] = None
1169
+ self._element = container
1170
+ self._m.deploymentGroups = [g.name for g in deployment_groups] if deployment_groups else ["Default"]
1171
+ self._tags = {'Container Instance'}.union(tags)
1172
+ self._m.tags = ','.join(self._tags)
1173
+
1174
+ self._sources: List[DslElement] = []
1175
+ self._destinations: List[DslElement] = []
1176
+ self._relationships: Set[DslRelationship] = set()
1177
+
1178
+ stack = _current_deployment_node_stack.get()
1179
+ if stack:
1180
+ self._parent = stack[-1]
1181
+ self._parent.add_element_instance(self)
1182
+
1183
+ deployment_environment = _current_deployment_environment.get()
1184
+ if deployment_environment is not None:
1185
+ self._m.environment = deployment_environment.name
1186
+
1187
+ @property
1188
+ def model(self) -> buildzr.models.ContainerInstance:
1189
+ return self._m
1190
+
1191
+ @property
1192
+ def tags(self) -> Set[str]:
1193
+ return self._tags
1194
+
1195
+ @property
1196
+ def parent(self) -> Optional[DeploymentNode]:
1197
+ return self._parent
1198
+
1199
+ @property
1200
+ def children(self) -> None:
1201
+ """
1202
+ The `ContainerInstance` element does not have any children, and will always return
1203
+ `None`.
1204
+ """
1205
+ return None
1206
+
1207
+ @property
1208
+ def sources(self) -> List[DslElement]:
1209
+ return self._sources
1210
+
1211
+ @property
1212
+ def destinations(self) -> List[DslElement]:
1213
+ return self._destinations
1214
+
1215
+ @property
1216
+ def relationships(self) -> Set[DslRelationship]:
1217
+ return self._relationships
1218
+
1219
+ @property
1220
+ def element(self) -> DslElement:
1221
+ return self._element
1222
+
1223
+ class DeploymentGroup:
1224
+
1225
+ def __init__(self, name: str) -> None:
1226
+ self._name = name
1227
+
1228
+ @property
1229
+ def name(self) -> str:
1230
+ return self._name
1231
+
711
1232
  def _auto_layout_to_model(auto_layout: _AutoLayout) -> buildzr.models.AutomaticLayout:
712
1233
  """
713
1234
  See: https://docs.structurizr.com/dsl/language#autolayout
@@ -1126,6 +1647,248 @@ class ComponentView(DslViewElement):
1126
1647
  for relationship_id in relationship_ids:
1127
1648
  self._m.relationships.append(RelationshipView(id=relationship_id))
1128
1649
 
1650
+ class DeploymentView(DslViewElement):
1651
+
1652
+ from buildzr.dsl.expression import Expression, WorkspaceExpression, ElementExpression, RelationshipExpression
1653
+
1654
+ @property
1655
+ def model(self) -> buildzr.models.DeploymentView:
1656
+ return self._m
1657
+
1658
+ def __init__(
1659
+ self,
1660
+ environment: DeploymentEnvironment,
1661
+ key: str,
1662
+ software_system_selector: Optional[Union[SoftwareSystem, Callable[[WorkspaceExpression], SoftwareSystem]]]=None,
1663
+ description: str="",
1664
+ auto_layout: _AutoLayout='tb',
1665
+ title: Optional[str]=None,
1666
+ include_elements: List[Union[DslElement, Callable[[WorkspaceExpression, ElementExpression], bool]]]=[],
1667
+ exclude_elements: List[Union[DslElement, Callable[[WorkspaceExpression, ElementExpression], bool]]]=[],
1668
+ include_relationships: List[Union[DslElement, Callable[[WorkspaceExpression, RelationshipExpression], bool]]]=[],
1669
+ exclude_relationships: List[Union[DslElement, Callable[[WorkspaceExpression, RelationshipExpression], bool]]]=[],
1670
+ properties: Optional[Dict[str, str]]=None,
1671
+ ) -> None:
1672
+ self._m = buildzr.models.DeploymentView()
1673
+
1674
+ self._selector = software_system_selector
1675
+ self._environment = environment
1676
+
1677
+ self._m.key = key
1678
+ self._m.description = description
1679
+ self._m.environment = environment.name
1680
+
1681
+ self._m.automaticLayout = _auto_layout_to_model(auto_layout)
1682
+ self._m.title = title
1683
+ self._m.properties = properties
1684
+
1685
+ self._include_elements = include_elements
1686
+ self._exclude_elements = exclude_elements
1687
+ self._include_relationships = include_relationships
1688
+ self._exclude_relationships = exclude_relationships
1689
+
1690
+ workspace = _current_workspace.get()
1691
+ if workspace is not None:
1692
+ workspace.apply_view(self)
1693
+
1694
+ def _on_added(self, workspace: Workspace) -> None:
1695
+
1696
+ from buildzr.dsl.expression import Expression, WorkspaceExpression, ElementExpression, RelationshipExpression
1697
+ from buildzr.dsl.explorer import Explorer
1698
+ from buildzr.models import ElementView, RelationshipView
1699
+
1700
+ software_system: Optional[SoftwareSystem] = None
1701
+ if self._selector is not None:
1702
+ if isinstance(self._selector, SoftwareSystem):
1703
+ software_system = self._selector
1704
+ self._m.softwareSystemId = software_system.model.id
1705
+ else:
1706
+ software_system = self._selector(WorkspaceExpression(workspace))
1707
+ self._m.softwareSystemId = software_system.model.id
1708
+
1709
+ view_elements_filter: List[Union[DslElement, Callable[[WorkspaceExpression, ElementExpression], bool]]] = []
1710
+ view_elements_filter_excludes: List[Union[DslElement, Callable[[WorkspaceExpression, ElementExpression], bool]]] = []
1711
+ view_relationships_filter_env: List[Union[DslElement, Callable[[WorkspaceExpression, RelationshipExpression], bool]]] = []
1712
+ view_relationships_filter_implied_instance_relationships: List[Union[DslElement, Callable[[WorkspaceExpression, RelationshipExpression], bool]]] = []
1713
+
1714
+ def is_software_system_contains_container(
1715
+ software_system_id: str,
1716
+ container_id: str,
1717
+ ) -> bool:
1718
+ for software_system in workspace.model.model.softwareSystems:
1719
+ if software_system.id == software_system_id:
1720
+ for container in software_system.containers:
1721
+ if container.id == container_id:
1722
+ return True
1723
+ return False
1724
+
1725
+ def recursive_includes(
1726
+ deployment_node_ancestor_ids: List[str],
1727
+ deployment_node: buildzr.models.DeploymentNode,
1728
+ upstream_software_system_ids: Set[str],
1729
+ environment: str,
1730
+ include_ids: Set[str],
1731
+ selected_software_system: Optional[buildzr.models.SoftwareSystem] = None,
1732
+ ) -> None:
1733
+
1734
+ """
1735
+ Recursively includes the relevant deployment nodes, software system
1736
+ instances, container instances, and infrastructure nodes based on
1737
+ the provided environment and DeploymentView parameters.
1738
+
1739
+ @param deployment_node_ancestor_ids: List of ancestor deployment
1740
+ node IDs. Useful for tracing back the upstream deployment nodes that
1741
+ should be included in the view. For example, we may have deployment nodes
1742
+ `a` -> `b` -> `c`, and we want to include all of them if `c` is included,
1743
+ even if `b` has no software system instances, container instances,
1744
+ or infrastructure nodes.
1745
+
1746
+ @param upstream_software_system_ids: Set of software system IDs that
1747
+ whose instance exists in the upstream deployment nodes.
1748
+ """
1749
+
1750
+ instance_ids: Set[str] = set()
1751
+ for child in deployment_node.children:
1752
+ if child.environment == environment:
1753
+ recursive_includes(
1754
+ deployment_node_ancestor_ids + [deployment_node.id],
1755
+ child,
1756
+ upstream_software_system_ids.union({
1757
+ software_system_instance.softwareSystemId
1758
+ for software_system_instance in deployment_node.softwareSystemInstances
1759
+ }),
1760
+ environment,
1761
+ include_ids,
1762
+ selected_software_system
1763
+ )
1764
+
1765
+ if selected_software_system is None:
1766
+ software_instance_ids = {
1767
+ instance.id for instance in deployment_node.softwareSystemInstances
1768
+ if instance.environment == environment
1769
+ }
1770
+
1771
+ sibling_software_system_ids = {
1772
+ instance.softwareSystemId for instance in deployment_node.softwareSystemInstances
1773
+ if instance.environment == environment
1774
+ }
1775
+
1776
+ container_instance_ids = {
1777
+ instance.id for instance in deployment_node.containerInstances
1778
+ if instance.environment == environment and \
1779
+ not any({
1780
+ is_software_system_contains_container(
1781
+ software_system_id,
1782
+ instance.containerId
1783
+ ) for software_system_id in upstream_software_system_ids.union(sibling_software_system_ids)
1784
+ })
1785
+ }
1786
+
1787
+ instance_ids.update(software_instance_ids)
1788
+ instance_ids.update(container_instance_ids)
1789
+
1790
+ else:
1791
+ container_instance_ids = {
1792
+ instance.id for instance in deployment_node.containerInstances
1793
+ if instance.environment == environment and \
1794
+ is_software_system_contains_container(
1795
+ selected_software_system.id,
1796
+ instance.containerId
1797
+ )
1798
+ }
1799
+
1800
+ instance_ids.update(container_instance_ids)
1801
+
1802
+ software_instance_relation_ids: Set[str] = set()
1803
+ for software_system_instance in deployment_node.softwareSystemInstances:
1804
+ if software_system_instance.relationships and software_system_instance.environment == environment:
1805
+ for relationship in software_system_instance.relationships:
1806
+ software_instance_relation_ids.add(relationship.id)
1807
+
1808
+ container_instance_relation_ids: Set[str] = set()
1809
+ if selected_software_system is not None:
1810
+ # Note: These relations are created in the `__exit__` of each
1811
+ # `DeploymentEnvironment` -- the relationships are being implied
1812
+ # from the respective `SoftwareSystem`s and `Container`s.
1813
+ for container_instance in deployment_node.containerInstances:
1814
+ if container_instance.relationships and container_instance.environment == environment:
1815
+ for relationship in container_instance.relationships:
1816
+ container_instance_relation_ids.add(relationship.id)
1817
+
1818
+ infrastructure_node_relation_ids: Set[str] = set()
1819
+ for infrastructure_node in deployment_node.infrastructureNodes:
1820
+ if infrastructure_node.relationships and infrastructure_node.environment == environment:
1821
+ for relationship in infrastructure_node.relationships:
1822
+ infrastructure_node_relation_ids.add(relationship.id)
1823
+
1824
+ infrastructure_node_ids = {
1825
+ infrastructure_node.id for infrastructure_node in deployment_node.infrastructureNodes
1826
+ if infrastructure_node.environment == environment
1827
+ }
1828
+
1829
+ instance_ids.update(software_instance_relation_ids)
1830
+ instance_ids.update(container_instance_relation_ids)
1831
+ instance_ids.update(infrastructure_node_relation_ids)
1832
+ instance_ids.update(infrastructure_node_ids)
1833
+
1834
+ # Only include this deployment node
1835
+ # if there's anything to include at all.
1836
+ if len(instance_ids) > 0:
1837
+ for deployment_node_ancestor_id in deployment_node_ancestor_ids:
1838
+ include_ids.add(deployment_node_ancestor_id)
1839
+ include_ids.add(deployment_node.id)
1840
+ include_ids.update(instance_ids)
1841
+
1842
+ include_ids: Set[str] = set()
1843
+ upstream_software_system_ids: Set[str] = set()
1844
+
1845
+ for root_deployment_node in workspace.model.model.deploymentNodes:
1846
+ if root_deployment_node.environment == self._environment.name:
1847
+ recursive_includes(
1848
+ [],
1849
+ root_deployment_node,
1850
+ upstream_software_system_ids,
1851
+ self._environment.name,
1852
+ include_ids,
1853
+ software_system.model if software_system else None
1854
+ )
1855
+
1856
+ view_elements_filter = [
1857
+ lambda w, e: (
1858
+ e.id in include_ids
1859
+ ),
1860
+ ]
1861
+
1862
+ view_relationships_filter_env = [
1863
+ lambda w, r: r.source.environment == self._environment.name,
1864
+ lambda w, r: r.destination.environment == self._environment.name,
1865
+ ]
1866
+
1867
+ view_relationships_filter_implied_instance_relationships = [
1868
+ lambda w, r: r.id in include_ids,
1869
+ ]
1870
+
1871
+ expression = Expression(
1872
+ include_elements=self._include_elements + view_elements_filter,
1873
+ exclude_elements=self._exclude_elements,
1874
+ include_relationships=self._include_relationships +\
1875
+ view_relationships_filter_env +\
1876
+ view_relationships_filter_implied_instance_relationships,
1877
+ exclude_relationships=self._exclude_relationships,
1878
+ )
1879
+
1880
+ element_ids = [str(element.model.id) for element in expression.elements(workspace)]
1881
+ relationship_ids = [str(relationship.model.id) for relationship in expression.relationships(workspace)]
1882
+
1883
+ self._m.elements = []
1884
+ for element_id in element_ids:
1885
+ self._m.elements.append(ElementView(id=element_id))
1886
+
1887
+ self._m.relationships = []
1888
+ for relationship_id in relationship_ids:
1889
+ self._m.relationships.append(RelationshipView(id=relationship_id))
1890
+
1891
+
1129
1892
  class StyleElements:
1130
1893
 
1131
1894
  from buildzr.dsl.expression import WorkspaceExpression, ElementExpression
buildzr/dsl/explorer.py CHANGED
@@ -3,6 +3,10 @@ from buildzr.dsl.dsl import (
3
3
  SoftwareSystem,
4
4
  Container,
5
5
  Component,
6
+ DeploymentNode,
7
+ InfrastructureNode,
8
+ SoftwareSystemInstance,
9
+ ContainerInstance,
6
10
  )
7
11
 
8
12
  from buildzr.dsl.relations import (
@@ -27,10 +31,32 @@ from buildzr.dsl.interfaces import (
27
31
 
28
32
  class Explorer:
29
33
 
30
- def __init__(self, workspace_or_element: Union[Workspace, Person, SoftwareSystem, Container, Component]):
34
+ def __init__(
35
+ self,
36
+ workspace_or_element: Union[
37
+ Workspace,
38
+ Person,
39
+ SoftwareSystem,
40
+ Container,
41
+ Component,
42
+ DeploymentNode,
43
+ InfrastructureNode,
44
+ SoftwareSystemInstance,
45
+ ContainerInstance,
46
+ ]
47
+ ):
31
48
  self._workspace_or_element = workspace_or_element
32
49
 
33
- def walk_elements(self) -> Generator[Union[Person, SoftwareSystem, Container, Component], None, None]:
50
+ def walk_elements(self) -> Generator[Union[
51
+ Person,
52
+ SoftwareSystem,
53
+ Container,
54
+ Component,
55
+ DeploymentNode,
56
+ InfrastructureNode,
57
+ SoftwareSystemInstance,
58
+ ContainerInstance
59
+ ], None, None]:
34
60
  if self._workspace_or_element.children:
35
61
  for child in self._workspace_or_element.children:
36
62
  explorer = Explorer(child).walk_elements()
buildzr/dsl/expression.py CHANGED
@@ -10,6 +10,10 @@ from buildzr.dsl.dsl import (
10
10
  SoftwareSystem,
11
11
  Container,
12
12
  Component,
13
+ DeploymentNode,
14
+ InfrastructureNode,
15
+ SoftwareSystemInstance,
16
+ ContainerInstance,
13
17
  TypedDynamicAttribute,
14
18
  )
15
19
 
@@ -20,7 +24,22 @@ from typing import Set, Union, Optional, List, Dict, Any, Callable, Tuple, Seque
20
24
  from typing_extensions import TypeIs
21
25
 
22
26
  def _has_technology_attribute(obj: DslElement) -> TypeIs[Union[Container, Component]]:
23
- if isinstance(obj, (Person, SoftwareSystem, Workspace)):
27
+ if isinstance(obj, (Person, SoftwareSystem, Workspace, SoftwareSystemInstance, ContainerInstance)):
28
+ return False
29
+ return True
30
+
31
+ def _has_group_attribute(obj: DslElement) -> TypeIs[Union[Person, SoftwareSystem, Container, Component]]:
32
+ if isinstance(obj, (Workspace, DeploymentNode, InfrastructureNode, SoftwareSystemInstance, ContainerInstance)):
33
+ return False
34
+ return True
35
+
36
+ def _has_name_attribute(obj: DslElement) -> TypeIs[Union[Person, SoftwareSystem, Container, Component, DeploymentNode, InfrastructureNode]]:
37
+ if isinstance(obj, (Workspace, SoftwareSystemInstance, ContainerInstance)):
38
+ return False
39
+ return True
40
+
41
+ def _has_environment_attribute(obj: DslElement) -> TypeIs[Union[ContainerInstance, SoftwareSystemInstance]]:
42
+ if isinstance(obj, (Workspace, Person, SoftwareSystem, Container, Component)):
24
43
  return False
25
44
  return True
26
45
 
@@ -38,7 +57,19 @@ class FlattenElement:
38
57
 
39
58
  @property
40
59
  def names(self) -> Set[Union[str]]:
41
- return set([str(element.model.name) for element in self._elements])
60
+
61
+ """
62
+ Returns the names of the elements.
63
+
64
+ If the element is a `SoftwareSystemInstance` or `ContainerInstance`,
65
+ which has no name attribute, it will be excluded from the result.
66
+ """
67
+
68
+ name_set: Set[str] = set()
69
+ for element in self._elements:
70
+ if _has_name_attribute(element):
71
+ name_set.add(str(element.model.name))
72
+ return name_set
42
73
 
43
74
  @property
44
75
  def tags(self) -> Set[Union[str]]:
@@ -102,6 +133,10 @@ class ElementExpression:
102
133
  def parent(self) -> Optional[Union[DslWorkspaceElement, DslElement]]:
103
134
  return self._element.parent
104
135
 
136
+ @property
137
+ def children(self) -> FlattenElement:
138
+ return FlattenElement(self._element.children)
139
+
105
140
  @property
106
141
  def sources(self) -> FlattenElement:
107
142
  return FlattenElement(self._element.sources)
@@ -112,18 +147,47 @@ class ElementExpression:
112
147
 
113
148
  @property
114
149
  def properties(self) -> Dict[str, Any]:
115
- return self._element.model.properties
150
+ if self._element.model.properties is not None:
151
+ return self._element.model.properties
152
+ return dict()
116
153
 
117
154
  @property
118
155
  def group(self) -> Optional[str]:
156
+
119
157
  """
120
- Returns the group of the element. The group is a string that is used to
158
+ Returns the group of the element (if applicable). The group is a string that is used to
121
159
  group elements in the Structurizr DSL.
122
160
  """
123
- if not isinstance(self._element.model, buildzr.models.Workspace):
161
+
162
+ if _has_group_attribute(self._element):
124
163
  return self._element.model.group
125
164
  return None
126
165
 
166
+ @property
167
+ def environment(self) -> Optional[str]:
168
+
169
+ """
170
+ Returns the environment of the element (if applicable). The environment
171
+ is a string that is used to group deployment nodes and instances in the
172
+ Structurizr DSL.
173
+ """
174
+
175
+ if _has_environment_attribute(self._element):
176
+ return self._element.model.environment
177
+ return None
178
+
179
+ def is_instance_of(self, other: DslElement) -> bool:
180
+
181
+ """
182
+ Returns `True` if the element is an instance of the other element.
183
+ """
184
+
185
+ if isinstance(self._element, SoftwareSystemInstance):
186
+ return self._element.model.softwareSystemId == other.model.id
187
+ elif isinstance(self._element, ContainerInstance):
188
+ return self._element.model.containerId == other.model.id
189
+ return False
190
+
127
191
  def __eq__(self, element: object) -> bool:
128
192
  return isinstance(element, type(self._element)) and\
129
193
  element.model.id == self._element.model.id
@@ -3,6 +3,10 @@ from .interfaces import (
3
3
  DslRelationship,
4
4
  DslWorkspaceElement,
5
5
  DslViewElement,
6
+ DslDeploymentEnvironment,
7
+ DslInfrastructureNodeElement,
8
+ DslDeploymentNodeElement,
9
+ DslElementInstance,
6
10
  BindLeft,
7
11
  BindRight,
8
12
  BindLeftLate,
@@ -25,6 +25,10 @@ Model = Union[
25
25
  buildzr.models.SoftwareSystem,
26
26
  buildzr.models.Container,
27
27
  buildzr.models.Component,
28
+ buildzr.models.DeploymentNode,
29
+ buildzr.models.InfrastructureNode,
30
+ buildzr.models.SoftwareSystemInstance,
31
+ buildzr.models.ContainerInstance,
28
32
  ]
29
33
 
30
34
  TSrc = TypeVar('TSrc', bound='DslElement', contravariant=True)
@@ -205,4 +209,77 @@ class DslViewElement(ABC):
205
209
  @property
206
210
  @abstractmethod
207
211
  def model(self) -> ViewModel:
212
+ pass
213
+
214
+ class DslElementInstance(DslElement):
215
+
216
+ Model = Union[
217
+ buildzr.models.SoftwareSystemInstance,
218
+ buildzr.models.ContainerInstance,
219
+ ]
220
+
221
+ @property
222
+ @abstractmethod
223
+ def model(self) -> Model:
224
+ pass
225
+
226
+ @property
227
+ def parent(self) -> Optional['DslDeploymentNodeElement']:
228
+ pass
229
+
230
+ @property
231
+ def tags(self) -> Set[str]:
232
+ pass
233
+
234
+ @property
235
+ def element(self) -> DslElement:
236
+ pass
237
+
238
+ class DslInfrastructureNodeElement(DslElement):
239
+
240
+ @property
241
+ @abstractmethod
242
+ def model(self) -> buildzr.models.InfrastructureNode:
243
+ pass
244
+
245
+ @property
246
+ def tags(self) -> Set[str]:
247
+ pass
248
+
249
+ @property
250
+ @abstractmethod
251
+ def parent(self) -> Optional['DslDeploymentNodeElement']:
252
+ pass
253
+
254
+ class DslDeploymentNodeElement(DslElement):
255
+
256
+ @property
257
+ @abstractmethod
258
+ def model(self) -> buildzr.models.DeploymentNode:
259
+ pass
260
+
261
+ @property
262
+ def tags(self) -> Set[str]:
263
+ pass
264
+
265
+ @property
266
+ @abstractmethod
267
+ def parent(self) -> Optional['DslWorkspaceElement']:
268
+ pass
269
+
270
+ @property
271
+ @abstractmethod
272
+ def children(self) -> Optional[Sequence[Union[DslElementInstance, 'DslInfrastructureNodeElement', 'DslDeploymentNodeElement']]]:
273
+ pass
274
+
275
+ class DslDeploymentEnvironment(ABC):
276
+
277
+ @property
278
+ @abstractmethod
279
+ def parent(self) -> Optional[DslWorkspaceElement]:
280
+ pass
281
+
282
+ @property
283
+ @abstractmethod
284
+ def children(self) -> Sequence[DslDeploymentNodeElement]:
208
285
  pass
@@ -5,6 +5,15 @@ curl $schema_url > structurizr.yaml
5
5
  # Change from 'long' (unsupported) to 'integer'
6
6
  yq -i -y '.components.schemas.Workspace.properties.id.type = "integer"' structurizr.yaml
7
7
 
8
+ # Add `deploymentGroups: List[str]` to the following dataclasses:
9
+ # - `SoftwareSystemInstance`
10
+ # - `ContainerInstance`
11
+ # Because the `deploymentGroups` property is not in the schema, but it's
12
+ # something that is present in the JSON output if we convert the DSL into JSON
13
+ # (when using the `deploymentGroup` keyword).
14
+ yq -i -y '.components.schemas.ContainerInstance.properties.deploymentGroups = {"type": "array", "items": {"type": "string"}}' structurizr.yaml
15
+ yq -i -y '.components.schemas.SoftwareSystemInstance.properties.deploymentGroups = {"type": "array", "items": {"type": "string"}}' structurizr.yaml
16
+
8
17
  # Type 'integer' doesn't support 'number' type, but supports the following:
9
18
  # int32, int64, default, date-time, unix-time
10
19
  # yq -i 'select(.components.schemas.*.properties.*.format=="integer" and .components.schemas.*.properties.*.type=="number") .components.schemas.*.properties.*.format="default"' structurizr.yaml
buildzr/models/models.py CHANGED
@@ -1,6 +1,6 @@
1
1
  # generated by datamodel-codegen:
2
2
  # filename: structurizr.yaml
3
- # timestamp: 2024-07-06T09:38:20+00:00
3
+ # timestamp: 2025-05-20T13:19:11+00:00
4
4
 
5
5
  from __future__ import annotations
6
6
 
@@ -1098,6 +1098,7 @@ class SoftwareSystemInstance:
1098
1098
  """
1099
1099
  The set of HTTP-based health checks for this software system instance.
1100
1100
  """
1101
+ deploymentGroups: Optional[List[str]] = None
1101
1102
 
1102
1103
 
1103
1104
  @dataclass
@@ -1142,6 +1143,7 @@ class ContainerInstance:
1142
1143
  """
1143
1144
  The set of HTTP-based health checks for this container instance.
1144
1145
  """
1146
+ deploymentGroups: Optional[List[str]] = None
1145
1147
 
1146
1148
 
1147
1149
  @dataclass
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: buildzr
3
- Version: 0.0.13
3
+ Version: 0.0.14
4
4
  Summary: Structurizr for the `buildzr`s 🧱⚒️
5
5
  Project-URL: homepage, https://github.com/amirulmenjeni/buildzr
6
6
  Project-URL: issues, https://github.com/amirulmenjeni/buildzr/issues
@@ -11,12 +11,10 @@ Classifier: Development Status :: 3 - Alpha
11
11
  Classifier: License :: OSI Approved :: MIT License
12
12
  Classifier: Operating System :: OS Independent
13
13
  Classifier: Programming Language :: Python :: 3
14
- Classifier: Programming Language :: Python :: 3.8
15
- Classifier: Programming Language :: Python :: 3.9
16
14
  Classifier: Programming Language :: Python :: 3.10
17
15
  Classifier: Programming Language :: Python :: 3.11
18
16
  Classifier: Programming Language :: Python :: 3.12
19
- Requires-Python: >=3.8
17
+ Requires-Python: >=3.10
20
18
  Requires-Dist: pyhumps==3.8.0
21
19
  Requires-Dist: pytest>=8.3.3
22
20
  Provides-Extra: dev
@@ -0,0 +1,24 @@
1
+ buildzr/__about__.py,sha256=Re70LR9m7cAhH54rssYyZTF_NDTijR8Lo_1hWF3ofTI,19
2
+ buildzr/__init__.py,sha256=hY-cOdjBQcz0v2m8cBF1oEJFIbcR3sWI-xww--0RKSo,99
3
+ buildzr/dsl/__init__.py,sha256=qJ41IXcabKUjvwMzgfUCFdmDnSBBK7VFADpoVdOYLKQ,538
4
+ buildzr/dsl/color.py,sha256=at5lo3WgLEDCjrnbu37ra1p1TjzdB51sxeW7pBMC_7U,4019
5
+ buildzr/dsl/dsl.py,sha256=qqKlz8KNzAxdwsdPM5YhVE2JhwYMRJ9o7KbMMarQGlw,83579
6
+ buildzr/dsl/explorer.py,sha256=m1nI0Rd0bXGj1uXDgTC4DJhc2FMma522IepPNvQF07E,1853
7
+ buildzr/dsl/expression.py,sha256=TLSe-uGlHhNqMPQU_5IRLIP-ZGsQ_ts3DquBMcYlwBg,11777
8
+ buildzr/dsl/relations.py,sha256=GBs5epr9uuExU_H6VcP4XY76iJPQ__rz_d8tZlhhWQ4,11891
9
+ buildzr/dsl/factory/__init__.py,sha256=niaYqvNPUWJejoPyRyABUtzVsoxaV8eSjzS9dta4bMI,30
10
+ buildzr/dsl/factory/gen_id.py,sha256=LnaeOCMngSvYkcGnuARjQYoUVWdcOoNHO2EHe6PMGco,538
11
+ buildzr/dsl/interfaces/__init__.py,sha256=3InvtLOyYNm9nCPFAkYVbunBQ4AVSdHZ46Ah0CkoLNM,294
12
+ buildzr/dsl/interfaces/interfaces.py,sha256=hLISS0cAfhHqhTWRI5UPKKzqmsPuHmFgdx3JjzBA01U,6750
13
+ buildzr/encoders/__init__.py,sha256=suID63Ay-023T0uKD25EAoGYmAMTa9AKxIjioccpiPM,32
14
+ buildzr/encoders/encoder.py,sha256=n8WLVMrisykBTLTr1z6PAxgqhqW2dFRZhSupOuMdx_A,3235
15
+ buildzr/models/__init__.py,sha256=SRfF7oDVlOOAi6nGKiJIUK6B_arqYLO9iSMp-2IZZps,21
16
+ buildzr/models/generate.sh,sha256=EJ63d4cYmRnMFzc3hIR6bro44PXYEOt3EE9BxY4F8cU,1670
17
+ buildzr/models/models.py,sha256=NJOFYiRQ2i_1gP2ajPNpEfVLAz-1iCqqt1gPOHDPIks,42587
18
+ buildzr/sinks/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
19
+ buildzr/sinks/interfaces.py,sha256=LOZekP4WNjomD5J5f3FnZTwGj0aXMr6RbrvyFV5zn0E,383
20
+ buildzr/sinks/json_sink.py,sha256=onKOZTpwOQfeMEj1ONkuIEHBAQhx4yQSqqI_lgZBaP8,777
21
+ buildzr-0.0.14.dist-info/METADATA,sha256=CkcJWUlnCfXDHZQwMZWhbnxTgCkOIWDdoJI4n2dl4ZM,6480
22
+ buildzr-0.0.14.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
23
+ buildzr-0.0.14.dist-info/licenses/LICENSE.md,sha256=e8e6W6tL4MbBY-c-gXMgDbaMf_BnaQDQv4Yoy42b-CI,1070
24
+ buildzr-0.0.14.dist-info/RECORD,,
@@ -1,24 +0,0 @@
1
- buildzr/__about__.py,sha256=0umS7uDo4dgXIWRbDuyPpvLwiPObPtpkbuCwUnINda0,18
2
- buildzr/__init__.py,sha256=hY-cOdjBQcz0v2m8cBF1oEJFIbcR3sWI-xww--0RKSo,99
3
- buildzr/dsl/__init__.py,sha256=k0G9blhA3NSzCBs1dSfBNzCh0iDS_ylkzS_5a3pqrSY,375
4
- buildzr/dsl/color.py,sha256=at5lo3WgLEDCjrnbu37ra1p1TjzdB51sxeW7pBMC_7U,4019
5
- buildzr/dsl/dsl.py,sha256=EXHGvC84Xz8ba2f3XMTS3HLqfrkxc8D905IThJu_WUM,53644
6
- buildzr/dsl/explorer.py,sha256=GuQihoEvmTwiriXT3X8oasJ_U65ERyKJeJ2WW-S9D84,1389
7
- buildzr/dsl/expression.py,sha256=Q4lK6tWETLg_YfLTGuT20Gl2dsWp6m5_8PhlTF_dJbw,9525
8
- buildzr/dsl/relations.py,sha256=GBs5epr9uuExU_H6VcP4XY76iJPQ__rz_d8tZlhhWQ4,11891
9
- buildzr/dsl/factory/__init__.py,sha256=niaYqvNPUWJejoPyRyABUtzVsoxaV8eSjzS9dta4bMI,30
10
- buildzr/dsl/factory/gen_id.py,sha256=LnaeOCMngSvYkcGnuARjQYoUVWdcOoNHO2EHe6PMGco,538
11
- buildzr/dsl/interfaces/__init__.py,sha256=GRzfjdDxAUaZ-2n-eP4YaGLy3b0_giHhMshGqoj9rbo,176
12
- buildzr/dsl/interfaces/interfaces.py,sha256=OYOS-eGlkadGWXvcLSP1Qs9AnJfhtoJGh9UqJRC8gDk,5079
13
- buildzr/encoders/__init__.py,sha256=suID63Ay-023T0uKD25EAoGYmAMTa9AKxIjioccpiPM,32
14
- buildzr/encoders/encoder.py,sha256=n8WLVMrisykBTLTr1z6PAxgqhqW2dFRZhSupOuMdx_A,3235
15
- buildzr/models/__init__.py,sha256=SRfF7oDVlOOAi6nGKiJIUK6B_arqYLO9iSMp-2IZZps,21
16
- buildzr/models/generate.sh,sha256=924UoEXr5WBZ926TZfRgEQGHwBqtLGU5k0G2UfExLEg,1061
17
- buildzr/models/models.py,sha256=0LhLG1wmbt4dvROV5MEBZLLoxPbMpkUsOqNz525cynE,42489
18
- buildzr/sinks/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
19
- buildzr/sinks/interfaces.py,sha256=LOZekP4WNjomD5J5f3FnZTwGj0aXMr6RbrvyFV5zn0E,383
20
- buildzr/sinks/json_sink.py,sha256=onKOZTpwOQfeMEj1ONkuIEHBAQhx4yQSqqI_lgZBaP8,777
21
- buildzr-0.0.13.dist-info/METADATA,sha256=oz1_tOasiJ4EKOqtPpO45Bq8jmoua3eoohE9mbK_CdQ,6579
22
- buildzr-0.0.13.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
23
- buildzr-0.0.13.dist-info/licenses/LICENSE.md,sha256=e8e6W6tL4MbBY-c-gXMgDbaMf_BnaQDQv4Yoy42b-CI,1070
24
- buildzr-0.0.13.dist-info/RECORD,,