Documentation With Any Editor

Christoph Stoettner

Christoph Stoettner

  • Application Servers

    • Installation, Configuration

    • Performance Optimization, Stresstesting

  • Started with Linux / OSS around 1994/1995

    • Linux Kernel < 1.0

    • Slackware

  • VIM lover

    • maybe too stupid for Emacs

I’m mainly Administrator using Developer tools

My history of documentation

  • Content of most of my documentations

    • Config options (XML, GUI)

    • Screenshots (GUI)

    • Parts of Property Files

  • Used tools

    • MS Excel / Libreoffice (with Dropbox)

    • MS Word / Libreoffice with Sharepoint or Mail

    • Several Wiki engines, Evernote

    • LaTex and Docbook

My needs

  • Searchable documentation

  • Editing on mobile, tablet, notebook, customer computer, server (ssh)

  • Output formats depend on customer and project

  • Offline support

  • Version Control

  • Include config settings of *.xml, *.properties

No manual task to update output format

Why did I switch the tools?

  • Evernote

    • Linux client long time a problem

    • New license limits device count

    • No markdown support

  • Office

    • Compatibility

    • Edit on different devices, versions

    • Sometimes switching printer is enough to flip images around

  • Copy&Paste of screenshots and config file settings

Why not using a wiki?

  • Edit from mobile often a pain

  • Documenting the Wiki itself?

    • Not accessible when down

  • Syntax different from one wiki to another

  • Customer / PM often needs something printed / printer friendly

  • AND manual copy&paste

Markdown and rst

  • I started writing in Markdown

  • Some software supports markdown directly

  • Cool WYSIWIG editors

  • Great for typing notes (Still using it on mobile)

  • But a little bit too simple

    • including source files missing

Asciidoc / Asciidoctor

Doctypes

:doctype: article|book|manpage|inline
  • Article (article) default

    • One level 0 heading

  • Book (book)

    • Additional top-level title as part titles

  • Man page (manpage)

    • roff or HTML-formatted man page

  • Inline (inline)

    • Use within source-code, e.g. javadoc

Syntax - Headings

 :numbered: (1)

 == H2
 === H3
 ==== H4

 :!numbered: (2)

 == H2
 === H3
 ==== H4
1Headings numbered
2Headings without numbers
headings
  • H1 only appears once in Asciidoctor article

  • There can be multiple toplevel headings in :doctype: book

  • numbered can be set in document header for all headings

Headings of blocks and images

  • Can be used with images and all kind of blocks, no TOC entry

.Heading (1)
[source]
----
ls -al
----

.Image (2)
image::test.png[]
1Heading above Code block
2Image heading
source heading
pngtest

Syntax - Lists

=== Bullet Points

* Bullet Points
** Sub Bullet Point

=== Numbered Lists
. Numbered List
.. Sub 1
.. Sub 2
. Numbered 2

=== Definition Lists

CPU:: The brain of the computer.
Hard drive:: Permanent storage for operating system...
listings

Images

image::sunset.jpg[]
image::sunset.jpg[role=right] (1)
image:sunset.jpg[]            (2)
1You can add roles to all elements and use CSS for formatting
2One colon after image → inline image, double colon → figure
double :
<div class="imageblock" style=""><img src="images/sunset.jpg" alt="sunset"></div>
<div class="imageblock right" style=""><img src="images/sunset.jpg" alt="sunset"></div>
single :
<div class="paragraph"><p><span class="image"><img src="images/sunset.jpg" alt="sunset"></span></p></div>

Use Inline Icons

  • You can add any Font Awesome Icon

  • Enable in document header

:icons: font
Some Examples
icon:twitter[] Twitter https://twitter.com[@stoeps]
icon:linux[] Linux Icon
icon:windows[] Windows Icon
icons

Admonition Blocks

  • Admonition blocks (Warning, Caution, Important, Note, Tip)

  • Font-Awesome Icons with :icons: font

WARNING: This is a warning
This is a warning
CAUTION: This is a caution
This is a caution
IMPORTANT: This is important
This is important

Admonition Blocks in Html and PDF

NOTE: A note

TIP: Here is a tip

IMPORTANT: That's important

WARNING: Warning message

CAUTION: Caution, be careful
admonition html
admonition pdf

Menus, Keys and Buttons

:experimental: (1)
1Following features need experimental set
Menu, Button, Keys
.Copy Text
menu:Edit[Copy Special > Text]

.Button
Press kbd:[OK]

.Keyboard
kbd:[Ctrl+C] to stop this.
experimental
experimental pdf

Sourcecode

  • Adding [source]

 .A Python function
 [source,python]
 ----
 def function():
    var x = 10
    return x
 ----
src
src pdf
  • Syntax Highlighting with Pygments, Highlightjs or Rouge

:source-highlighter: pygments|highlightjs|rouge

Including Files

  • Split longer documents and include Asciidoc Source

  • Include any type of files in [source]

  • Powerful

  • Include complete files

  • Include only parts

include::path/filename[] (1)
include::path/filename[lines=10..15] (2)
include::path/filename[tags=mytag] (3)
1Include entire file
2Include lines 10-15
3Include area between mytag tags tag::mytag, end::mytag

Example Include

...
<title>example</title>
<!-- tag::stoeps[] -->
<!-- even comments -->
</head><body>
<h1>Test</h1>
<!-- end::stoeps[] -->
</body>
...
Include in our asciidoc source
 [source, indent=0]
 ----
 include::test.html[tags=stoeps]
 ----
Included source
<!-- even comments -->
</head>
<body>
<h1>Test</h1>

Callouts in Sources

 [source]
 ----
 def function:
     x = 'secret' # <1>
     print(secret)
     return 0
 ----
 <1> Hardcoded variable
def function:
    x = 'secret' (1)
    print(secret)
    return 0
1Hardcoded variable
callout html
callout pdf

Variables

Definition
:variable: content  (1)
:OS: Linux          (2)
:SLASH: /           (3)
1Generic definition
2Variable OS set to Linux
3Variable SLASH set to /
Windows Version
:OS: Windows Server 2016 Datacenter Edition
:SLASH: \
:VERSION: 0.8
Linux Version
:OS: Linux
:SLASH: /
:VERSION: 8.5.5.4

Add Variables to extra file

  • Include into main document (main.adoc)

  • Use generic variable file for example to store OS differences

  • Add additional one for project specific paths, hostnames

.
├── _attributes.asciidoc
├── images
├── include
├── main.adoc (1)
├── more.asciidoc
├── _variables-linux.asciidoc (2)
├── _variables_project.asciidoc (4)
└── _variables-win.asciidoc (3)
1Main document
2Variables for Linux OS installations
3Variables for Windows installations
4Project specific variables

Conditional Directives

  • Within main document show different informations based on variables

  :OS: Linux                      (1)
  ifeval::["{OS}" == "Linux"]     (2)
  icon:linux[] rocks!
  endif::[]

  :OS: Windows                    (3)
  ifeval::["{OS}" == "Windows"]   (4)
  icon:windows[] really?
  endif::[]
  :OS: Linux
1Set OS = Linux
2If OS = Linux
3Set OS = Windows
4If OS = Windows
conditional html
conditional pdf

Including Diagrams

Diagram - ditaa

[ditaa]
....
               +-------------+
               | Asciidoctor |-------+
               |   diagram   |       |
               +-------------+       | PNG out
                   ^                 |
                   | ditaa in        |
                   |                 v
 +--------+   +--------+----+    /---------------\
 |c9CF    | --+ Asciidoctor +--> |c9CC           |
 |Document|   +-------------+    |   Beautiful   |
 |     {d}|   |   !magic!   |    |    Output     |
 +---+----+   +-------------+    \---------------/
....
diag 3ccc112b784244f9886daba5806a9372

Plantuml

 [plantuml]
 ....
 title Network Plan
 actor user [
   User
   ]
 actor admin [
   Administrator
   ]
 node http [
   HTTP Server
   connect.example.com
   ]
 node dmgr [
   WebSphere Deployment Manager
   dmgr.example.com
   ]
 database db2 [
   DB2 Database Server
   db2.example.com
   ]

 user -down-> http:443/tcp
 admin -right-> dmgr:9043/tcp
 admin -down-> db2:50000/tcp
 dmgr -up-> http
 dmgr -down-> db2

 center footer Connections 6.0 Deployment
 ....
diag 1da8c2c68a4ba5bcabe2a55f997fd81b

Plantuml Simple Flowdiagram

[plantuml]
....
start

if (Graphviz installed?) then (yes)
  :process all\ndiagrams;
else (no)
  :process only
  __sequence__ and __activity__ diagrams;
endif

stop
....
diag 0750c6cde092e6f522d16a079c7d071f

Tables

.Hostnames
[%header, cols=3]
|===
|Hostname
|IP
|Function

|www.example.com
|192.168.1.100
|Webserver

|dmgr.example.com
|192.168.2.100
|Application Server

|db.example.com
|192.168.2.101
|Database Server
tables html
tables pdf

Putting everything together

  • Let’s have a look at a simple document with the main parts

  • Automate with Gitlab and CI/CD

    • It’s also possible with Travis CI or Jenkins

    • Just to have a working example

  • Asciidoctor gradle

  • Git (with GitLab)

  • Gitlab CI/CD functionality

  • https://gitlab.com/stoeps/gpn19-documentation

Main document (main.adoc) - header

 = Example Project Documentation (1)
 :author: Christoph Stoettner
 :email: christoph.stoettner@stoeps.de
 :revnumber: 1.0
 :revdate: 2018-08-24
 :revremark: Froscon 2018
 :encoding: utf-8
 :lang: en (2)
 :experimental: (3)
 :title-logo-image: image::logo.png[] (4)
 :toc: (5)
 :imagesdir: images (6)
 :doctype: article
 :icons: font (7)
 :source-highlighter: rouge (8)
 :quick-uri: https://www.stoeps.de
 :numbered: (9)
 include::_variables-linux.asciidoc[]
 include::_variables-project.asciidoc[]
 include::_attributes.asciidoc[] (10)
1Document title
2Language
3Enable experimental features
4Title logo (for pdf title page)
5Create table of contents
6Default images directory
7Use Font Awesome Icons
8Use rouge for Syntax Highlighting
9Headings numbered
10Translation file for built-in labels, so the labels for language used in (2) will be inserted

Attribute (translation of built-in labels)

Example for german labels
 // German translation, courtesy of Florian Wilhelm
 ifeval::["{lang}" == "de"]
 :appendix-caption: Anhang
 :caution-caption: Achtung
 :chapter-label: Kapitel
 :example-caption: Beispiel
 :figure-caption: Abbildung
 :important-caption: Wichtig
 :last-update-label: Zuletzt aktualisiert
 //:listing-caption: Listing
 :manname-title: BEZEICHNUNG
 :note-caption: Anmerkung
 //:preface-title: Vorwort
 :table-caption: Tabelle
 :tip-caption: Hinweis
 :toc-title: Inhalt
 :untitled-label: Ohne Titel
 :version-label: Version
 :warning-caption: Warnung
 endif::[]

Preface

  • First paragraph after header section

include::_attributes.asciidoc[]

Get tough with it, get strong.
This is the way you take out your flustrations.
Go out on a limb - that's where the fruit is.
If we're gonna walk though the woods, we need a little path.
Trees live in your fan brush, but you have to scare them out.

== Networkplan
It’s Asciidoc best practise to write each sentence into one line
  • Paragraph until first blank line

  • In chapter Networkplan I include a plantuml file

Conditions to show updated informations

 === Software Updates

 Here we check the `VERSION` from our variables doc.
 When we update the main document, it can happen that we adjust the version numbers,
 then new generated documents show this warning.

 ifeval::["{VERSION}" >= "8.5.5.7"]
 INFO: No updates needed!
 endif::[]

 ifeval::["{VERSION}" < "8.5.5.6"]
 WARNING: Update needed!
 endif::[]
conditions

Different Operating Systems

  • Documention is splitted into generic parts

  • Differences

    • Slash or Backslash

    • .bat or .sh

    • Paths

  • Small differences I handle with
    ifeval::["{variable}" == "OS Type"]

  • Paths and hostnames are stored in _variables-xxx.asciidoc

  • So moving to a new version only needs adjustments in main.adoc

Including Configuration Files

  • Working to get customers to commit configuration to internal git servers

  • Adding these repositories to documentation repository

Git Submodules
git add submodule https://internal.gitserver.example.org/appserver/mainconfig.git
  • Git directories within repositories

git submodule

Build Outputs

Use Themes

Editors

  • Best: you can use any editor on any device

  • Syntax Highlighting in the most important ones

    • VIM

    • Emacs

    • Notepad++

    • VSCode|VSCodium, Atom

  • Documentation on editors

On Windows, stay away from Notepad and Wordpad because they produce plain text which is not cross-platform friendly.

Mobile

  • I use git for all documents

    • Version Control

    • Good mobile clients (for small adjustments)

  • Android

    • Termux

      • Vim

      • Git

  • Browser interface (Github, Gitlab)

Preview

  • (in the beginning) you will ask for WYSIWIG or Preview

  • VS Codium has a built-in preview plugin

  • Browser Extension to render Asciidoc

    • Check whitelist or you won’t see Font Awesome icons

  • Makefile

    • convert your documents with make

  • Guardfile with Guard

    • Run make everytime when file is saved

    • Very powerful when you finalize documents or presentations

Convert your documents

# Creates HTML of yourfile.adoc, name: yourfile.html
asciidoctor yourfile.adoc

# Create PDF
asciidoctor-pdf yourfile.adoc
You need to install all dependencies

Docker-Asciidoctor

# convert main.doc to html
docker run --rm -v $(pwd):/documents/ asciidoctor/asciidoctor asciidoctor main.adoc

Docker command explained

# Run this in the folder with your asciidoc files
docker run \
    --rm \                                       (1)
    -v $(pwd):/documents/ \                      (2)
    asciidoctor/asciidoctor \                    (3)
    asciidoctor \                                (4)
    main.adoc                                    (5)
1delete container after run
2Use Volume $(pwd) actual path in Linux and Mac OS as /documents in container
3Image name (template for container)
4Run command asciidoctor in that container
5On document main.adoc

Special command line options can be added!

Different Outputs with Docker container

Html
docker run --rm -v $(pwd):/documents/ asciidoctor/asciidoctor asciidoctor main.adoc
Html with Diagram
docker run --rm -v $(pwd):/documents/ asciidoctor/asciidoctor asciidoctor -r asciidoctor-diagram main.adoc
PDF with Diagram
docker run --rm -v $(pwd):/documents/ asciidoctor/asciidoctor asciidoctor-pdf -r asciidoctor-diagram main.adoc
Create page in Confluence Wiki
asciidoctor-confluence --host HOSTNAME --spaceKey KEY --title TITLE \
--username USER --password PASSWORD [--update] sample.adoc              (1)
1With --update the page gets updated, without created

Gradle

CI/CD with Gitlab

  • Best result

  • Hosted (https://gitlab.com) and Selfhosted

  • Converts on commit

  • Browse, publish or download results

  • Deploy the documents to webservers

  • How to:

    • Add CI/CD to your Gitlab project

    • Create .gitlab-ci.yml

Repository

.
├── docker-asciidoctor  (submodule)
├── documents-personal
│   ├── basic-example.adoc
├── documents-work
│   ├── basic-example.adoc
├── images
│   └── logo.png
├── LICENSE
├── pdftheme
│   ├── logo.png
│   ├── personal-theme.yml
│   └── work-theme.yml
├── presentations
│   └── slidedeck.adoc
├── public
│   ├── html-personal
│   ├── html-work
│   ├── images
│   ├── pdf-personal
│   ├── pdf-work
│   └── presentations
├── README.adoc
├── scripts
│   ├── create-index.sh
│   ├── html-conversion.sh
│   ├── html-work-conversion.sh
│   ├── pdf-conversion.sh
│   ├── pdf-work-conversion.sh
│   └── reveal-conversion.sh
└── wiki-articles

.gitlab-ci.yml (1)

image: docker:git

services:
- docker:dind

variables:
  CONTAINER_TEST_IMAGE: registry.gitlab.com/stoeps/$CI_PROJECT_NAME:$CI_BUILD_REF_NAME
  CONTAINER_RELEASE_IMAGE: registry.gitlab.com/stoeps/$CI_PROJECT_NAME:latest

before_script:
  - docker login -u gitlab-ci-token -p $CI_BUILD_TOKEN registry.gitlab.com
  - git submodule sync --recursive
  - git submodule update --init --recursive

stages:
  - build
  - test
  - release
  - conversion
  - deploy

build:
  stage: build
  script:
    - docker build -t $CONTAINER_TEST_IMAGE docker-asciidoctor
    - docker push $CONTAINER_TEST_IMAGE
  only:
    changes:
      - docker-asciidoctor/Dockerfile
    refs:

.gitlab-ci.yml (2)

      - master
    variables:
      - $BUILDCONTAINER

test 1:
  stage: test
  script:
    - echo "Run tests here"
    - docker run -t --rm $CONTAINER_TEST_IMAGE asciidoctor -v | grep "Asciidoctor"
  only:
    changes:
      - docker-asciidoctor/Dockerfile
    refs:
      - master
    variables:
      - $BUILDCONTAINER

test 2:
  stage: test
  script:
    - docker run -t --rm $CONTAINER_TEST_IMAGE asciidoctor-revealjs -v
  only:
    changes:
      - docker-asciidoctor/Dockerfile
    refs:
      - master
    variables:
      - $BUILDCONTAINER

release-image:

.gitlab-ci.yml (3)

  stage: release
  script:
    - echo "Tag Image and push to registry"
    - docker pull $CONTAINER_TEST_IMAGE
    - docker tag $CONTAINER_TEST_IMAGE $CONTAINER_RELEASE_IMAGE
    - docker push $CONTAINER_RELEASE_IMAGE
  only:
    changes:
      - docker-asciidoctor/Dockerfile
    refs:
      - master
    variables:
      - $BUILDCONTAINER

pdf:personal:
  stage: conversion
  script:
    - echo "Start Asciidoctor conversion"
    - echo $CONTAINER_IMAGE:$CI_COMMIT_SHA
    - docker run -t --rm -v $(pwd)/documents-personal:/documents/ -v $(pwd)/images:/images -v $(pwd)/scripts:/scripts $CONTAINER_RELEASE_IMAGE /scripts/pdf-conversion.sh
    - cp documents-personal/*.pdf public/pdf-personal
  artifacts:
    name: "pdf-personal-$CI_COMMIT_TAG"
    paths:
      - public/pdf-personal
    expire_in: 2 hours
  except:
    variables:
      - $BUILDCONTAINER

.gitlab-ci.yml (4)

pdf:work:
  stage: conversion
  script:
    - echo "Start Asciidoctor conversion"
    - echo $CONTAINER_IMAGE:$CI_COMMIT_SHA
    - docker run -t --rm -v $(pwd)/documents-work:/documents/ -v $(pwd)/images:/images -v $(pwd)/scripts:/scripts -v $(pwd)/pdftheme:/pdftheme/ $CONTAINER_RELEASE_IMAGE /scripts/pdf-work-conversion.sh
    - cp documents-work/*.pdf public/pdf-work
  artifacts:
    name: "pdf-work-$CI_COMMIT_TAG"
    paths:
      - public/pdf-work
    expire_in: 2 hours
  except:
    variables:
      - $BUILDCONTAINER

html:
  stage: conversion
  script:
    - echo "Start Asciidoctor conversion"
    - echo $CONTAINER_IMAGE:$CI_COMMIT_SHA
    - docker run -t --rm -v $(pwd)/documents-work:/documents/ -v $(pwd)/images:/images -v $(pwd)/scripts:/scripts $CONTAINER_RELEASE_IMAGE /scripts/html-work-conversion.sh
    - cp documents-work/*.html public/html-work
    - docker run -t --rm -v $(pwd)/documents-personal:/documents/ -v $(pwd)/images:/images -v $(pwd)/scripts:/scripts $CONTAINER_RELEASE_IMAGE /scripts/html-conversion.sh
    - cp documents-personal/*.html public/html-personal
  artifacts:
    name: "html-$CI_COMMIT_TAG"
    paths:
      - public/html-work
      - public/html-personal

.gitlab-ci.yml (5)

      - images
    expire_in: 2 hours
  except:
    variables:
      - $BUILDCONTAINER

reveal:
  stage: conversion
  script:
    - echo "Start Asciidoctor conversion"
    - echo $CONTAINER_IMAGE:$CI_COMMIT_SHA
    - docker run -t --rm -v $(pwd)/presentations:/documents/ -v $(pwd)/images:/images -v $(pwd)/scripts:/scripts $CONTAINER_RELEASE_IMAGE /scripts/reveal-conversion.sh
    - cp presentations/*.html public/presentations
  artifacts:
    name: "html-$CI_COMMIT_TAG"
    paths:
      - public/presentations
      - images
    expire_in: 2 hours
  except:
    variables:
      - $BUILDCONTAINER

pages:
  stage: deploy
  dependencies:
    - html
    - reveal
    - pdf:personal
    - pdf:work

.gitlab-ci.yml (6)

  script:
    - cp -arvf images/* public/images/
    - sh scripts/create-index.sh
    - chmod +r public -R
  artifacts:
    paths:
      - public
    expire_in: 1 hour
  only:
    refs:
      - master # this job will affect only the 'master' branch
  except:
    variables:
      - $BUILDCONTAINER

Example conversion script

#!/usr/bin/env bash
#
# Author:       Christoph Stoettner
#
for i in /documents/*.adoc
do
  asciidoctor \
      -r asciidoctor-pdf \
      -r asciidoctor-diagram \
      -r asciidoctor-mathematical \
      -b pdf \
      -a pdf-stylesdir=/pdftheme \
      -a pdf-style=work \
      -a media=prepress \
      "$i"
done

Gitlab Pipeline

gitlab pipelines
1Build pipeline ran successful
2Failed execution
3Download artifacts (Output formats)

Demo

Additional informations