Skip to content

Commit

Permalink
feat: load UML from any remote http/https endpoint
Browse files Browse the repository at this point in the history
  • Loading branch information
tsypuk committed Feb 16, 2024
1 parent 77e178d commit ca72932
Show file tree
Hide file tree
Showing 5 changed files with 211 additions and 15 deletions.
54 changes: 40 additions & 14 deletions multicloud_diagrams/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@
import os.path
import pkgutil
import re

import requests
import yaml
import hashlib

Expand Down Expand Up @@ -117,6 +119,30 @@ def extract_info(input_string):
return None


def extract_sequence_diagram(start_tag, end_tag, lines, start_line):
sequence_diagram = []

if isinstance(lines, str):
lines = lines.split("\n")

in_uml = False
for line in lines[start_line - 1:]:
if start_tag in line:
in_uml = True
if end_tag in line:
in_uml = False
sequence_diagram.append(line)
break
if in_uml:
sequence_diagram.append(line)
sequence_diagram = '\n'.join(sequence_diagram)
return sequence_diagram


def extract_resource_from_endpoint(md_file_name):
return os.path.basename(md_file_name)


class MultiCloudDiagrams:
def __init__(self, debug_mode=False, shadow=True, layer_name=''):
self.actors_to_nodes = {}
Expand Down Expand Up @@ -654,25 +680,25 @@ def export_to_file(self, file_path):
with open(file_path, 'w', encoding="utf-8") as file:
file.write(resulting_xml)

def read_uml_from_http(self, md_http_endpoint, base, start_line=0, start_tag="@startuml", end_tag="@enduml", edge_style=None, label_style=None):
response = requests.get(md_http_endpoint)
# Check if the request was successful (status code 200)
if response.status_code == 200:
sequence_diagram = extract_sequence_diagram(start_tag, end_tag, response.text, start_line)
base = base if base else extract_resource_from_endpoint(md_http_endpoint)
print(sequence_diagram)
self.process_sequence_diagram(edge_style, base, label_style, sequence_diagram)
else:
print(f"Failed to read the file. Status code: {response.status_code}")

def read_uml_from_md(self, md_file_name, base, start_line=0, start_tag="@startuml", end_tag="@enduml", edge_style=None, label_style=None):
with open(md_file_name, 'r') as file:
lines = file.readlines()

sequence_diagram = []
in_uml = False
for line in lines[start_line - 1:]:
if start_tag in line:
in_uml = True
if end_tag in line:
in_uml = False
sequence_diagram.append(line)
break
if in_uml:
sequence_diagram.append(line)
sequence_diagram = ''.join(sequence_diagram)
sequence_diagram = extract_sequence_diagram(start_tag, end_tag, lines, start_line)
print(sequence_diagram)

if not base:
base = md_file_name
base = base if base else md_file_name

self.process_sequence_diagram(edge_style, base, label_style, sequence_diagram)

Expand Down
2 changes: 1 addition & 1 deletion samples/output/output.prod_plantuml.adr.drawio

Large diffs are not rendered by default.

103 changes: 103 additions & 0 deletions samples/output/output.prod_plantuml.https.adr.drawio
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
<mxfile host="multicloud-diagrams" agent="PIP package multicloud-diagrams. Generate resources in draw.io compatible format for Cloud infrastructure. Copyrights @ Roman Tsypuk 2023. MIT license." type="MultiCloud">
<diagram id="diagram_1" name="AWS components">
<mxGraphModel dx="1015" dy="661" grid="1" gridSize="10" guides="1" tooltips="1" connect="1" arrows="1" fold="1" page="1" pageScale="1" pageWidth="850" pageHeight="1100" math="0" shadow="1">
<root>
<mxCell id="0"/>
<mxCell id="1" parent="0"/>
<mxCell id="vertex:lambda_function:arn:aws:lambda:eu-west-1:123456789012:function:producer-lambda" value="&lt;b&gt;Name&lt;/b&gt;: producer-lambda&lt;BR&gt;&lt;b&gt;ARN&lt;/b&gt;: arn:aws:lambda:eu-west-1:123456789012:function:producer-lambda&lt;BR&gt;-----------&lt;BR&gt;&lt;b&gt;CodeSize&lt;/b&gt;: 1234&lt;BR&gt;&lt;b&gt;Handler&lt;/b&gt;: main&lt;BR&gt;&lt;b&gt;Layers&lt;/b&gt;: 0&lt;BR&gt;&lt;b&gt;Memory&lt;/b&gt;: 128&lt;BR&gt;&lt;b&gt;PackageType&lt;/b&gt;: Zip&lt;BR&gt;&lt;b&gt;Runtime&lt;/b&gt;: go1.x&lt;BR&gt;&lt;b&gt;Timeout&lt;/b&gt;: 30&lt;BR&gt;&lt;b&gt;TracingConfig&lt;/b&gt;: {'Mode': 'Active'}&lt;BR&gt;&lt;b&gt;Version&lt;/b&gt;: $LATEST" style="verticalLabelPosition=bottom;verticalAlign=top;aspect=fixed;align=left;pointerEvents=1;shape=mxgraph.aws3.lambda_function;prIcon=server;fillColor=#F58534;gradientColor=none;html=1;" parent="1" vertex="1">
<mxGeometry width="69" height="72" as="geometry" x="590" y="654"/>
</mxCell>
<mxCell id="vertex:lambda_function:arn:aws:lambda:eu-west-1:123456789012:function:consumer-lambda" value="&lt;b&gt;Name&lt;/b&gt;: consumer-lambda&lt;BR&gt;&lt;b&gt;ARN&lt;/b&gt;: arn:aws:lambda:eu-west-1:123456789012:function:consumer-lambda" style="verticalLabelPosition=bottom;verticalAlign=top;aspect=fixed;align=left;pointerEvents=1;shape=mxgraph.aws3.lambda_function;prIcon=server;fillColor=#F58534;gradientColor=none;html=1;" parent="1" vertex="1">
<mxGeometry width="69" height="72" as="geometry" x="1770" y="433"/>
</mxCell>
<mxCell id="vertex:dynamo:arn:aws:dynamodb:eu-west-1:123456789012:table/table1" value="&lt;b&gt;Name&lt;/b&gt;: table1&lt;BR&gt;&lt;b&gt;ARN&lt;/b&gt;: arn:aws:dynamodb:eu-west-1:123456789012:table/table1" style="outlineConnect=0;dashed=0;verticalLabelPosition=bottom;verticalAlign=top;align=left;html=1;shape=mxgraph.aws3.dynamo_db;fillColor=#2E73B8;gradientColor=none;" parent="1" vertex="1">
<mxGeometry width="72" height="81" as="geometry" x="1768.5" y="590"/>
</mxCell>
<mxCell id="vertex:sns:arn:aws:sns:eu-west-1:123456789012:internal.fifo" value="&lt;b&gt;Name&lt;/b&gt;: internal&lt;BR&gt;&lt;b&gt;ARN&lt;/b&gt;: arn:aws:sns:eu-west-1:123456789012:internal.fifo&lt;BR&gt;-----------&lt;BR&gt;&lt;b&gt;Owner&lt;/b&gt;: 123456789&lt;BR&gt;&lt;b&gt;SubscriptionsConfirmed&lt;/b&gt;: 3&lt;BR&gt;&lt;b&gt;SubscriptionsPending&lt;/b&gt;: 0" style="sketch=0;outlineConnect=0;gradientColor=#FF4F8B;gradientDirection=north;fillColor=#BC1356;strokeColor=#ffffff;dashed=0;verticalLabelPosition=bottom;verticalAlign=top;align=left;html=1;fontSize=12;fontStyle=0;aspect=fixed;shape=mxgraph.aws4.resourceIcon;resIcon=mxgraph.aws4.sns;" parent="1" vertex="1">
<mxGeometry width="78" height="78" as="geometry" x="900" y="540"/>
</mxCell>
<mxCell id="vertex:sqs:arn:aws:sqs:eu-west-1:123456789012:int-eu-live-events.fifo" value="&lt;b&gt;Name&lt;/b&gt;: events&lt;BR&gt;&lt;b&gt;ARN&lt;/b&gt;: arn:aws:sqs:eu-west-1:123456789012:int-eu-live-events.fifo&lt;BR&gt;-----------&lt;BR&gt;&lt;b&gt;DelaySeconds&lt;/b&gt;: 0&lt;BR&gt;&lt;b&gt;FifoQueue&lt;/b&gt;: TRUE&lt;BR&gt;&lt;b&gt;ReceiveMessageWaitTimeSeconds&lt;/b&gt;: 0&lt;BR&gt;&lt;b&gt;SqsManagedSseEnabled&lt;/b&gt;: false&lt;BR&gt;&lt;b&gt;VisibilityTimeout&lt;/b&gt;: 30" style="sketch=0;outlineConnect=0;gradientColor=#FF4F8B;gradientDirection=north;fillColor=#BC1356;strokeColor=#ffffff;dashed=0;verticalLabelPosition=bottom;verticalAlign=top;align=left;html=1;fontSize=12;fontStyle=0;aspect=fixed;shape=mxgraph.aws4.resourceIcon;resIcon=mxgraph.aws4.sqs;" parent="1" vertex="1">
<mxGeometry width="78" height="78" as="geometry" x="1380" y="430"/>
</mxCell>
<mxCell id="vertex:sqs:arn:aws:sqs:eu-west-1:123456789012:int-eu-live-events2.fifo" value="&lt;b&gt;Name&lt;/b&gt;: events2&lt;BR&gt;&lt;b&gt;ARN&lt;/b&gt;: arn:aws:sqs:eu-west-1:123456789012:int-eu-live-events2.fifo" style="sketch=0;outlineConnect=0;gradientColor=#FF4F8B;gradientDirection=north;fillColor=#BC1356;strokeColor=#ffffff;dashed=0;verticalLabelPosition=bottom;verticalAlign=top;align=left;html=1;fontSize=12;fontStyle=0;aspect=fixed;shape=mxgraph.aws4.resourceIcon;resIcon=mxgraph.aws4.sqs;" parent="1" vertex="1">
<mxGeometry width="78" height="78" as="geometry" x="1380" y="654"/>
</mxCell>
<mxCell id="vertex:s3:arn:aws:s3:::bucket_name/key_name" value="&lt;b&gt;Name&lt;/b&gt;: key_name&lt;BR&gt;&lt;b&gt;ARN&lt;/b&gt;: arn:aws:s3:::bucket_name/key_name" style="outlineConnect=0;dashed=0;verticalLabelPosition=bottom;verticalAlign=top;align=left;html=1;shape=mxgraph.aws3.bucket_with_objects;fillColor=#E05243;gradientColor=none;" parent="1" vertex="1">
<mxGeometry width="78" height="78" as="geometry" x="230" y="651"/>
</mxCell>
<mxCell id="edge:lambda_function:arn:aws:lambda:eu-west-1:123456789012:function:producer-lambda:to:sns:arn:aws:sns:eu-west-1:123456789012:internal.fifo" style="jettySize=auto;html=1;startArrow=none;endArrow=none;" parent="1" source="vertex:lambda_function:arn:aws:lambda:eu-west-1:123456789012:function:producer-lambda" target="vertex:sns:arn:aws:sns:eu-west-1:123456789012:internal.fifo" edge="2">
<mxGeometry as="geometry"/>
</mxCell>
<mxCell id="edge:lambda_function:arn:aws:lambda:eu-west-1:123456789012:function:producer-lambda:to:s3:arn:aws:s3:::bucket_name/key_name" style="jettySize=auto;html=1;startArrow=none;endArrow=none;" parent="1" source="vertex:lambda_function:arn:aws:lambda:eu-west-1:123456789012:function:producer-lambda" target="vertex:s3:arn:aws:s3:::bucket_name/key_name" edge="2">
<mxGeometry as="geometry"/>
</mxCell>
<mxCell id="edge:sns:arn:aws:sns:eu-west-1:123456789012:internal.fifo:to:sqs:arn:aws:sqs:eu-west-1:123456789012:int-eu-live-events.fifo" style="jettySize=auto;html=1;startArrow=none;endArrow=none;" parent="1" source="vertex:sns:arn:aws:sns:eu-west-1:123456789012:internal.fifo" target="vertex:sqs:arn:aws:sqs:eu-west-1:123456789012:int-eu-live-events.fifo" edge="2">
<mxGeometry as="geometry"/>
</mxCell>
<mxCell id="edge:sns:arn:aws:sns:eu-west-1:123456789012:internal.fifo:to:sqs:arn:aws:sqs:eu-west-1:123456789012:int-eu-live-events2.fifo" style="jettySize=auto;html=1;startArrow=none;endArrow=none;" parent="1" source="vertex:sns:arn:aws:sns:eu-west-1:123456789012:internal.fifo" target="vertex:sqs:arn:aws:sqs:eu-west-1:123456789012:int-eu-live-events2.fifo" edge="2">
<mxGeometry as="geometry"/>
</mxCell>
<mxCell id="edge:sqs:arn:aws:sqs:eu-west-1:123456789012:int-eu-live-events.fifo:to:lambda_function:arn:aws:lambda:eu-west-1:123456789012:function:consumer-lambda" style="jettySize=auto;html=1;startArrow=none;endArrow=none;" parent="1" source="vertex:sqs:arn:aws:sqs:eu-west-1:123456789012:int-eu-live-events.fifo" target="vertex:lambda_function:arn:aws:lambda:eu-west-1:123456789012:function:consumer-lambda" edge="2">
<mxGeometry as="geometry"/>
</mxCell>
<mxCell id="edge:lambda_function:arn:aws:lambda:eu-west-1:123456789012:function:consumer-lambda:to:dynamo:arn:aws:dynamodb:eu-west-1:123456789012:table/table1" style="jettySize=auto;html=1;startArrow=none;endArrow=none;" parent="1" source="vertex:lambda_function:arn:aws:lambda:eu-west-1:123456789012:function:consumer-lambda" target="vertex:dynamo:arn:aws:dynamodb:eu-west-1:123456789012:table/table1" edge="2">
<mxGeometry as="geometry"/>
</mxCell>
<mxCell id="2" parent="0" value="process"/>
<mxCell id="3" parent="0" value="actors"/>
<mxCell id="vertex:actor:5991ce42" value="&lt;b&gt;Name&lt;/b&gt;: Donald" style="shape=umlActor;verticalLabelPosition=bottom;verticalAlign=top;html=1;outlineConnect=0;" parent="3" vertex="1">
<mxGeometry width="30" height="60" as="geometry"/>
</mxCell>
<mxCell id="edge_process_1:actor:5991ce42:to:s3:arn:aws:s3:::bucket_name/key_name" style="jettySize=auto;html=1;orthogonalLoop=1;edgeStyle=orthogonalEdgeStyle;curved=1;startArrow=oval;endArrow=classicThin;dashed=1;strokeColor=#FF3333;strokeWidth=3;fontSize=22;" parent="2" source="vertex:actor:5991ce42" target="vertex:s3:arn:aws:s3:::bucket_name/key_name" edge="2">
<mxGeometry as="geometry"/>
</mxCell>
<mxCell id="label_process_1:actor:5991ce42:to:s3:arn:aws:s3:::bucket_name/key_name" value="1: Put new file into S3 bucket&lt;BR&gt;Single line note on the left" style="edgeLabel;html=1;align=left;verticalAlign=middle;resizable=0;points=[];labelBackgroundColor=none;fontColor=#FF3333;fontStyle=0;fontSize=14;" parent="edge_process_1:actor:5991ce42:to:s3:arn:aws:s3:::bucket_name/key_name" vertex="1" connectable="0">
<mxGeometry relative="1" as="geometry">
<mxPoint as="offset"/>
</mxGeometry>
</mxCell>
<mxCell id="edge_process_2:s3:arn:aws:s3:::bucket_name/key_name:to:lambda_function:arn:aws:lambda:eu-west-1:123456789012:function:producer-lambda" style="jettySize=auto;html=1;orthogonalLoop=1;edgeStyle=orthogonalEdgeStyle;curved=1;startArrow=oval;endArrow=classicThin;dashed=1;strokeColor=#FF3333;strokeWidth=3;fontSize=22;" parent="2" source="vertex:s3:arn:aws:s3:::bucket_name/key_name" target="vertex:lambda_function:arn:aws:lambda:eu-west-1:123456789012:function:producer-lambda" edge="2">
<mxGeometry as="geometry"/>
</mxCell>
<mxCell id="label_process_2:s3:arn:aws:s3:::bucket_name/key_name:to:lambda_function:arn:aws:lambda:eu-west-1:123456789012:function:producer-lambda" value="2: LifeConfig Rule invokes lambda function" style="edgeLabel;html=1;align=left;verticalAlign=middle;resizable=0;points=[];labelBackgroundColor=none;fontColor=#FF3333;fontStyle=0;fontSize=14;" parent="edge_process_2:s3:arn:aws:s3:::bucket_name/key_name:to:lambda_function:arn:aws:lambda:eu-west-1:123456789012:function:producer-lambda" vertex="1" connectable="0">
<mxGeometry relative="1" as="geometry">
<mxPoint as="offset"/>
</mxGeometry>
</mxCell>
<mxCell id="edge_process_3:lambda_function:arn:aws:lambda:eu-west-1:123456789012:function:producer-lambda:to:sns:arn:aws:sns:eu-west-1:123456789012:internal.fifo" style="jettySize=auto;html=1;orthogonalLoop=1;edgeStyle=orthogonalEdgeStyle;curved=1;startArrow=oval;endArrow=classicThin;dashed=1;strokeColor=#FF3333;strokeWidth=3;fontSize=22;" parent="2" source="vertex:lambda_function:arn:aws:lambda:eu-west-1:123456789012:function:producer-lambda" target="vertex:sns:arn:aws:sns:eu-west-1:123456789012:internal.fifo" edge="2">
<mxGeometry as="geometry"/>
</mxCell>
<mxCell id="label_process_3:lambda_function:arn:aws:lambda:eu-west-1:123456789012:function:producer-lambda:to:sns:arn:aws:sns:eu-west-1:123456789012:internal.fifo" value="3: Send Event to SNS that file processing is finished&lt;BR&gt;multiline&lt;BR&gt;note&lt;BR&gt;added on the right" style="edgeLabel;html=1;align=left;verticalAlign=middle;resizable=0;points=[];labelBackgroundColor=none;fontColor=#FF3333;fontStyle=0;fontSize=14;" parent="edge_process_3:lambda_function:arn:aws:lambda:eu-west-1:123456789012:function:producer-lambda:to:sns:arn:aws:sns:eu-west-1:123456789012:internal.fifo" vertex="1" connectable="0">
<mxGeometry relative="1" as="geometry">
<mxPoint as="offset"/>
</mxGeometry>
</mxCell>
<mxCell id="edge_process_4:sns:arn:aws:sns:eu-west-1:123456789012:internal.fifo:to:sqs:arn:aws:sqs:eu-west-1:123456789012:int-eu-live-events.fifo" style="jettySize=auto;html=1;orthogonalLoop=1;edgeStyle=orthogonalEdgeStyle;curved=1;startArrow=oval;endArrow=classicThin;dashed=1;strokeColor=#FF3333;strokeWidth=3;fontSize=22;" parent="2" source="vertex:sns:arn:aws:sns:eu-west-1:123456789012:internal.fifo" target="vertex:sqs:arn:aws:sqs:eu-west-1:123456789012:int-eu-live-events.fifo" edge="2">
<mxGeometry as="geometry"/>
</mxCell>
<mxCell id="label_process_4:sns:arn:aws:sns:eu-west-1:123456789012:internal.fifo:to:sqs:arn:aws:sqs:eu-west-1:123456789012:int-eu-live-events.fifo" value="4: Fanout Event to SQS" style="edgeLabel;html=1;align=left;verticalAlign=middle;resizable=0;points=[];labelBackgroundColor=none;fontColor=#FF3333;fontStyle=0;fontSize=14;" parent="edge_process_4:sns:arn:aws:sns:eu-west-1:123456789012:internal.fifo:to:sqs:arn:aws:sqs:eu-west-1:123456789012:int-eu-live-events.fifo" vertex="1" connectable="0">
<mxGeometry relative="1" as="geometry">
<mxPoint as="offset"/>
</mxGeometry>
</mxCell>
<mxCell id="4" parent="0" value="load"/>
<mxCell id="edge_load_1:sqs:arn:aws:sqs:eu-west-1:123456789012:int-eu-live-events.fifo:to:lambda_function:arn:aws:lambda:eu-west-1:123456789012:function:consumer-lambda" style="jettySize=auto;html=1;orthogonalLoop=1;edgeStyle=orthogonalEdgeStyle;curved=1;startArrow=oval;endArrow=classicThin;dashed=1;strokeColor=#FF3333;strokeWidth=3;fontSize=22;" parent="4" source="vertex:sqs:arn:aws:sqs:eu-west-1:123456789012:int-eu-live-events.fifo" target="vertex:lambda_function:arn:aws:lambda:eu-west-1:123456789012:function:consumer-lambda" edge="2">
<mxGeometry as="geometry"/>
</mxCell>
<mxCell id="label_load_1:sqs:arn:aws:sqs:eu-west-1:123456789012:int-eu-live-events.fifo:to:lambda_function:arn:aws:lambda:eu-west-1:123456789012:function:consumer-lambda" value="1: poll message from SQS and invoke consumer lambda function" style="edgeLabel;html=1;align=left;verticalAlign=middle;resizable=0;points=[];labelBackgroundColor=none;fontColor=#FF3333;fontStyle=0;fontSize=14;" parent="edge_load_1:sqs:arn:aws:sqs:eu-west-1:123456789012:int-eu-live-events.fifo:to:lambda_function:arn:aws:lambda:eu-west-1:123456789012:function:consumer-lambda" vertex="1" connectable="0">
<mxGeometry relative="1" as="geometry">
<mxPoint as="offset"/>
</mxGeometry>
</mxCell>
<mxCell id="edge_load_2:lambda_function:arn:aws:lambda:eu-west-1:123456789012:function:consumer-lambda:to:dynamo:arn:aws:dynamodb:eu-west-1:123456789012:table/table1" style="jettySize=auto;html=1;orthogonalLoop=1;edgeStyle=orthogonalEdgeStyle;curved=1;startArrow=oval;endArrow=classicThin;dashed=1;strokeColor=#FF3333;strokeWidth=3;fontSize=22;" parent="4" source="vertex:lambda_function:arn:aws:lambda:eu-west-1:123456789012:function:consumer-lambda" target="vertex:dynamo:arn:aws:dynamodb:eu-west-1:123456789012:table/table1" edge="2">
<mxGeometry as="geometry"/>
</mxCell>
<mxCell id="label_load_2:lambda_function:arn:aws:lambda:eu-west-1:123456789012:function:consumer-lambda:to:dynamo:arn:aws:dynamodb:eu-west-1:123456789012:table/table1" value="2: Update DynamoDB Table. Save image status." style="edgeLabel;html=1;align=left;verticalAlign=middle;resizable=0;points=[];labelBackgroundColor=none;fontColor=#FF3333;fontStyle=0;fontSize=14;" parent="edge_load_2:lambda_function:arn:aws:lambda:eu-west-1:123456789012:function:consumer-lambda:to:dynamo:arn:aws:dynamodb:eu-west-1:123456789012:table/table1" vertex="1" connectable="0">
<mxGeometry relative="1" as="geometry">
<mxPoint as="offset"/>
</mxGeometry>
</mxCell>
</root>
</mxGraphModel>
</diagram>
</mxfile>
40 changes: 40 additions & 0 deletions samples/samples/aws_plant_uml_from_https.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
from multicloud_diagrams import MultiCloudDiagrams
from samples.samples.aws_service_end_2_end import prepare_end2end


def main():
mcd = MultiCloudDiagrams()

prefix = 'prod'
prev_file = f'../output/output.{prefix}_plantuml.https.adr.drawio'

mcd.read_coords_from_file(prev_file)
prepare_end2end(mcd)
mcd.read_uml_mappings('uml_mapping.yml')

label_style = {
'labelBackgroundColor': 'none',
'fontColor': '#FF3333',
'fontStyle': 0,
'fontSize': 14
}
style = {
'orthogonalLoop': '1',
'edgeStyle': 'orthogonalEdgeStyle',
'curved': '1',
'startArrow': 'oval',
'endArrow': 'classicThin',
'dashed': '1',
'strokeColor': '#FF3333',
'strokeWidth': '3',
'fontSize': '22'
}

mcd.read_uml_from_http(md_http_endpoint="https://raw.githubusercontent.com/tsypuk/multicloud-diagrams/main/samples/samples/ADR.MD", start_line=11, base="process", edge_style=style, label_style=label_style)
mcd.read_uml_from_http(md_http_endpoint="https://raw.githubusercontent.com/tsypuk/multicloud-diagrams/main/samples/samples/ADR.MD", start_line=37, base="load", edge_style=style, label_style=label_style)

mcd.export_to_file(prev_file)


if __name__ == "__main__":
main()

0 comments on commit ca72932

Please sign in to comment.