GitHub Action, Docker Container, and CLI tool to allow merging child documents into one README.md
BE CAREFUL: This will overwrite your README.md
file.
Layout and syntax for README Merge has deliberately designed to be very simple. You only need:
- Directory for Markdown files
- Entry-point source Markdown file
- Other source Markdown files
- Merge Directives in Source files
Your source directory of Markdown files should have an entry point file which by convention README Merge names _index.md
in the ./md
subdirectory off the repository's root.
Note that if you use those names — e.g. ./readme/_index.md
— you will not need to specify them when using the GitHub Action.
Other source files are just Markdown files in the same directory as the _index.md
file that can be merged. The first special cases for how they need to be authored is discussed below.
Your entry point file — which I will refer to as _index.md
from here on in this section — should have one or more [merge]
directives. They are the same syntax as a link but use the word merge
as a special keyword.
From the samples _index.md
file — shown below — you can see that the [merge]
directive MUST be in the first column or README Merge will ignore it. This allows you to still link the work merge to somewhere if you have that need:
# Just a Sample README-merge Index Template
[merge](./foo.md)
[merge](./bar.md)
# Footer
As you can see from the samples foo.md
file — merged above and shown below — you can see that the merged files can also contain [merge]
directives:
# Foo Template
This is the Foo template
[merge](./baz.md)
To avoid scope-creep and additional complexity README Merge does not support underlines to indicate headers. Headers must use hash (#
) characters, e.g:
#
##
###
####
#####
# Good Header
# Bad Header
# Worse Header
To simplify implementation headers MUST be placed in column one (1) or they will be ignored by README Merge.
The reason for this is that the first non-whitespace characters in source code examples are occassionally #
characters — which as comments in Shell scripts nd Ruby source code — so to keep parsing simple we have decided to require headers to be in column 1. This requirement also limits potential bugs.
If this becomes a problem we can potentially enhance README Merge to recognize headings with up to three (3) space characters before the (first) #
, but we won't do that until it becomes a repeated sore point for users.
One reason the author built this was he hated having to author Markdown files as parts of a whole that could not live on their own as standalone Markdown files.
Specifically, if a Markdown file with a level 1 heading — e.g. #
— is merged in to an _index.md
file then that level 1 heading would compete with the level 1 heading of the _index.md
file and thus with the resultant README.md
output file.
To solve this, README Merge demotes any headings of a merged document by one. For example, if usage.md
starts with # Usage
and is merged into _index.md
then it will appear as ## Usage
in the output README.md
.
# Usage
# Example README
## Usage
This is further true of nested documents. This is docker-usage.md
is merged into usage.md
which is merged into _index.md
and docker-usage.md
has a header of # Docker Usage
then in the resultant README.md
it will appear two levels demoted, or ### Docker Usage
.
# Docker Usage
# Example README
## Usage
### Docker Usage
To understand the layout and syntax expected by README merge you can review the very simple samples files located in ./samples/readme
as seen in the screenshot below:
Directory tree for sample Markdown source files.
Alternately you can look at the source markdown files for this repo's README.md
in the ./md
:
Directory tree for Markdown source files for this repo.
readme-merge <index_file> <readme_path> [no_commit]
readme-merge readme/_index.md . no_commit
In order to configure this GitHub Action to work for your repository you need to do the following three (3) things:
- Add a directory of source Markdown files and an entry point file
- Set Read/Write Access
- Add a workflow .YAML file
README Merge reads an entry point file in a subdirectory that defaults — if you do not specify otherwise in your workflow — to ./readme/_index.md
where /readme
is a subdirectory off the root.
For more details about the entry-point file and document syntax see Layout and Syntax.
As the entire purpose of this action is to build the README.md
this action cannot perform its purpose unless it can update the GitHub repo. If you have security concerns about write access see the security section below.
To configure your GitHub repo for to allow writes, visit your repo's Settings from the top GitHub menu, select GitHub Actions and then follow the instructions in this screenshot:
Save the following code as .github/workflows/generate-readme.yaml
in your repo and commit.
No changes necessary if:
- Your source Markdown files are in a subdirectory
/readme
off your repo's root, - Your entry point document in your subdirectory is named
_index.md
, - You use
main
as your primary branch, and - You want to update the
README.md
on push themain
.
If you have more complex needs and/or use-cases then modifications to this workflow will obviously be required:
name: Generate README
on:
push:
branches:
- main
- test-actions
jobs:
generate-readme:
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Generate README
uses: mikeschinkel/readme-merge@main
with:
index_filepath: './readme/_index.md'
readme_dir: '.'
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
This GitHub Action requires read and write access to your repository so it can update the README.md
file. The updates happen in the shell script /bin/entrypoint.sh
for your security review.
If you cannot set read/write access because your security team does not allow it, or you simply do not want to allow write access to GitHub Actions on your repo then do not use this GitHub Action and instead either use the Docker container or the readme-merge
executable elsewhere in your CI/CD and/or README authoring process.
docker build -t readme-merge:<your_tag> ../
docker run -v "<your_local_repo_root>:/app/<repo_in_container>" --rm \
readme-merge:<your_tag> \
./<repo_in_container>/<local_markdown_source_dir>/<entry_point_doc> \
./<repo_in_container>/<local_dir_for_readme> \
[commit|no_commit]
docker build -t readme-merge:your_tag ../
docker run -v "$(pwd)/..:/app/repo" --rm \
readme-merge:local_usage \
./repo/samples/readme/_index.md \
./repo/samples/. \
no_commit
There is a very simply set of Markdown documents in the /samples/readme
directory.
Directory tree for sample Markdown source files.
You can see how the samples work by running the following commands which will build a Docker container to run go build
and then run readme-merge
which will merge the sample docs into an example README.md
file as /samples/README.md
and then use less
to view it:
git clone https://github.com/mikeschinkel/readme-merge
cd readme-merge/samples
./build-sample-readme.sh
To build the sample README.md
you need:
- To be running a flavor of *nix (Linux, macOS, WSL, etc)
- To have a running Docker daemon installed.
There is not batch file or PowerShell script for use if you are running Windows but if you are motivated you can port ./samples/build-sample-readme.sh
and support a PR to include for future Windows users.
If you use README Merge please consider submitting a pull request with a link to your repo using to contained in ./where-used.md
.
- GitHub Action does not handle not having a starting README.md correctly.
- No Table of Contents generation.
MIT