Inkan
↑↓ move↵ open
GitHub

CLI · ADR

0006: Import from log4brains, MADR and adr-tools

Date

Context#

Most teams that try Inkan already have decisions: a docs/adr/ folder made with adr-tools, a log4brains site, or MADR files written by hand. Those formats keep metadata in the body, as a ## Status section, a Date: line or a list of * Status: accepted items under the title. Inkan keeps metadata in front matter and takes the type and number from the path. Converting a few dozen files by hand is boring and error-prone, and it is the first thing a new user has to do.

Decision#

inkan import <dir|file...> --project <name> reads files in the three common dialects and writes them as <contentDir>/<project>/<type>/NNNN-slug.md with front matter:

  • the first # heading becomes title; a leading 1. becomes the record number,
  • status, date, deciders and tags move into front matter, with status spellings mapped to your configured statuses,
  • a Superseded by [..](..) status and adr-tools Supersedes [..](..) lines become supersededBy and supersedes when they point at files of the same import,
  • links between imported files are rewritten to the new file names,
  • original numbers are kept when they are free; existing files are never overwritten.

The command converts the metadata and leaves the body as it was, so the imported text reads exactly like the original.

How to use it#

Run it#

Terminal window
npx inkan import ../old-repo/docs/adr --project platform --dry-run
npx inkan import ../old-repo/docs/adr --project platform
Wrote decisions/platform/adr/0001-record-architecture-decisions.md <- ../old-repo/docs/adr/0001-record-architecture-decisions.md (adr-tools, accepted)
Wrote decisions/platform/adr/0002-use-postgres.md <- ../old-repo/docs/adr/0002-use-postgres.md (adr-tools, superseded)
Wrote decisions/platform/adr/0003-use-cockroachdb.md <- ../old-repo/docs/adr/20200927-use-cockroachdb.md (madr, accepted)
Imported 3 records into decisions/platform/adr.

Inputs are folders (walked recursively, _-prefixed files and folders skipped) or single .md and .mdx files, in any mix. Files named README, index or template (any case) are skipped. When the project folder has no _project.yml, one is created with name: <project> for you to fill in.

OptionDefaultWhat it does
--project <name>requiredProject folder to write into: letters, digits, - and _. Must not be a project listed in sources.
--type <type>adrType folder inside the project. Must be a key of docTypes.
--format auto|log4brains|madr|adr-toolsautoDialect of every input file. log4brains and madr are the same parser; auto detects per file.
--dry-runoffPrints what would be written and writes nothing, not even _project.yml.
--root <dir>current folderFolder with inkan.config.*.

Dialect detection#

With --format auto, a file is adr-tools when its body has a ## Status heading and a Date: ... line before the first ## heading. Everything else is parsed as MADR, which covers log4brains and MADR 2.x header lists as well as MADR 3 and 4 front matter.

SourceWhere the metadata isWhat is read
adr-toolsDate: line under the title; ## Status sectionDate becomes date. In ## Status, the first plain line is the status, Supersedes [..](..) lines fill supersedes, lines starting with Amended, Extended, Clarified or Related fill related. The section is removed from the body.
log4brains, MADR 2.x* Status:, * Date:, * Deciders: (or Decision makers:), * Tags:, * Consulted:, * Informed: list items under the titleEach becomes the front matter field of the same name; deciders and tags are split on commas, a leading @ is dropped. Other list items stay in the body.
MADR 3 and 4YAML front mattertitle, status, date, deciders / decision-makers, tags, consulted, informed.

In every dialect the first # heading is the title (falling back to a front matter title) and is removed from the body; a file with neither is skipped with no heading. A status that reads Superseded by [title](file.md) sets supersededBy from the link and the status superseded.

Status mapping#

The status is reduced to its first word, lowercased, and matched against your statuses:

  1. an exact key (accepted),
  2. a synonym, when the target is configured: approved to accepted, pending to proposed, wip to draft, declined to rejected, obsolete to deprecated, done to implemented,
  3. the closest key by edit distance (acepted to accepted).

A status that maps to nothing is left out, and a warning names the file: status "Parked" is not configured; left out. Add the status to statuses first if you want to keep it; see Configurable status lifecycle.

Numbers, names and dates#

In the sourceResult
0007-use-kafka.mdnumber 7, slug use-kafka
# 7. Use Kafkanumber 7 (the heading wins over the file name), title Use Kafka
20200927-use-kafka.md (log4brains)date: 2020-09-27 unless the file states a date, slug use-kafka
use-kafka.md, no number anywherethe next free number in the target folder

Original numbers are kept when no record in the target folder uses them. Two sources claiming the same number, or a number already taken, fall back to the next free number in input order. The slug comes from the file name, or from the title when the name has none. A slug that already exists in the target folder means the file was imported before and is skipped with already imported as <file>; a target file that exists is never overwritten.

Relative Markdown links from one imported file to another are rewritten to the new name, keeping any #anchor: [2. Use Postgres](0002-use-postgres.md) becomes [2. Use Postgres](./0002-use-postgres.md) under its new number. supersedes, supersededBy and related get the full id of the target record (platform/adr/0002-use-postgres). A link whose target is not part of the same import is left as text and, for the three link fields, dropped with a warning: supersedes link "0003-x.md" points outside this import; left out. Import a whole folder at once so the links resolve.

Check the result#

Terminal window
npx inkan check
npx inkan dev

check reports one-sided supersede links, unknown authors and missing owners in the new _project.yml; see Check records in CI. Deciders are imported as written (Ann, Bob), so either add them to _authors.yml under those handles or edit them to existing handles.

Tip

Run the import with --dry-run first. It prints every target file, every warning and the skip reasons, and leaves the content folder untouched.

Consequences#

  • A folder of adr-tools, log4brains or MADR files becomes a working Inkan project in one command, with the body text unchanged.
  • Only metadata the three formats agree on is mapped. consulted and informed are written to front matter but the site does not display them; MADR “Decision Outcome” or “Considered Options” sections stay as ordinary body text.
  • Numbers are preserved per type folder. Importing two sources into the same project renumbers the second one wherever numbers collide, and links are rewritten accordingly only within one run.
  • Links to records outside the import are not resolved. Import related folders together, or fix the supersedes fields afterwards with inkan supersede.
  • The command never overwrites or deletes, so re-running it is safe but does not update records that changed in the source.

History 1

  1. ImplementedInkan maintainers9e5e535 commit diff