TLDR; This is a reference for myself how you can change the contents of a GitHub wiki using a GitHub action.
So, the use-case to cover was to create a summary document, whenever the
wiki was modified by someone. Luckily GitHub actions has a hook for this
named gollum
. In case you are wondering, this is the name of the wiki
engine in use. See more in the official documentation.
So, how does an action look like? How about this to put in your
.github/workflows
folder:
name: Recreate wiki summary page on wiki changes
on:
gollum:
workflow_dispatch:
jobs:
create-wiki-summary:
runs-on: ubuntu-latest
steps:
- name: Check out repo
uses: actions/checkout@v2
- name: Check out wiki
uses: actions/checkout@v2
with:
repository: 'user/my-repo.wiki'
ref: 'master'
path: 'my-repo.wiki'
- name: Update summary.md if needed
run: ./create-summary.sh $GITHUB_WORKSPACE/my-repo.wiki
working-directory: ./my-directory
So, what happens here? Basically there are three steps
- Check out the repo where this has been triggered
- Check out the wiki into the directory
my-repo.wiki
- a GitHub wiki is stored in a GitHub repository as well, so checking it out is easy - Run the script in
my-directory/create-summary.sh
and pass the path of the repo as argument
Lastly the workflow_dispatch
event exists to be able to trigger this via
the github actions tab of the repository.
The shell script (make sure it’s marked as executable) is extracting the last paragraph of each markdown file and appends it into another markdown file, so that the reader can possibly just look at that one instead of all pages individually:
#!/bin/bash
#########
# some debug output to check in case of failures
# also exit on any error
set -xe
cd $1
# Get the md5sum from the summary markdown file
md5=$(md5sum Summary.md)
# Run the summary
rm -f Summary.md
(
# exclude documents that you do not want to check
for i in $(find . -name '*.md' \
'!' -name first-excluded-document.md \
'!' -name further-excluded-document.md \
'!' -name Summary.md | sort) ; do
name=$(basename $i)
name=${name/.md}
cat $i | \
# print everything after this point in the markdown
sed -n -e '/## LAST PARAGRAPH TITLE/,$p' | \
# replace title with name of the file
sed -e 's@^## LAST PARAGRAPH TITLE@## '"$name"'@'
echo
done
) > Summary.md
# Compare md5 sums
new_md5=$(md5sum Summary.md)
echo "Old md5 sum: $md5 ; New md5 sum: $new_md5"
if [ "$md5" != "$new_md5" ] ; then
# this is required for the push to succeed
git config --global user.email "team+github-action@elastic.co"
git config --global user.name "Action McActionFace"
git add Summary.md
git commit -m "Update Summary.md at $(date)"
git push origin master
fi
The shell script checks the md5sum of a certain markdown file, then goes on to create the summary, then checks the md5sum again, and only if those differ, the final markdown is committed.
There are two specialties here. First, the sed
call. For every markdown
file returnind from the find
call, this gets run
cat $i | \
# print everything after this point in the markdown
sed -n -e '/## LAST PARAGRAPH TITLE/,$p' | \
# replace title with name of the file
sed -e 's@^## LAST PARAGRAPH TITLE@## '"$name"'@'
The first sed call returns everything till the end of the file, when ## LAST PARAGRAPH TITLE
is found. This works in my case, because I only need
to extract the last paragraph, but might differ in your use-case. The second
part replaces the title with the name of file, so that it is easy to
identify in the document.
The final part with all the git
commands, ensures that the push is
successful by setting the user name and emails plus creating a commit
message for the wiki.
A new git commit should only be done if there have been actual changes to the part of the markdown that gets collected in the summary document - this is the reason for the md5 check.
That’s it. You could optimize this by inlining the shell script, so that it does not need to check out the repository, but I like this approach a little more than embed shell scripts in the github action.