Growing with the Web

Enabling pull requests on GitHub wikis

Published
Tags:

GitHub wikis are great for documentating projects due to their ease of use and high visibility. The problem is though that there are only two options for access; full access for everyone or restricted to collaborators only. Unfortunately it’s rarely the case you want the public to have full edit access to the wiki, and restricted prevents external contributions completely. This article describes how I recently got around this to enable contributions to the Visual Studio Code wiki via pull requests.

Underneath, GitHub wikis are just Git repositories which should enable all the collaborative goodness of the projects themselves through forking and pull requests. Unfortunately you cannot fork the wikis through the UI, so while you can clone the wiki and make a change to your copy, you cannot submit a pull request as your copy is not “linked” with the original repository.

A relatively easy workaround for this issue is to just move the documentation to the project repository, this comes with a number of drawbacks however:

  • No automatic table of contents
  • No longer highly visible; users searching for documentation need to hunt through the codebase (or follow links) to find what they want
  • Commits to documentation are mixed in with code commits

There is a workaround though that can allow people to submit pull requests to the wiki.

How it works

The technique works by cloning the wiki, pushing it to a new repository so that pull requests can be put out against it, then creating a CI build that automates syncing between the two repositories.

While it takes a bit of work to setup, it’s a really nice experience for collaborators and users afterwards.

In this walkthrough I’ll be using the project Tyriar/wiki-sync-example.

Create a new repository and sync it with the wiki

First start by creating a new repository, name it the same as the original repository but add -wiki to the end, the one I created is Tyriar/wiki-sync-example-wiki.

Next open the wiki of the original repository and copy the repository address, it should end with .wiki.git.

Now clone the wiki, change the remote to point at the new repository and push.

# Clone the original wiki
git clone https://github.com/Tyriar/wiki-sync-example.wiki.git

# Rename the folder as it's going to be pushed to the -wiki repository
mv wiki-sync-example.wiki wiki-sync-example-wiki

# Enter the folder
cd wiki-sync-example-wiki

# Remove the original wiki repository as the origin
git remote remove origin

# Add the new wiki repository as the origin
git remote add origin https://github.com/Tyriar/wiki-sync-example-wiki.git

# Push to GitHub!
git push -u origin master

To verify this worked, go to the new repository on GitHub. You should see the structure of the wiki in the Code tab.

Create the travis.yml that will do the syncing

Create a .travis.yml in the new repository with the following contents, replace your own values for <USER_NAME>, <EMAIL> and the repository address:

script:
- |
  git config user.name "<USER_NAME>"
  git config user.email "<EMAIL>"
  git remote remove origin
  git remote add origin https://$GITHUB_API_KEY@github.com/Tyriar/wiki-sync-example-wiki.git > /dev/null 2>&1
  git remote add upstream https://$GITHUB_API_KEY@github.com/Tyriar/wiki-sync-example.wiki.git > /dev/null 2>&1
  git fetch origin
  git fetch upstream
  git merge upstream/master --no-edit
  git push origin HEAD:master > /dev/null 2>&1
  git push upstream HEAD:master > /dev/null 2>&1

Note that in the above script, the secret key $GITHUB_API_KEY that’s about to be setup is used and any output generated by the command is redirected to /dev/null so that the key doesn’t show up in the build log.

Generate a GitHub personal access token with write access to the project

A personal access token that has push access to the repository will need to be generated to do the actual syncing between the repositories. This can be generated in Settings > Personal access token.

Make sure it only has as much access as it needs, in my case it only needs the public_repo permission. Remember, this generated key has push access to your repositories so you need to be careful with it.

Setup a Travis CI encrypted variable that houses your personal access token

You now need to let Travis CI know about the personal access token. Since it’s a secret key, you need to encrypt it so that it’s not visible in your public builds. This can be achieved using Travis CI encrypted variables.

You will need python installed before you can complete this step. See the Travis CI documentation for how to add an encrypted variable against the repository. Here’s what I ran, where <SECRET_KEY> was my key.

sudo gem install travis
travis --sync
travis encrypt GITHUB_API_KEY=<SECRET_KEY> --add env.matrix

This should add the encrypted key to your .travis.yml, now commit it and push to GitHub:

git add .travis.yml
git commit -m "Add .travis.yml to sync repositories"
git push

Turn on Travis CI for the new repository

The Travis CI builds can then be turned on for the -wiki repository on your Travis CI profile page.

The next time a commit is pushed to the wiki, the CI build will trigger and it will sync the new addition. The Travis CI build badge can then be added to the project repository to easily track whether there are any issues with the sync job.

The last part of simple syncing is to add a message to the wiki’s footer, informing people how to contribute. Create a _Footer.md file and make the contents something like this:

### Want to contribute to this Wiki?

[Fork it and send a pull request.](https://github.com/Tyriar/wiki-sync-example-wiki)

This results the following at the bottom of each wiki page:

The message defined in _Footer.md

More robust two-way syncing using periodic builds

If you’ve made it this far, simple two-way syncing is complete and any commits that are pushed to the -wiki repo will be pushed to the project’s wiki page after merging in the .wiki repo.

There’s one more improvement that can be made. Currently if many commits are made through the /wiki web UI then the -wiki repo will become stale, increasing the likelyhood of merge conflicts that require manual intervention to resolve. To counter this, periodic builds can be setup so that the sync job will run periodically. You’ll need to loop in another service such as Nightli.es for Travis CI or VSTS to accomplish this since Travis CI does not support periodic builds.

This last step may not be necessary though if there aren’t many contributions made through the web UI.

Like this article?
Subscribe for more!