buildzr 0.0.19__tar.gz → 0.0.20__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.
- {buildzr-0.0.19 → buildzr-0.0.20}/PKG-INFO +1 -1
- buildzr-0.0.20/buildzr/__about__.py +1 -0
- {buildzr-0.0.19 → buildzr-0.0.20}/buildzr/dsl/dsl.py +56 -0
- {buildzr-0.0.19 → buildzr-0.0.20}/tests/test_dsl.py +217 -1
- buildzr-0.0.19/buildzr/__about__.py +0 -1
- {buildzr-0.0.19 → buildzr-0.0.20}/.gitignore +0 -0
- {buildzr-0.0.19 → buildzr-0.0.20}/CONTRIBUTING.md +0 -0
- {buildzr-0.0.19 → buildzr-0.0.20}/LICENSE.md +0 -0
- {buildzr-0.0.19 → buildzr-0.0.20}/README.md +0 -0
- {buildzr-0.0.19 → buildzr-0.0.20}/buildzr/__init__.py +0 -0
- {buildzr-0.0.19 → buildzr-0.0.20}/buildzr/dsl/__init__.py +0 -0
- {buildzr-0.0.19 → buildzr-0.0.20}/buildzr/dsl/color.py +0 -0
- {buildzr-0.0.19 → buildzr-0.0.20}/buildzr/dsl/explorer.py +0 -0
- {buildzr-0.0.19 → buildzr-0.0.20}/buildzr/dsl/expression.py +0 -0
- {buildzr-0.0.19 → buildzr-0.0.20}/buildzr/dsl/factory/__init__.py +0 -0
- {buildzr-0.0.19 → buildzr-0.0.20}/buildzr/dsl/factory/gen_id.py +0 -0
- {buildzr-0.0.19 → buildzr-0.0.20}/buildzr/dsl/interfaces/__init__.py +0 -0
- {buildzr-0.0.19 → buildzr-0.0.20}/buildzr/dsl/interfaces/interfaces.py +0 -0
- {buildzr-0.0.19 → buildzr-0.0.20}/buildzr/dsl/relations.py +0 -0
- {buildzr-0.0.19 → buildzr-0.0.20}/buildzr/encoders/__init__.py +0 -0
- {buildzr-0.0.19 → buildzr-0.0.20}/buildzr/encoders/encoder.py +0 -0
- {buildzr-0.0.19 → buildzr-0.0.20}/buildzr/models/__init__.py +0 -0
- {buildzr-0.0.19 → buildzr-0.0.20}/buildzr/models/generate.sh +0 -0
- {buildzr-0.0.19 → buildzr-0.0.20}/buildzr/models/models.py +0 -0
- {buildzr-0.0.19 → buildzr-0.0.20}/buildzr/sinks/__init__.py +0 -0
- {buildzr-0.0.19 → buildzr-0.0.20}/buildzr/sinks/interfaces.py +0 -0
- {buildzr-0.0.19 → buildzr-0.0.20}/buildzr/sinks/json_sink.py +0 -0
- {buildzr-0.0.19 → buildzr-0.0.20}/pyproject.toml +0 -0
- {buildzr-0.0.19 → buildzr-0.0.20}/tests/__init__.py +0 -0
- {buildzr-0.0.19 → buildzr-0.0.20}/tests/abstract_builder.py +0 -0
- {buildzr-0.0.19 → buildzr-0.0.20}/tests/samples/__init__.py +0 -0
- {buildzr-0.0.19 → buildzr-0.0.20}/tests/samples/component_view.py +0 -0
- {buildzr-0.0.19 → buildzr-0.0.20}/tests/samples/container_view.py +0 -0
- {buildzr-0.0.19 → buildzr-0.0.20}/tests/samples/container_view_sugar.py +0 -0
- {buildzr-0.0.19 → buildzr-0.0.20}/tests/samples/groups.py +0 -0
- {buildzr-0.0.19 → buildzr-0.0.20}/tests/samples/implied_relationships.py +0 -0
- {buildzr-0.0.19 → buildzr-0.0.20}/tests/samples/nested_groups.py +0 -0
- {buildzr-0.0.19 → buildzr-0.0.20}/tests/samples/simple.py +0 -0
- {buildzr-0.0.19 → buildzr-0.0.20}/tests/samples/simple_dsl.py +0 -0
- {buildzr-0.0.19 → buildzr-0.0.20}/tests/samples/system_context_view.py +0 -0
- {buildzr-0.0.19 → buildzr-0.0.20}/tests/samples/system_landscape_view.py +0 -0
- {buildzr-0.0.19 → buildzr-0.0.20}/tests/test_explorer.py +0 -0
- {buildzr-0.0.19 → buildzr-0.0.20}/tests/test_expression.py +0 -0
- {buildzr-0.0.19 → buildzr-0.0.20}/tests/test_typehints.py +0 -0
- {buildzr-0.0.19 → buildzr-0.0.20}/tests/test_views.py +0 -0
- {buildzr-0.0.19 → buildzr-0.0.20}/tests/test_workspaces.py +0 -0
@@ -0,0 +1 @@
|
|
1
|
+
VERSION = "0.0.20"
|
@@ -842,6 +842,10 @@ class DeploymentEnvironment(DslDeploymentEnvironment):
|
|
842
842
|
new relationship between those software system instances.
|
843
843
|
|
844
844
|
These implied relationships are used in `DeploymentView`.
|
845
|
+
|
846
|
+
Relationships are only created between instances that share at least
|
847
|
+
one common deployment group. If no deployment groups are specified,
|
848
|
+
instances are considered to be in the same default group.
|
845
849
|
"""
|
846
850
|
|
847
851
|
software_instances = [
|
@@ -889,6 +893,13 @@ class DeploymentEnvironment(DslDeploymentEnvironment):
|
|
889
893
|
for this_software_instance in this_software_instances:
|
890
894
|
for other_software_instance in other_software_instances:
|
891
895
|
|
896
|
+
# Only create relationship if instances share a deployment group
|
897
|
+
if not self._instances_share_deployment_group(
|
898
|
+
this_software_instance,
|
899
|
+
other_software_instance
|
900
|
+
):
|
901
|
+
continue
|
902
|
+
|
892
903
|
already_exists = this_software_instance.model.relationships is not None and any(
|
893
904
|
r.sourceId == this_software_instance.model.id and
|
894
905
|
r.destinationId == other_software_instance.model.id and
|
@@ -906,6 +917,40 @@ class DeploymentEnvironment(DslDeploymentEnvironment):
|
|
906
917
|
)
|
907
918
|
r.model.linkedRelationshipId = relationship.id
|
908
919
|
|
920
|
+
def _instances_share_deployment_group(
|
921
|
+
self,
|
922
|
+
instance1: Union['ContainerInstance', 'SoftwareSystemInstance'],
|
923
|
+
instance2: Union['ContainerInstance', 'SoftwareSystemInstance']
|
924
|
+
) -> bool:
|
925
|
+
"""
|
926
|
+
Check if two deployment instances share at least one common deployment group.
|
927
|
+
|
928
|
+
If either instance has no deployment groups specified, they are considered
|
929
|
+
to be in the "default" group and can relate to all other instances without
|
930
|
+
deployment groups.
|
931
|
+
|
932
|
+
Args:
|
933
|
+
instance1: First deployment instance
|
934
|
+
instance2: Second deployment instance
|
935
|
+
|
936
|
+
Returns:
|
937
|
+
True if instances share at least one deployment group or if both have
|
938
|
+
no deployment groups specified, False otherwise.
|
939
|
+
"""
|
940
|
+
groups1 = set(instance1.model.deploymentGroups or [])
|
941
|
+
groups2 = set(instance2.model.deploymentGroups or [])
|
942
|
+
|
943
|
+
# If both have no deployment groups, they can relate
|
944
|
+
if not groups1 and not groups2:
|
945
|
+
return True
|
946
|
+
|
947
|
+
# If one has groups and the other doesn't, they cannot relate
|
948
|
+
if (groups1 and not groups2) or (not groups1 and groups2):
|
949
|
+
return False
|
950
|
+
|
951
|
+
# Check if they share at least one common group
|
952
|
+
return bool(groups1.intersection(groups2))
|
953
|
+
|
909
954
|
def _imply_container_instance_relationships(self, workspace: Workspace) -> None:
|
910
955
|
|
911
956
|
"""
|
@@ -915,6 +960,10 @@ class DeploymentEnvironment(DslDeploymentEnvironment):
|
|
915
960
|
between those container instances.
|
916
961
|
|
917
962
|
These implied relationships are used in `DeploymentView`.
|
963
|
+
|
964
|
+
Relationships are only created between instances that share at least
|
965
|
+
one common deployment group. If no deployment groups are specified,
|
966
|
+
instances are considered to be in the same default group.
|
918
967
|
"""
|
919
968
|
|
920
969
|
from buildzr.dsl.expression import Expression
|
@@ -963,6 +1012,13 @@ class DeploymentEnvironment(DslDeploymentEnvironment):
|
|
963
1012
|
for this_container_instance in this_container_instances:
|
964
1013
|
for other_container_instance in other_container_instances:
|
965
1014
|
|
1015
|
+
# Only create relationship if instances share a deployment group
|
1016
|
+
if not self._instances_share_deployment_group(
|
1017
|
+
this_container_instance,
|
1018
|
+
other_container_instance
|
1019
|
+
):
|
1020
|
+
continue
|
1021
|
+
|
966
1022
|
already_exists = this_container_instance.model.relationships is not None and any(
|
967
1023
|
r.sourceId == this_container_instance.model.id and
|
968
1024
|
r.destinationId == other_container_instance.model.id and
|
@@ -1373,4 +1373,220 @@ def test_container_instance_relationships_with_missing_instances() -> Optional[N
|
|
1373
1373
|
all_api_destinations = [
|
1374
1374
|
r.destinationId for r in (api_instance.model.relationships or [])
|
1375
1375
|
]
|
1376
|
-
assert external_service.model.id not in all_api_destinations
|
1376
|
+
assert external_service.model.id not in all_api_destinations
|
1377
|
+
|
1378
|
+
def test_container_instance_relationships_respect_deployment_groups() -> Optional[None]:
|
1379
|
+
"""
|
1380
|
+
Test that container instance relationships only connect instances within
|
1381
|
+
the same deployment group.
|
1382
|
+
|
1383
|
+
When containers have relationships and are deployed with deployment groups,
|
1384
|
+
instance relationships should only be created between instances that share
|
1385
|
+
at least one common deployment group.
|
1386
|
+
|
1387
|
+
This matches the behavior in Structurizr DSL where deployment groups act
|
1388
|
+
as boundaries for relationship propagation.
|
1389
|
+
"""
|
1390
|
+
|
1391
|
+
with Workspace("w", scope=None) as w:
|
1392
|
+
with SoftwareSystem("Software System") as software_system:
|
1393
|
+
database = Container("Database")
|
1394
|
+
api = Container("Service API")
|
1395
|
+
api >> "Reads from and writes to" >> database
|
1396
|
+
|
1397
|
+
with DeploymentEnvironment("Production") as production:
|
1398
|
+
service_instance_1 = DeploymentGroup("Service Instance 1")
|
1399
|
+
service_instance_2 = DeploymentGroup("Service Instance 2")
|
1400
|
+
|
1401
|
+
with DeploymentNode("Server 1") as server_1:
|
1402
|
+
api_instance_1 = ContainerInstance(api, [service_instance_1])
|
1403
|
+
with DeploymentNode("Database Server"):
|
1404
|
+
db_instance_1 = ContainerInstance(database, [service_instance_1])
|
1405
|
+
|
1406
|
+
with DeploymentNode("Server 2") as server_2:
|
1407
|
+
api_instance_2 = ContainerInstance(api, [service_instance_2])
|
1408
|
+
with DeploymentNode("Database Server"):
|
1409
|
+
db_instance_2 = ContainerInstance(database, [service_instance_2])
|
1410
|
+
|
1411
|
+
# Verify deployment group assignments
|
1412
|
+
assert api_instance_1.model.deploymentGroups == ["Service Instance 1"]
|
1413
|
+
assert db_instance_1.model.deploymentGroups == ["Service Instance 1"]
|
1414
|
+
assert api_instance_2.model.deploymentGroups == ["Service Instance 2"]
|
1415
|
+
assert db_instance_2.model.deploymentGroups == ["Service Instance 2"]
|
1416
|
+
|
1417
|
+
# Check that api_instance_1 only has relationship to db_instance_1 (same group)
|
1418
|
+
api_1_relationships = [
|
1419
|
+
r for r in (api_instance_1.model.relationships or [])
|
1420
|
+
if r.description == "Reads from and writes to"
|
1421
|
+
]
|
1422
|
+
assert len(api_1_relationships) == 1, f"Expected 1 relationship, found {len(api_1_relationships)}"
|
1423
|
+
assert api_1_relationships[0].destinationId == db_instance_1.model.id
|
1424
|
+
assert api_1_relationships[0].destinationId != db_instance_2.model.id
|
1425
|
+
|
1426
|
+
# Check that api_instance_2 only has relationship to db_instance_2 (same group)
|
1427
|
+
api_2_relationships = [
|
1428
|
+
r for r in (api_instance_2.model.relationships or [])
|
1429
|
+
if r.description == "Reads from and writes to"
|
1430
|
+
]
|
1431
|
+
assert len(api_2_relationships) == 1, f"Expected 1 relationship, found {len(api_2_relationships)}"
|
1432
|
+
assert api_2_relationships[0].destinationId == db_instance_2.model.id
|
1433
|
+
assert api_2_relationships[0].destinationId != db_instance_1.model.id
|
1434
|
+
|
1435
|
+
# Verify no cross-group relationships exist
|
1436
|
+
all_api_1_destinations = [r.destinationId for r in (api_instance_1.model.relationships or [])]
|
1437
|
+
all_api_2_destinations = [r.destinationId for r in (api_instance_2.model.relationships or [])]
|
1438
|
+
|
1439
|
+
assert db_instance_2.model.id not in all_api_1_destinations, "api_instance_1 should not connect to db_instance_2"
|
1440
|
+
assert db_instance_1.model.id not in all_api_2_destinations, "api_instance_2 should not connect to db_instance_1"
|
1441
|
+
|
1442
|
+
def test_software_system_instance_relationships_respect_deployment_groups() -> Optional[None]:
|
1443
|
+
"""
|
1444
|
+
Test that software system instance relationships only connect instances
|
1445
|
+
within the same deployment group.
|
1446
|
+
|
1447
|
+
When software systems have relationships and are deployed with deployment
|
1448
|
+
groups, instance relationships should only be created between instances
|
1449
|
+
that share at least one common deployment group.
|
1450
|
+
"""
|
1451
|
+
|
1452
|
+
with Workspace("w", scope=None) as w:
|
1453
|
+
api_system = SoftwareSystem("API System")
|
1454
|
+
db_system = SoftwareSystem("Database System")
|
1455
|
+
|
1456
|
+
api_system >> "Connects to" >> db_system
|
1457
|
+
|
1458
|
+
with DeploymentEnvironment("Production") as production:
|
1459
|
+
region_1 = DeploymentGroup("Region 1")
|
1460
|
+
region_2 = DeploymentGroup("Region 2")
|
1461
|
+
|
1462
|
+
with DeploymentNode("Datacenter 1") as dc1:
|
1463
|
+
api_instance_1 = SoftwareSystemInstance(api_system, [region_1])
|
1464
|
+
db_instance_1 = SoftwareSystemInstance(db_system, [region_1])
|
1465
|
+
|
1466
|
+
with DeploymentNode("Datacenter 2") as dc2:
|
1467
|
+
api_instance_2 = SoftwareSystemInstance(api_system, [region_2])
|
1468
|
+
db_instance_2 = SoftwareSystemInstance(db_system, [region_2])
|
1469
|
+
|
1470
|
+
# Verify deployment group assignments
|
1471
|
+
assert api_instance_1.model.deploymentGroups == ["Region 1"]
|
1472
|
+
assert db_instance_1.model.deploymentGroups == ["Region 1"]
|
1473
|
+
assert api_instance_2.model.deploymentGroups == ["Region 2"]
|
1474
|
+
assert db_instance_2.model.deploymentGroups == ["Region 2"]
|
1475
|
+
|
1476
|
+
# Check that api_instance_1 only has relationship to db_instance_1 (same group)
|
1477
|
+
api_1_relationships = [
|
1478
|
+
r for r in (api_instance_1.model.relationships or [])
|
1479
|
+
if r.description == "Connects to"
|
1480
|
+
]
|
1481
|
+
assert len(api_1_relationships) == 1, f"Expected 1 relationship, found {len(api_1_relationships)}"
|
1482
|
+
assert api_1_relationships[0].destinationId == db_instance_1.model.id
|
1483
|
+
assert api_1_relationships[0].destinationId != db_instance_2.model.id
|
1484
|
+
|
1485
|
+
# Check that api_instance_2 only has relationship to db_instance_2 (same group)
|
1486
|
+
api_2_relationships = [
|
1487
|
+
r for r in (api_instance_2.model.relationships or [])
|
1488
|
+
if r.description == "Connects to"
|
1489
|
+
]
|
1490
|
+
assert len(api_2_relationships) == 1, f"Expected 1 relationship, found {len(api_2_relationships)}"
|
1491
|
+
assert api_2_relationships[0].destinationId == db_instance_2.model.id
|
1492
|
+
assert api_2_relationships[0].destinationId != db_instance_1.model.id
|
1493
|
+
|
1494
|
+
# Verify no cross-group relationships exist
|
1495
|
+
all_api_1_destinations = [r.destinationId for r in (api_instance_1.model.relationships or [])]
|
1496
|
+
all_api_2_destinations = [r.destinationId for r in (api_instance_2.model.relationships or [])]
|
1497
|
+
|
1498
|
+
assert db_instance_2.model.id not in all_api_1_destinations, "api_instance_1 should not connect to db_instance_2"
|
1499
|
+
assert db_instance_1.model.id not in all_api_2_destinations, "api_instance_2 should not connect to db_instance_1"
|
1500
|
+
|
1501
|
+
def test_container_instance_relationships_with_multiple_shared_deployment_groups() -> Optional[None]:
|
1502
|
+
"""
|
1503
|
+
Test that container instances with overlapping deployment groups can have
|
1504
|
+
relationships.
|
1505
|
+
|
1506
|
+
If two container instances share at least one deployment group, they should
|
1507
|
+
be able to have relationships even if they belong to other groups as well.
|
1508
|
+
"""
|
1509
|
+
|
1510
|
+
with Workspace("w", scope=None) as w:
|
1511
|
+
with SoftwareSystem("Software System") as software_system:
|
1512
|
+
frontend = Container("Frontend")
|
1513
|
+
backend = Container("Backend")
|
1514
|
+
frontend >> "Calls" >> backend
|
1515
|
+
|
1516
|
+
with DeploymentEnvironment("Production") as production:
|
1517
|
+
group_a = DeploymentGroup("Group A")
|
1518
|
+
group_b = DeploymentGroup("Group B")
|
1519
|
+
group_shared = DeploymentGroup("Shared Group")
|
1520
|
+
|
1521
|
+
with DeploymentNode("Server 1"):
|
1522
|
+
# Frontend in Group A and Shared Group
|
1523
|
+
frontend_instance = ContainerInstance(frontend, [group_a, group_shared])
|
1524
|
+
|
1525
|
+
with DeploymentNode("Server 2"):
|
1526
|
+
# Backend in Group B and Shared Group
|
1527
|
+
backend_instance = ContainerInstance(backend, [group_b, group_shared])
|
1528
|
+
|
1529
|
+
# Verify deployment group assignments
|
1530
|
+
assert set(frontend_instance.model.deploymentGroups) == {"Group A", "Shared Group"}
|
1531
|
+
assert set(backend_instance.model.deploymentGroups) == {"Group B", "Shared Group"}
|
1532
|
+
|
1533
|
+
# Frontend and backend share "Shared Group", so relationship should exist
|
1534
|
+
frontend_relationships = [
|
1535
|
+
r for r in (frontend_instance.model.relationships or [])
|
1536
|
+
if r.description == "Calls"
|
1537
|
+
]
|
1538
|
+
assert len(frontend_relationships) == 1, f"Expected 1 relationship, found {len(frontend_relationships)}"
|
1539
|
+
assert frontend_relationships[0].destinationId == backend_instance.model.id
|
1540
|
+
|
1541
|
+
def test_container_instance_relationships_with_no_deployment_groups() -> Optional[None]:
|
1542
|
+
"""
|
1543
|
+
Test that container instances without deployment groups can still have
|
1544
|
+
relationships (backward compatibility).
|
1545
|
+
|
1546
|
+
When no deployment groups are specified, all instances should be able to
|
1547
|
+
relate to each other as before.
|
1548
|
+
"""
|
1549
|
+
|
1550
|
+
with Workspace("w", scope=None) as w:
|
1551
|
+
with SoftwareSystem("Software System") as software_system:
|
1552
|
+
service_a = Container("Service A")
|
1553
|
+
service_b = Container("Service B")
|
1554
|
+
service_a >> "Communicates with" >> service_b
|
1555
|
+
|
1556
|
+
with DeploymentEnvironment("Production") as production:
|
1557
|
+
with DeploymentNode("Server 1"):
|
1558
|
+
# No deployment groups specified
|
1559
|
+
service_a_instance_1 = ContainerInstance(service_a)
|
1560
|
+
service_b_instance_1 = ContainerInstance(service_b)
|
1561
|
+
|
1562
|
+
with DeploymentNode("Server 2"):
|
1563
|
+
# No deployment groups specified
|
1564
|
+
service_a_instance_2 = ContainerInstance(service_a)
|
1565
|
+
service_b_instance_2 = ContainerInstance(service_b)
|
1566
|
+
|
1567
|
+
# When no deployment groups are specified, instances should be able to
|
1568
|
+
# relate to each other (all instances are in the "default" group)
|
1569
|
+
# This maintains backward compatibility
|
1570
|
+
|
1571
|
+
# Each service_a instance should relate to ALL service_b instances
|
1572
|
+
service_a_1_rels = [
|
1573
|
+
r for r in (service_a_instance_1.model.relationships or [])
|
1574
|
+
if r.description == "Communicates with"
|
1575
|
+
]
|
1576
|
+
service_a_2_rels = [
|
1577
|
+
r for r in (service_a_instance_2.model.relationships or [])
|
1578
|
+
if r.description == "Communicates with"
|
1579
|
+
]
|
1580
|
+
|
1581
|
+
# When no groups specified, all instances should connect to all other instances
|
1582
|
+
assert len(service_a_1_rels) == 2, f"Expected 2 relationships (to both service_b instances), found {len(service_a_1_rels)}"
|
1583
|
+
assert len(service_a_2_rels) == 2, f"Expected 2 relationships (to both service_b instances), found {len(service_a_2_rels)}"
|
1584
|
+
|
1585
|
+
# Verify destinations
|
1586
|
+
service_a_1_destinations = {r.destinationId for r in service_a_1_rels}
|
1587
|
+
service_a_2_destinations = {r.destinationId for r in service_a_2_rels}
|
1588
|
+
|
1589
|
+
assert service_b_instance_1.model.id in service_a_1_destinations
|
1590
|
+
assert service_b_instance_2.model.id in service_a_1_destinations
|
1591
|
+
assert service_b_instance_1.model.id in service_a_2_destinations
|
1592
|
+
assert service_b_instance_2.model.id in service_a_2_destinations
|
@@ -1 +0,0 @@
|
|
1
|
-
VERSION = "0.0.19"
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|