-
-
Notifications
You must be signed in to change notification settings - Fork 290
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Adds a couple of inspections related to embedded views in documentati…
…on and decisions.
- Loading branch information
1 parent
371d570
commit 757ef70
Showing
6 changed files
with
365 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
83 changes: 83 additions & 0 deletions
83
...rc/main/java/com/structurizr/inspection/documentation/AbstractDocumentableInspection.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,83 @@ | ||
package com.structurizr.inspection.documentation; | ||
|
||
import com.structurizr.Workspace; | ||
import com.structurizr.documentation.*; | ||
import com.structurizr.inspection.Inspection; | ||
import com.structurizr.inspection.Inspector; | ||
import com.structurizr.inspection.Severity; | ||
import com.structurizr.inspection.Violation; | ||
import com.structurizr.model.Element; | ||
|
||
import java.util.LinkedHashSet; | ||
import java.util.Set; | ||
import java.util.regex.Matcher; | ||
import java.util.regex.Pattern; | ||
|
||
public abstract class AbstractDocumentableInspection extends Inspection { | ||
|
||
private static final Pattern MARKDOWN_EMBED = Pattern.compile("!\\[.*?]\\(embed:(.+?)\\)"); | ||
private static final Pattern ASCIIDOC_EMBED = Pattern.compile("image::embed:(.+?)\\[]"); | ||
|
||
public AbstractDocumentableInspection(Inspector inspector) { | ||
super(inspector); | ||
} | ||
|
||
public final Violation run(Documentable documentable) { | ||
Severity severity; | ||
if (documentable instanceof Workspace) { | ||
severity = getInspector().getSeverityStrategy().getSeverity(this, (Workspace)documentable); | ||
} else { | ||
Element element = (Element)documentable; | ||
severity = getInspector().getSeverityStrategy().getSeverity(this, element); | ||
} | ||
Violation violation = inspect(documentable); | ||
|
||
return violation == null ? null : violation.withSeverity(severity); | ||
} | ||
|
||
protected abstract Violation inspect(Documentable documentable); | ||
|
||
protected Set<String> findEmbeddedViewKeys(Documentable documentable) { | ||
Set<String> keys = new LinkedHashSet<>(); | ||
|
||
for (Section section : documentable.getDocumentation().getSections()) { | ||
keys.addAll(findEmbeddedViewKeys(section)); | ||
} | ||
|
||
for (Decision decision : documentable.getDocumentation().getDecisions()) { | ||
keys.addAll(findEmbeddedViewKeys(decision)); | ||
} | ||
|
||
return keys; | ||
} | ||
|
||
private Set<String> findEmbeddedViewKeys(DocumentationContent content) { | ||
Set<String> keys = new LinkedHashSet<>(); | ||
|
||
String[] lines = content.getContent().split("\n"); | ||
for (String line : lines) { | ||
if (content.getFormat() == Format.Markdown) { | ||
// ![](embed:MyDiagramKey) | ||
Matcher matcher = MARKDOWN_EMBED.matcher(line); | ||
if (matcher.matches()) { | ||
String key = matcher.group(1); | ||
keys.add(key); | ||
} | ||
} else if (content.getFormat() == Format.AsciiDoc) { | ||
// image::embed:MyDiagramKey[] | ||
Matcher matcher = ASCIIDOC_EMBED.matcher(line); | ||
if (matcher.matches()) { | ||
String key = matcher.group(1); | ||
keys.add(key); | ||
} | ||
} | ||
} | ||
|
||
return keys; | ||
} | ||
|
||
protected String terminologyFor(Element element) { | ||
return getWorkspace().getViews().getConfiguration().getTerminology().findTerminology(element).toLowerCase(); | ||
} | ||
|
||
} |
52 changes: 52 additions & 0 deletions
52
...src/main/java/com/structurizr/inspection/documentation/EmbeddedViewMissingInspection.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,52 @@ | ||
package com.structurizr.inspection.documentation; | ||
|
||
import com.structurizr.Workspace; | ||
import com.structurizr.documentation.Documentable; | ||
import com.structurizr.documentation.Format; | ||
import com.structurizr.documentation.Section; | ||
import com.structurizr.inspection.Inspector; | ||
import com.structurizr.inspection.Violation; | ||
import com.structurizr.model.Element; | ||
import com.structurizr.view.View; | ||
|
||
import java.util.HashSet; | ||
import java.util.LinkedHashSet; | ||
import java.util.Set; | ||
import java.util.regex.Matcher; | ||
import java.util.regex.Pattern; | ||
|
||
public class EmbeddedViewMissingInspection extends AbstractDocumentableInspection { | ||
|
||
public EmbeddedViewMissingInspection(Inspector inspector) { | ||
super(inspector); | ||
} | ||
|
||
protected Violation inspect(Documentable documentable) { | ||
Set<String> keys = findEmbeddedViewKeys(documentable); | ||
Set<String> missingViews = new LinkedHashSet<>(); | ||
|
||
for (String key : keys) { | ||
View view = getWorkspace().getViews().getViewWithKey(key); | ||
if (view == null) { | ||
missingViews.add(key); | ||
} | ||
} | ||
|
||
if (!missingViews.isEmpty()) { | ||
if (documentable instanceof Workspace) { | ||
return violation("The following views are embedded into documentation for the workspace but do not exist in the workspace: " + String.join(", ", missingViews)); | ||
} else if (documentable instanceof Element) { | ||
Element element = (Element)documentable; | ||
return violation("The following views are embedded into documentation for the " + terminologyFor(element).toLowerCase() + " named \"" + element.getName() + "\" but do not exist in the workspace: " + String.join(", ", missingViews)); | ||
} | ||
} | ||
|
||
return noViolation(); | ||
} | ||
|
||
@Override | ||
protected String getType() { | ||
return "documentation.embeddedView"; | ||
} | ||
|
||
} |
49 changes: 49 additions & 0 deletions
49
...java/com/structurizr/inspection/documentation/EmbeddedViewWithGeneratedKeyInspection.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,49 @@ | ||
package com.structurizr.inspection.documentation; | ||
|
||
import com.structurizr.Workspace; | ||
import com.structurizr.documentation.Documentable; | ||
import com.structurizr.inspection.Inspector; | ||
import com.structurizr.inspection.Violation; | ||
import com.structurizr.model.Element; | ||
import com.structurizr.view.View; | ||
|
||
import java.util.LinkedHashSet; | ||
import java.util.Set; | ||
import java.util.regex.Matcher; | ||
import java.util.regex.Pattern; | ||
|
||
public class EmbeddedViewWithGeneratedKeyInspection extends AbstractDocumentableInspection { | ||
|
||
public EmbeddedViewWithGeneratedKeyInspection(Inspector inspector) { | ||
super(inspector); | ||
} | ||
|
||
protected Violation inspect(Documentable documentable) { | ||
Set<String> keys = findEmbeddedViewKeys(documentable); | ||
Set<String> viewsWithGeneratedKeys = new LinkedHashSet<>(); | ||
|
||
for (String key : keys) { | ||
View view = getWorkspace().getViews().getViewWithKey(key); | ||
if (view != null && view.isGeneratedKey()) { | ||
viewsWithGeneratedKeys.add(key); | ||
} | ||
} | ||
|
||
if (!viewsWithGeneratedKeys.isEmpty()) { | ||
if (documentable instanceof Workspace) { | ||
return violation("The following views are embedded into documentation for the workspace via an automatically generated view key: " + String.join(", ", viewsWithGeneratedKeys)); | ||
} else if (documentable instanceof Element) { | ||
Element element = (Element)documentable; | ||
return violation("The following views are embedded into documentation for the " + terminologyFor(element).toLowerCase() + " named \"" + element.getName() + "\" via an automatically generated view key: " + String.join(", ", viewsWithGeneratedKeys)); | ||
} | ||
} | ||
|
||
return noViolation(); | ||
} | ||
|
||
@Override | ||
protected String getType() { | ||
return "documentation.embeddedView"; | ||
} | ||
|
||
} |
91 changes: 91 additions & 0 deletions
91
...est/java/com/structurizr/inspection/documentation/EmbeddedViewMissingInspectionTests.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,91 @@ | ||
package com.structurizr.inspection.documentation; | ||
|
||
import com.structurizr.Workspace; | ||
import com.structurizr.documentation.Decision; | ||
import com.structurizr.documentation.Format; | ||
import com.structurizr.documentation.Section; | ||
import com.structurizr.inspection.DefaultInspector; | ||
import com.structurizr.inspection.Severity; | ||
import com.structurizr.inspection.Violation; | ||
import com.structurizr.inspection.model.SoftwareSystemDocumentationInspection; | ||
import com.structurizr.model.Container; | ||
import com.structurizr.model.SoftwareSystem; | ||
import org.junit.jupiter.api.Assertions; | ||
import org.junit.jupiter.api.Test; | ||
|
||
import static org.junit.jupiter.api.Assertions.assertEquals; | ||
import static org.junit.jupiter.api.Assertions.assertNull; | ||
|
||
public class EmbeddedViewMissingInspectionTests { | ||
|
||
@Test | ||
public void run_WithMissingView() { | ||
Workspace workspace = new Workspace("Name", "Description"); | ||
SoftwareSystem softwareSystem = workspace.getModel().addSoftwareSystem("Software System"); | ||
|
||
Section section = new Section(); | ||
section.setFormat(Format.Markdown); | ||
section.setContent(""" | ||
## Context | ||
![](embed:SystemContext) | ||
"""); | ||
softwareSystem.getDocumentation().addSection(section); | ||
|
||
Decision decision = new Decision("1"); | ||
decision.setTitle("Decision 1"); | ||
decision.setStatus("Accepted"); | ||
decision.setFormat(Format.AsciiDoc); | ||
decision.setContent(""" | ||
## Containers | ||
image::embed:Containers[] | ||
"""); | ||
softwareSystem.getDocumentation().addDecision(decision); | ||
|
||
Violation violation = new EmbeddedViewMissingInspection(new DefaultInspector(workspace)).run(softwareSystem); | ||
Assertions.assertEquals(Severity.ERROR, violation.getSeverity()); | ||
assertEquals("documentation.embeddedView", violation.getType()); | ||
assertEquals("The following views are embedded into documentation for the software system named \"Software System\" but do not exist in the workspace: SystemContext, Containers", violation.getMessage()); | ||
|
||
workspace.getViews().createSystemContextView(softwareSystem, "SystemContext", "Description"); | ||
|
||
violation = new EmbeddedViewMissingInspection(new DefaultInspector(workspace)).run(softwareSystem); | ||
Assertions.assertEquals(Severity.ERROR, violation.getSeverity()); | ||
assertEquals("documentation.embeddedView", violation.getType()); | ||
assertEquals("The following views are embedded into documentation for the software system named \"Software System\" but do not exist in the workspace: Containers", violation.getMessage()); | ||
} | ||
|
||
@Test | ||
public void run_WithoutMissingView() { | ||
Workspace workspace = new Workspace("Name", "Description"); | ||
SoftwareSystem softwareSystem = workspace.getModel().addSoftwareSystem("Software System"); | ||
|
||
Section section = new Section(); | ||
section.setFormat(Format.Markdown); | ||
section.setContent(""" | ||
## Context | ||
![](embed:SystemContext) | ||
"""); | ||
softwareSystem.getDocumentation().addSection(section); | ||
|
||
Decision decision = new Decision("1"); | ||
decision.setTitle("Decision 1"); | ||
decision.setStatus("Accepted"); | ||
decision.setFormat(Format.AsciiDoc); | ||
decision.setContent(""" | ||
## Containers | ||
image::embed:Containers[] | ||
"""); | ||
softwareSystem.getDocumentation().addDecision(decision); | ||
|
||
workspace.getViews().createSystemContextView(softwareSystem, "SystemContext", "Description"); | ||
workspace.getViews().createContainerView(softwareSystem, "Containers", "Description"); | ||
|
||
Violation violation = new EmbeddedViewMissingInspection(new DefaultInspector(workspace)).run(softwareSystem); | ||
assertNull(violation); | ||
} | ||
|
||
} |
Oops, something went wrong.