Skip to content

Commit

Permalink
Merge pull request #13 from avisi-cloud/add-workspace-level-adrs
Browse files Browse the repository at this point in the history
Support workspace-level ADR's
  • Loading branch information
dirkgroot authored Jun 27, 2022
2 parents 5cff091 + 1933d20 commit cf0f28a
Show file tree
Hide file tree
Showing 17 changed files with 172 additions and 72 deletions.
1 change: 1 addition & 0 deletions docs/example/.adr-dir
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
workspace-adrs
19 changes: 19 additions & 0 deletions docs/example/workspace-adrs/0001-record-architecture-decisions.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# 1. Record architecture decisions

Date: 2022-06-27

## Status

Accepted

## Context

We need to record the architectural decisions made on this project.

## Decision

We will use Architecture Decision Records, as [described by Michael Nygard](http://thinkrelevance.com/blog/2011/11/15/documenting-architecture-decisions).

## Consequences

See Michael Nygard's article, linked above. For a lightweight ADR toolset, see Nat Pryce's [adr-tools](https://github.com/npryce/adr-tools).
1 change: 1 addition & 0 deletions docs/example/workspace.dsl
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
*/
workspace "Big Bank plc" "This is an example workspace to illustrate the key features of Structurizr, via the DSL, based around a fictional online banking system." {
!docs workspace-docs
!adrs workspace-adrs

model {
customer = person "Personal Banking Customer" "A customer of the bank, with personal bank accounts." "Customer"
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package nl.avisi.structurizr.site.generatr.site

import java.time.ZoneId
import java.util.*

fun formatDate(date: Date): String {
val localDate = date.toInstant().atZone(ZoneId.systemDefault()).toLocalDate()
return String.format("%02d-%02d-%04d", localDate.dayOfMonth, localDate.monthValue, localDate.year)
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,7 @@ import kotlinx.html.stream.appendHTML
import nl.avisi.structurizr.site.generatr.homeSection
import nl.avisi.structurizr.site.generatr.internalSoftwareSystems
import nl.avisi.structurizr.site.generatr.site.context.*
import nl.avisi.structurizr.site.generatr.site.context.SoftwareSystemsOverviewPageContext
import nl.avisi.structurizr.site.generatr.site.pages.documentationSectionPage
import nl.avisi.structurizr.site.generatr.site.pages.indexPage
import nl.avisi.structurizr.site.generatr.site.pages.softwareSystemsOverviewPage
import nl.avisi.structurizr.site.generatr.site.pages.*
import nl.avisi.structurizr.site.generatr.site.pages.softwaresystem.softwareSystemDecisionPage
import nl.avisi.structurizr.site.generatr.site.pages.softwaresystem.softwareSystemPage
import java.io.File
Expand Down Expand Up @@ -80,6 +77,10 @@ private fun generateHtmlFiles(context: GeneratorContext, exportDir: File) {
.filter { it != context.workspace.documentation.homeSection }
.forEach { yield(DocumentationSectionPageContext(context, it)) }
yield(HomePageContext(context, context.workspace.documentation.homeSection))
yield(WorkspaceDecisionsPageContext(context))
context.workspace.documentation.decisions.forEach { decision ->
yield(WorkspaceDecisionPageContext(context, decision))
}
yield(SoftwareSystemsOverviewPageContext(context))
}

Expand All @@ -100,6 +101,8 @@ fun writeHtmlFile(exportDir: File, context: AbstractPageContext) {
is AbstractSoftwareSystemPageContext -> softwareSystemPage(context)
is DocumentationSectionPageContext -> documentationSectionPage(context)
is SoftwareSystemsOverviewPageContext -> softwareSystemsOverviewPage(context)
is WorkspaceDecisionPageContext -> workspaceDecisionPage(context)
is WorkspaceDecisionsPageContext -> workspaceDecisionsPage(context)
}
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
package nl.avisi.structurizr.site.generatr.site.components

import com.structurizr.documentation.Decision
import kotlinx.html.*
import nl.avisi.structurizr.site.generatr.site.context.AbstractPageContext
import nl.avisi.structurizr.site.generatr.site.formatDate

fun DIV.decisionsTable(
context: AbstractPageContext,
decisions: Collection<Decision>,
createContext: (Decision) -> AbstractPageContext
) {
table(classes = "table") {
thead {
tr {
th { +"ID" }
th { +"Datum" }
th { +"Status" }
th { +"Title" }
}
}
tbody {
decisions.sortedBy { it.id.toInt() }.forEach {
tr {
th { +it.id }
td { +formatDate(it.date) }
td { +it.status.toString() }
td {
a(href = createContext(it).urlRelativeTo(context)) {
+it.title
}
}
}
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,10 @@ private fun ASIDE.generalSection(context: AbstractPageContext) {
).urlRelativeTo(context),
classes = if (context is HomePageContext) "is-active" else ""
) { +"Home" }
a(
href = WorkspaceDecisionsPageContext(context.generatorContext).urlRelativeTo(context),
classes = if (context is WorkspaceDecisionsContext) "is-active" else ""
) { +"Decisions" }
a(
href = SoftwareSystemsOverviewPageContext(context.generatorContext).urlRelativeTo(context),
classes = if (context is SoftwareSystemsOverviewPageContext) "is-active" else ""
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,16 +42,7 @@ private class CustomLinkResolver(private val pageContext: AbstractPageContext) :
.withStatus(LinkStatus.VALID)
.withUrl(makeUrlRelative("${pageContext.urlPrefix}/svg/${link.url.substring(6)}.svg", pageContext.url))
}
if (link.url.startsWith("http"))
return link
return link
.withStatus(LinkStatus.VALID)
.withUrl(
makeUrlRelative(
"${pageContext.urlPrefix}/${link.url}".replace("/{2,}".toRegex(), "/"),
pageContext.url
)
)
}

class Factory(private val pageContext: AbstractPageContext) : LinkResolverFactory {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package nl.avisi.structurizr.site.generatr.site.context

import com.structurizr.documentation.Decision

class WorkspaceDecisionPageContext(
generatorContext: GeneratorContext,
val decision: Decision
) :
AbstractPageContext(
generatorContext,
decision.title,
"decisions/${decision.id}/index.html"
),
WorkspaceDecisionsContext
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
package nl.avisi.structurizr.site.generatr.site.context

interface WorkspaceDecisionsContext
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
package nl.avisi.structurizr.site.generatr.site.context

class WorkspaceDecisionsPageContext(generatorContext: GeneratorContext) :
AbstractPageContext(generatorContext, "Decisions", "decisions/index.html"), WorkspaceDecisionsContext
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package nl.avisi.structurizr.site.generatr.site.pages

import kotlinx.html.HTML
import nl.avisi.structurizr.site.generatr.site.components.contentDiv
import nl.avisi.structurizr.site.generatr.site.components.page
import nl.avisi.structurizr.site.generatr.site.components.renderedMarkdown
import nl.avisi.structurizr.site.generatr.site.context.WorkspaceDecisionPageContext

fun HTML.workspaceDecisionPage(context: WorkspaceDecisionPageContext) {
page(context) {
contentDiv {
renderedMarkdown(context, context.decision.content)
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package nl.avisi.structurizr.site.generatr.site.pages

import kotlinx.html.HTML
import kotlinx.html.h2
import nl.avisi.structurizr.site.generatr.site.components.contentDiv
import nl.avisi.structurizr.site.generatr.site.components.decisionsTable
import nl.avisi.structurizr.site.generatr.site.components.page
import nl.avisi.structurizr.site.generatr.site.context.WorkspaceDecisionPageContext
import nl.avisi.structurizr.site.generatr.site.context.WorkspaceDecisionsPageContext

fun HTML.workspaceDecisionsPage(context: WorkspaceDecisionsPageContext) {
page(context) {
contentDiv {
h2 { +"Architecture decision records" }
decisionsTable(context, context.workspace.documentation.decisions) { decision ->
WorkspaceDecisionPageContext(context.generatorContext, decision)
}
}
}
}

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package nl.avisi.structurizr.site.generatr.site.pages.softwaresystem

import com.structurizr.documentation.Decision
import kotlinx.html.DIV
import kotlinx.html.h1
import nl.avisi.structurizr.site.generatr.site.components.contentDiv
import nl.avisi.structurizr.site.generatr.site.components.decisionsTable
import nl.avisi.structurizr.site.generatr.site.context.AbstractSoftwareSystemPageContext
import nl.avisi.structurizr.site.generatr.site.context.SoftwareSystemDecisionPageContext

fun DIV.decisionListFragment(context: AbstractSoftwareSystemPageContext) {
contentDiv {
h1 { +"Architecture decision records" }
decisionsTable(context, context.adrs) { decision: Decision ->
SoftwareSystemDecisionPageContext(
context.generatorContext,
context.softwareSystem,
decision
)
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package nl.avisi.structurizr.site.generatr.site.pages.softwaresystem

import kotlinx.html.HTML
import nl.avisi.structurizr.site.generatr.site.components.contentDiv
import nl.avisi.structurizr.site.generatr.site.components.renderedMarkdown
import nl.avisi.structurizr.site.generatr.site.context.SoftwareSystemDecisionPageContext

fun HTML.softwareSystemDecisionPage(context: SoftwareSystemDecisionPageContext) {
softwareSystemPage(context) {
contentDiv {
renderedMarkdown(context, context.decision.content)
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,21 +12,13 @@ fun HTML.softwareSystemPage(context: AbstractSoftwareSystemPageContext) {
is SoftwareSystemContainerPageContext -> containerFragment(context)
is SoftwareSystemComponentPageContext -> componentFragment(context)
is SoftwareSystemDeploymentPageContext -> deploymentFragment(context)
is SoftwareSystemDecisionsPageContext -> adrFragment(context)
is SoftwareSystemDecisionsPageContext -> decisionListFragment(context)
is SoftwareSystemDependenciesPageContext -> dependenciesFragment(context)
}
}
}

fun HTML.softwareSystemDecisionPage(context: SoftwareSystemDecisionPageContext) {
softwareSystemPage(context) {
contentDiv {
renderedMarkdown(context, context.decision.content)
}
}
}

private fun HTML.softwareSystemPage(context: AbstractSoftwareSystemPageContext, block: DIV.() -> Unit) {
fun HTML.softwareSystemPage(context: AbstractSoftwareSystemPageContext, block: DIV.() -> Unit) {
page(context) {
h1(classes = "title mt-3") { +context.softwareSystem.name }
h2(classes = "subtitle") { +context.softwareSystem.description }
Expand Down

0 comments on commit cf0f28a

Please sign in to comment.