Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add a merge option to copy layouts from an existing workspace #142

Closed
wants to merge 3 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 39 additions & 3 deletions src/main/java/com/structurizr/cli/export/ExportCommand.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package com.structurizr.cli.export;

import com.fasterxml.jackson.annotation.JsonCreator;
import com.structurizr.Workspace;
import com.structurizr.cli.AbstractCommand;
import com.structurizr.dsl.StructurizrDslParser;
Expand All @@ -11,7 +12,7 @@
import com.structurizr.export.plantuml.StructurizrPlantUMLExporter;
import com.structurizr.export.websequencediagrams.WebSequenceDiagramsExporter;
import com.structurizr.util.WorkspaceUtils;
import com.structurizr.view.ThemeUtils;
import com.structurizr.view.*;
import io.github.goto1134.structurizr.export.d2.D2Exporter;
import org.apache.commons.cli.*;
import org.apache.commons.logging.Log;
Expand Down Expand Up @@ -78,6 +79,10 @@ public void run(String... args) throws Exception {
option.setRequired(false);
options.addOption(option);

option = new Option("m", "merge", true, "Path to workspace file to merge layouts from");
option.setRequired(false);
options.addOption(option);

CommandLineParser commandLineParser = new DefaultParser();
HelpFormatter formatter = new HelpFormatter();

Expand All @@ -86,13 +91,16 @@ public void run(String... args) throws Exception {
long workspaceId = 1;
String format = "";
String outputPath = null;
String mergePathAsString = null;
File mergePath = null;

try {
CommandLine cmd = commandLineParser.parse(options, args);

workspacePathAsString = cmd.getOptionValue("workspace");
format = cmd.getOptionValue("format");
outputPath = cmd.getOptionValue("output");
mergePathAsString = cmd.getOptionValue("merge");

} catch (ParseException e) {
log.error(e.getMessage());
Expand All @@ -103,6 +111,7 @@ public void run(String... args) throws Exception {
}

Workspace workspace;
Workspace mergeWorkspace;

log.info("Exporting workspace from " + workspacePathAsString);

Expand All @@ -117,7 +126,7 @@ public void run(String... args) throws Exception {
workspacePath = new File(workspacePathAsString);
workspace = WorkspaceUtils.loadWorkspaceFromJson(workspacePath);
}

} else {
log.info(" - loading workspace from DSL");
StructurizrDslParser structurizrDslParser = new StructurizrDslParser();
Expand All @@ -134,6 +143,20 @@ public void run(String... args) throws Exception {
workspace = structurizrDslParser.getWorkspace();
}

try {
if (mergePathAsString != null) {
if (mergePathAsString.endsWith(".json")) {
mergePath = new File(mergePathAsString);
mergeWorkspace = WorkspaceUtils.loadWorkspaceFromJson(mergePath);
mergeWorkspaceViews(mergeWorkspace, workspace);
} else {
log.error("Merge file must be in JSON format");
}
}
} catch (IllegalArgumentException e) {
log.error("The source file to merge from cannot be found, skipping merge operation");
}

workspaceId = workspace.getId();

if (!JSON_FORMAT.equalsIgnoreCase(format)) {
Expand All @@ -145,7 +168,7 @@ public void run(String... args) throws Exception {
if (outputPath == null) {
outputPath = new File(workspacePath.getCanonicalPath()).getParent();
}

File outputDir = new File(outputPath);
outputDir.mkdirs();

Expand Down Expand Up @@ -261,4 +284,17 @@ private void writeToFile(File file, String content) throws Exception {
writer.close();
}

private void mergeWorkspaceViews(Workspace source, Workspace output) {
output.getViews().getViews().stream().forEach(view -> {
View existingLayout = source.getViews().getViewWithKey(view.getKey());
if (existingLayout!=null) {
((ModelView) view).setMergeFromRemote(true); //required to allow merge to happen
((ModelView) view).disableAutomaticLayout(); //remove auto layout
((ModelView) view).setDimensions(null); //null dimensions to force copy from source
((ModelView) view).setPaperSize(null); //null paper size to force copy from source
}
});
output.getViews().copyLayoutInformationFrom(source.getViews());
}

}
11 changes: 9 additions & 2 deletions src/test/dsl/workspace.dsl
Original file line number Diff line number Diff line change
@@ -1,10 +1,17 @@
workspace {

model {
softwareSystem "Software System" {
ss = softwareSystem "Software System" {
!docs docs
!adrs adrs
}

p = person "Person" {

}

p -> ss "Calls"

}

views {
Expand All @@ -16,4 +23,4 @@ workspace {
theme default
}

}
}
95 changes: 95 additions & 0 deletions src/test/dsl/workspace_layout.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
{
"id" : 0,
"name" : "Name",
"description" : "Description",
"properties" : {
"structurizr.dsl" : "d29ya3NwYWNlIHsKCiAgICBtb2RlbCB7CiAgICAgICAgc3MgPSBzb2Z0d2FyZVN5c3RlbSAiU29mdHdhcmUgU3lzdGVtIiB7CiAgICAgICAgICAgICFkb2NzIGRvY3MKICAgICAgICAgICAgIWFkcnMgYWRycwogICAgICAgIH0KCiAgICAgICAgcCA9IHBlcnNvbiAiUGVyc29uIiB7CgogICAgICAgIH0KCiAgICAgICAgcCAtPiBzcyAiQ2FsbHMiCgogICAgfQoKICAgIHZpZXdzIHsKICAgICAgICBzeXN0ZW1MYW5kc2NhcGUgIlN5c3RlbUxhbmRzY2FwZSIgewogICAgICAgICAgICBpbmNsdWRlICoKICAgICAgICAgICAgYXV0b2xheW91dAogICAgICAgIH0KCiAgICAgICAgdGhlbWUgZGVmYXVsdAogICAgfQoKfQo="
},
"configuration" : { },
"model" : {
"people" : [ {
"id" : "2",
"tags" : "Element,Person",
"properties" : {
"structurizr.dsl.identifier" : "p"
},
"name" : "Person",
"relationships" : [ {
"id" : "3",
"tags" : "Relationship",
"properties" : {
"structurizr.dsl.identifier" : "47a284c7-e195-4287-a7e8-649a9c6c7add"
},
"sourceId" : "2",
"destinationId" : "1",
"description" : "Calls"
} ],
"location" : "Unspecified"
} ],
"softwareSystems" : [ {
"id" : "1",
"tags" : "Element,Software System",
"properties" : {
"structurizr.dsl.identifier" : "ss"
},
"name" : "Software System",
"location" : "Unspecified",
"documentation" : {
"sections" : [ {
"content" : "## Context\n\n...",
"format" : "Markdown",
"filename" : "01-context.md",
"order" : 1,
"title" : ""
} ],
"decisions" : [ {
"content" : "# 1. Record architecture decisions\n\nDate: 2020-06-05\n\n## Status\n\nAccepted\n\n## Context\n\nWe need to record the architectural decisions made on this project.\n\n## Decision\n\nWe will use Architecture Decision Records, as described by Michael Nygard in this article: [http://thinkrelevance.com/blog/2011/11/15/documenting-architecture-decisions](http://thinkrelevance.com/blog/2011/11/15/documenting-architecture-decisions)\n\n## Consequences\n\nSee Michael Nygard's article, linked above.",
"format" : "Markdown",
"id" : "1",
"title" : "Record architecture decisions",
"date" : "2020-06-05T00:00:00Z",
"status" : "Accepted"
} ]
}
} ]
},
"documentation" : { },
"views" : {
"systemLandscapeViews" : [ {
"key" : "SystemLandscape",
"order" : 1,
"paperSize" : "A2_Portrait",
"dimensions" : {
"width" : 3954,
"height" : 5208
},
"automaticLayout" : {
"implementation" : "Graphviz",
"rankDirection" : "TopBottom",
"rankSeparation" : 300,
"nodeSeparation" : 300,
"edgeSeparation" : 0,
"vertices" : false
},
"enterpriseBoundaryVisible" : true,
"elements" : [ {
"id" : "1",
"x" : 250,
"y" : 200
}, {
"id" : "2",
"x" : 100,
"y" : 100
} ],
"relationships" : [ {
"id" : "3"
} ]
} ],
"configuration" : {
"branding" : { },
"styles" : { },
"themes" : [ "https://static.structurizr.com/themes/default/theme.json" ],
"terminology" : { }
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -33,4 +33,21 @@ public void exportWorkspace() throws Exception {
assertTrue(new File(tmpDir, "structurizr-SystemLandscape.puml").exists());
}

}
@Test
public void exportWorkspaceToJSONAndMerge() throws Exception {
File tmpDir = Files.createTempDirectory("structurizr").toFile();

String[] args = {
"export",
"-workspace", "src/test/dsl/workspace.dsl",
"-output", tmpDir.getCanonicalPath(),
"-format", "json",
"-merge", "src/test/dsl/workspace_layout.json"

};
StructurizrCliApplication.main(args);

assertTrue(new File(tmpDir, "workspace.json").exists());
}

}