I’ve been in a meetup recently and it was about architecture validation with the help of our good friend jqAssistant. Although I didn’t learn much new in the first part, the second part was highly interesting:

Combine ADR with the asciidoc processing of jqAssistant. I’ve never thought about it before, but once the speaker presented this idea I was totally into it.


For a starter, we need to add asciidoc support to the ADR tooling, since they normally are written in markdown. There is a pending PR that does exactly that:


Or if you need a complete set along with other nifty things like indexing a database (sqlite3) handling and basic atom/rss support, just use my version of it:


Once we’ve picked our version, we need to set this up accordingly:

adr-tools/adr init -t adoc jqassistant/decisions

adr-tools/adr new "Assertion Library"

jqAssistant 1

Messing with jqAssistant is always funny, when you manage to make your mind about cypher, you are busy with lots of flaky tests and varying output errors, but we’ll come to that later I guess.

I also will not go into detail how to set up jgAssistant or how to create a bootstrap project and focus on the funny parts. If you want to dive head first just checkout my demo project:


Back to our new ADR, let us just fill in a bit of magic:


= 1. Assertion library

| Proposed Date: | 2021-03-15
| Decision Date: | ?
| Proposer:      | Christoph Kappel
| Deciders:      | ?
| Status:        | drafted
| Issues:        | ?
| References:    |
| Priority:      | high

NOTE: *Status types:* drafted | proposed | rejected | accepted | deprecated | superseded +
      *Priority:* low | medium | high

== Context

There are dozen of assertion library available, we want to settle one for
our purpose and rely just on this one.

== Decision

After some consideration we agreed on using https://assertj.github.io/doc/[AssertJ].

== Consequences

.All calls to `assertThat` must be from `AssertJ`!
      (assertType:Type)-[:DECLARES]->(assertMethod) // (1)
      NOT assertType.fqn =~ "org.assertj.core.api.*" // (2)
            AND assertMethod.signature =~ ".*assertThat.*"
      testType.fqn + "#" + testMethod.name as TestMethod, // (3)
      invocation.lineNumber as LineNumber
      TestMethod, LineNumber

include::jQA:Rules[concepts="adr:AssertionLibrary*", constraints="adr:AssertionLibrary*"] // (4)

So this is basically the complete ADR and I assume most of the things beside the weird code block is pretty self explanatory. The code block - glad you’ve asked - is cypher.

It creates a simple query (1) for all methods, that have assertThat in its method signature and then checks, if the full-qualified name of the package is NOT org.assertj.core.api. (2) For every match (3), it returns the name of the method, along with its line number.

When this list is empty the test passes, if not you’ll get a neat nice table below the definition in the output.

NOTE: The part around (4) is required to see the actual results in the rendered document, took me quite a whole to figure this out.

jqAssistant 2

So we have to jump right back to jqAssistant, since we are done with the ADR.

Next best thing to do is to create an index.adoc document for jqAssistant to render:

:description: This is a demo project for the combination of ADR and jqAssistant.
:doctype: book
:toc: left
:toc-title: Table of Contents
:toclevels: 2
:icons: font

[[default]] // (1)
== Architecture decisions, tests and metrics

This document contains example https://jqassistant.org/[jqAssistant] rules
along with simple https://adr.github.io/[Architecture Decision Records].

[role=group,includesConcepts="adr:*",includesConstraints="adr:*"] // (2)
== List of Architecture Decision Records

include::decisions/0001-assertion-library.adoc[leveloffset=2] // (3)

The default group (1) is required, otherwise jqAssistant will not pick up this document and render nothing at all.

The remaining points, namely (2) and (3), include the ADR into our main document.