MkDocs and GitHub Pages Workflow¶
This article will not explain the syntax and semantics of MkDocs or how to actually write a documentation. Instead, it aims at providing a workflow on how to start and integrate MkDocs in an ongoing project. Hence, this explanation should be useful if you want to learn how to start with a documentation and/or if your README.md
of your project is not sufficient.
Without loss of generality, we assume the name of the project to be codeflow
and the name of the user to be lyrahgames
. Please interchange both of them with your own preference.
Requirements¶
- Python
- pip
- MkDocs
Preliminaries¶
Typically, the project files of your project codeflow
will reside in their own directory, also known as the project directory, with the same name. In the most cases, the project directory is version-controlled by Git and as a result, we may as well call the respective directory the project repository. As an example, assume your project would be a C++ application. The content of the project could then be something like the following.
codeflow
├── .git/...
├── .gitignore
│
├── build/
│ ├── bootstrap.build
│ └── root.build
├── buildfile
├── manifest
│
├── codeflow/
│ ├── application.cpp
│ ├── application.hpp
│ ├── buildfile
│ └── main.cpp
│
├── LICENSE
└── README.md
Here, we have some files and folders concerning Git, the chosen build system, the source code itself, license files, and the up-to-this-point-sufficient documentation in the file README.md
.
In a C++ project, we tend to use more than one configuration to build and test the source code of the project. As an example, we would like to build the project with the GCC and the Clang compiler. Due to their strong platform-dependence, these configurations should not be stored inside the project repository. Hence, they are not version-controlled by Git. To keep the overview over all those configurations, we use another parent directory again with the same name as the project. We call this parent directory the developer folder. In the following, the tree of the content for this example is shown.
codeflow/ # Developer Folder
│
├── codeflow/ # Project Folder
│ ├── .git/...
│ ├── .gitignore
│ │
│ ├── build/
│ │ ├── bootstrap.build
│ │ └── root.build
│ ├── buildfile
│ ├── manifest
│ │
│ ├── codeflow/
│ │ ├── buildfile
│ │ ├── application.hpp
│ │ ├── application.cpp
│ │ └── main.cpp
│ │
│ ├── LICENSE
│ └── README.md
│
├── codeflow-gcc/... # Configuration Folder 'gcc'
│
└── codeflow-clang/... # Configuration Folder 'clang'
Initialization¶
In the next step, we will initialize the documentation with its configuration. We assume that you are currently residing inside the developer folder of your project.
$ pwd
/home/lyrahgames/projects/codeflow
Go into the project folder and create a directory for the documentation. Afterwards, initialize a new web documentation with MkDocs.
cd codeflow
mkdir docs
cd docs
mkdocs new web
Note
Sometimes the documentation for a project does not only exist as website readable by browsers but also as LaTeX documents or other presentations. In this case, we want to be able to keep such files inside the docs directory without changing the web documentation. Therefore we use another subdirectory called web
. If you do want to keep things very simple then run mkdocs new docs
inside your project folder. But please be aware that this will pollute your project folder with configuration files concerning MkDocs and its themes.
We now have to make sure that Git is not ignoring those new files created by MkDocs. If you have chosen the white-listing approach for your .gitignore
files, we can add something like the following to a new .gitignore
file inside the web documentation folder.
# File: docs/web/.gitignore
!*.md
!mkdocs.yml
!requirements.txt
Because MkDocs is based on Python, we additionally have created the file requirements.txt
for the pip Package Manager to provide all requirements the documentation needs to be built. At this moment, it should only contain mkdocs
.
# File: docs/web/requirements.txt
mkdocs
The project folder structure should now look like the following.
codeflow # Project Folder
├── .git/...
├── .gitignore
│
├── build/
│ ├── bootstrap.build
│ └── root.build
├── buildfile
├── manifest
│
├── docs/ # Documentation Folder
│ └── web/ # Web Documentation Folder
│ ├── .gitignore
│ ├── docs/
│ │ └── index.md
│ ├── mkdocs.yml
│ └── requirements.txt
│
├── codeflow/
│ ├── application.cpp
│ ├── application.hpp
│ ├── buildfile
│ └── main.cpp
│
├── LICENSE
└── README.md
Now, to get an impression of the website, MkDocs provides the serve
command. It will generate the documentation, update it every time a file in the directory has changed, and provide browser access to the generated site at address 127.0.0.1:8000
. So go into the web documentation folder, run the following command, and look at the result in your browser.
mkdocs serve
This finalizes the initialization process and as a good practice, a commit should be made.
Configuration¶
At this point, you are able to start documenting your project by adding new files in the Markdown format inside the docs
folder of your web documentation folder. MkDocs will automatically detect those files and show them in the table of contents inside your browser. But on the other hand, it may be a good idea to take some more time to configure the MkDocs build process to slightly tweak the generated documentation.
Basics¶
The complete configuration of MkDocs can be done by adjusting the file mkdocs.yml
inside the web documentation folder. At first you should add the basic information about your project and its documentation.
# File: docs/web/mkdocs.yml
site_name: Codeflow
site_url: https://lyrahgames.github.io/codeflow
site_author: Markus Pawellek
site_description: >-
Tutorials, Explanations, Exercises, Solutions,
Workflows referring to Coding and Sciences
repo_name: lyrahgames/codeflow
repo_url: https://github.com/lyrahgames/codeflow
copyright: Copyright © 2020 Markus Pawellek
Theme¶
Afterwards, in my opinion one of the main decisions has to be made. We have to choose a theme. I recommend to choose the Material for MkDocs theme. This theme comes with an extremely good documentation about its usage and configuration. Furthermore, it gives you some hints about what extensions and plugins to additionally add to your MkDocs configuration to make the documentation process easier and faster. Here, we do not go through details but provide an example configuration for the Material theme.
# File: docs/web/mkdocs.yml
# ...
theme:
name: material
custom_dir: overrides
language: en
features:
- tabs
palette:
scheme: default
primary: white
accent: indigo
font:
text: Roboto
code: Roboto Mono
icon:
logo: material/library
repo: fontawesome/brands/git-alt
extra:
social:
- icon: fontawesome/brands/github
link: https://github.com/lyrahgames
markdown_extensions:
- admonition
- codehilite:
guess_lang: false
linenums: false
- toc:
permalink: true
- meta
- pymdownx.arithmatex
- pymdownx.betterem:
smart_enable: all
- pymdownx.caret
- pymdownx.critic
- pymdownx.details
- pymdownx.emoji:
emoji_index: !!python/name:materialx.emoji.twemoji
emoji_generator: !!python/name:materialx.emoji.to_svg
- pymdownx.inlinehilite
- pymdownx.magiclink
- pymdownx.mark
- pymdownx.smartsymbols
- pymdownx.superfences
- pymdownx.tasklist:
custom_checkbox: true
- pymdownx.tabbed
- pymdownx.tilde
extra_javascript:
- https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.0/MathJax.js?config=TeX-MML-AM_CHTML
plugins:
- search
- minify:
minify_html: true
- git-revision-date-localized
- awesome-pages
We make sure not to use something not provided by the system and add some new entries to the requirements.txt
file.
# File: docs/web/requirements.txt
mkdocs
mkdocs-material
mkdocs-minify-plugin
mkdocs-git-revision-date-localized-plugin
mkdocs-awesome-pages-plugin
Before looking at the generated output, make sure to use pip with this requirements.txt
to install the missing dependencies for ourselves by running the following command.
pip install -r requirements.txt
Customization of Material Theme: Justify Text¶
Nearly every theme for MkDocs will give possibilities to customize its design, formatting rules, and other stuff. As an example for the Material theme, we will show how to set the alignment of content text blocks to the justify mode. For this, we use the override mechanism provided by the Material theme.
First, create a new directory overrides
in the web documentation folder.
cd docs/web
mkdir overrides
cd overrides
Now, open the new file main.html
inside the folder overrides
and add the following content.
{% extends "base.html" %}
{% block content %}
<style type="text/css">
p {
text-align: justify;
text-justify: inter-word;
}
</style>
{{ super() }}
{% endblock %}
Your current project folder structure should look like the following.
codeflow # Project Folder
├── .git/...
├── .gitignore
│
├── build/
│ ├── bootstrap.build
│ └── root.build
├── buildfile
├── manifest
│
├── docs/ # Documentation Folder
│ └── web/ # Web Documentation Folder
│ ├── .gitignore
│ ├── docs/ # Folder for the Actual Documentation Files
│ │ └── index.md
│ ├── overrides/ # Material Theme Customization Folder
│ │ └── main.html # Customization for all Documentation Files
│ ├── mkdocs.yml
│ └── requirements.txt
│
├── codeflow/
│ ├── application.cpp
│ ├── application.hpp
│ ├── buildfile
│ └── main.cpp
│
├── LICENSE
└── README.md
Build and Deploy¶
After complete configuration and the writing of new documentation files, the generated site should be observed in the browser to test if all settings work as expected. This can be done again by using the command mkdocs serve
. If everything seems to be alright, we have to build the documentation to actually get the files of the website. We want to push those files to a documentation hosting platform, in our case GitHub Pages, to make the documentation available to other people.
Initialization¶
First, we set up a new configuration folder inside the developer folder where all files of the generated documentation will be put. Because we want to use GitHub Pages as a hosting platform, we have to make sure to use a Git repository which is pushing to the branch gh-pages
.
Make sure that you are in the developer folder.
$ pwd
/home/lyrahgames/projects/codeflow
Initialize a new Git repository, set it to the according branch, and provide the GitHub repository address as a remote by using the following commands.
git init codeflow-gh-pages
cd codeflow-gh-pages
git checkout -b gh-pages
git remote add origin git@github.com:lyrahgames/codeflow.git
The structure of your developer folder should now look like this.
codeflow/ # Developer Folder
│
├── codeflow/... # Project Folder
│
├── codeflow-gcc/... # Configuration Folder 'gcc'
│
├── codeflow-clang/... # Configuration Folder 'clang'
│
└── codeflow-gh-pages/ # Configuration Folder for GitHub Pages
The GitHub Pages environment on GitHub does not have to be turned on manually. GitHub should automatically enable this feature if the gh-pages
branch is available in the GitHub repository. If this is not the case, enable the environment manually.
Updating¶
Building the documentation has to be done every time you want to push the changes to the hosting platform. To keep your GitHub repository consistent, you should first make a commit in the project folder and push it to the master
branch of your GitHub repository.
git add .
git commit
git push origin master
Afterwards, you are now able to actually build the documentation into the configuration folder for GitHub Pages. Make sure to run the following command inside the web documentation folder.
mkdocs build -d ../../../codeflow-gh-pages
Now, we go into the configuration folder for GitHub Pages and commit its changes by amending to the previous commit. This makes sure the site will not be version-controlled by Git. We do not want it to be version-controlled because the generated site is a build artifact.
cd ../../../codeflow-gh-pages
git add .
git commit --amend -m "Update site"
Because we have amended to the previous commit, we have to do a force push to the gh-pages
branch to update the documentation on the hosting platform.
git push -f origin gh-pages.
Automatic Documentation Generation
Of course, it would be possible to automatically generate the documentation with a CI environment. But we do not recommend it. For this, we would need another server which additionally would have to be configured. This may introduce unnecessary version controlling for the generated site and as a result unnecessary memory usage of the repository. For a simple documentation site, this may be too much overhead. If one would not want to use GitHub Pages, we could use ReadTheDocs to automatically generate every commit to the master branch.
Making it Easier through Scripts¶
If you are frequently writing the documentation of your project on different platforms, it can become cumbersome to run all the commands for the initialization, building, and deploying every time. To make it easier and faster, we can provide simple scripts that allow us to do these processes in one simple step. Here, it is done for a Linux-based operating system. We will create two shell scripts, init.sh
for the initialization and build_and_deploy.sh
for the building and deployment, inside the web documentation folder. Your current project folder structure should then look like the following.
codeflow # Project Folder
├── .git/...
├── .gitignore
│
├── build/
│ ├── bootstrap.build
│ └── root.build
├── buildfile
├── manifest
│
├── docs/ # Documentation Folder
│ └── web/ # Web Documentation Folder
│ ├── .gitignore
│ ├── docs/ # Folder for the Actual Documentation Files
│ │ └── index.md
│ ├── overrides/
│ │ └── main.html
│ ├── mkdocs.yml
│ ├── requirements.txt
│ ├── init.sh # Shell Script for Initialization
│ └── build_and_deploy.sh # Shell Script for Building and Deployment
│
├── codeflow/
│ ├── application.cpp
│ ├── application.hpp
│ ├── buildfile
│ └── main.cpp
│
├── LICENSE
└── README.md
Both scripts only contain the commands that were already described in the above sections. Additionally, we have added a mechanism to determine the current folder and changing the current directory to the directory where the script itself lies. This makes sure there will be no problems when the scripts are called from another directory.
# File: docs/web/init.sh
#!/bin/sh
# Make sure to run the run the commands in the web documentation folder.
doc_dir=`dirname "$0"`
cd $doc_dir
# Install all requirements to be able to build the documentation.
pip install -r requirements.txt
# Create a configuration folder for the gh-pages branch next to the
# project folder and hopefully inside the developer folder.
# After building the documentation, we typically do a force push to
# the remote repository. Hence, it is enough to create a new repository
# and not to clone the remote repository.
# We can even run these commands if there is no gh-pages branch available.
cd ../../..
git init codeflow-gh-pages
cd codeflow-gh-pages
git checkout -b gh-pages
git remote add origin git@github.com:lyrahgames/codeflow.git
touch index.html
git add .
git commit -m "Initial commit"
# Alternative initialization process using cloning.
# cd ../../..
# git clone git@github.com:lyrahgames/codeflow.git --branch gh-pages --single-branch codeflow-gh-pages
# cd codeflow-gh-pages
# git checkout gh-pages
# File: docs/web/build_and_deploy.sh
#!/bin/sh
# Make sure to run the run the commands in the web documentation folder.
doc_dir=`dirname "$0"`
cd $doc_dir
# Build the documentation into the GitHub Pages configuration folder.
mkdocs build -d ../../../codeflow-gh-pages
# Deploy the documentation by amending the changes to disable version control
# and by force pushing to the remote repository.
cd ../../../codeflow-gh-pages
git add .
git commit --amend -m "Update site"
git push -f origin gh-pages
Of course, we have to slightly change the .gitignore
file to allow the shell scripts to be captured by Git.
# File: docs/web/.gitignore
!overrides/*.html
!mkdocs.yml
!requirements.txt
!*.sh
Afterwards, we set the executable flags to be able to run the scripts from the command line.
chmod +x init.sh build_and_deploy.sh
For the future this means, after cloning the repository, one should execute the init.sh
script to generate the GitHub Pages configuration folder. After changing the documentation and committing the result, one should call the build_and_deploy.sh
script to push the newly created site to documentation hosting platform.
Note
Going one step further, we could even think about using Git hooks to automatically run the build_and_deploy.sh
script for every commit on the master
branch.