Skip to content

Contributing

We welcome contributions! We believe that by fostering a healthy, inclusive, and active open source community that we will be able to build better software for all. A large part of that is by having an enforced code of conduct as well easy to use contributing guidelines.

Prerequisites

  • Python 3+ or above (with Pip)
  • Mkdocs 1.0.4 or above
  • Docker
  • Git

Build from source

This part should be easy. If it's not, let us know! The first thing you'll want to do is import the repository and open up the directory.

$ git clone git@github.com:backstage/mkdocs-monorepo-plugin.git

Then using the --editable flag, you can install the package locally. This points the actual plugin to the folder which allows you to make changes dynamically without having to re-install it every time you want to test a change.

$ cd mkdocs-monorepo-plugin/
$ pip install --editable .
$ pip install -r requirements.txt

Great, now you have the monorepo plugin available in Mkdocs. This allows you to do the following in an mkdocs.yml without errors:

site_name: Example Site

plugins:
  - monorepo

Of course, you'll need a folder to test it in. There is a conveniently folder named sample-docs/ folder that you can use to test your changes, although you can run mkdocs serve in any project you want as long as the mkdocs.yml has monorepo mentioned in the plugins key.

$ cd sample-docs/
$ mkdocs serve

Optionally, you can run it using Mkdocs Material which is what is powering the docs you're currently looking at. It makes Mkdocs really nice to work with. You can then simply pass through --theme to your mkdocs serve command like usual.

$ pip install mkdocs-material
$ mkdocs serve --theme material

That's pretty much it. Experiment, play about, make the changes you need.

How does it work?

Oh yes, that's worth mentioning! It works quite easily actually. There are two parts to the process: resolving the navigation, and merging the documentation folders.

Resolving the navigation

This is responsible for making sure whenever you use the !include statement in nav inside our mkdocs.yml that we appropriately open up the included file, get the nav, and then appropriately import that into the root nav. So to give you an example:

```yaml tab="Source mkdocs.yml files"

mkdocs.yml

site_name: Example Site

plugins: - monorepo

nav: - Getting Started: README.md - Design: '!include teams/design/mkdocs.yml' - Contributing: contributing.md

teams/design/mkdocs.yml

site_name: design-folder-alias

nav: - Menus: components/menus.md - Tabs: components/tabs.md - Playback Buttons: components/playback-buttons.md

```yaml tab="Output mkdocs.yml"
site_name: Example Site

plugins:
  - monorepo

nav:
  - Getting Started: README.md
  - Design:
      - Menus: design-folder-alias/components/menus.md
      - Tabs: design-folder-alias/components/tabs.md
      - Playback Buttons: design-folder-alias/components/playback-buttons.md
  - Contributing: contributing.md

Note that we've added a design-folder-alias/ to the links under Design. This is because when merging the docs in the next step, it is not possible to meaningfully merge them all into a single docs/ folder due to the likelihood of conflicts. Due to this, we made a design decision to repurpose the site_name to act as an alias when it is included in a monorepo context and uses this when it tries to create a "single" set of docs by using the alias as a folder.

The Python code related to this component lives in mkdocs_monorepo_plugin/parser.py.

Merging the docs folders

This takes the work the resolver does and applies it to reality. It is responsible for creating a temporary folder using Python's TemporaryFolder() and moves the root docs/ folder, as well as the docs/ folders of all included paths from the root nav. As mentioned, it also takes their site_name values and uses that to indicate where it should be placed in our "merged" documentation folder.

The Python code related to this component lives in mkdocs_monorepo_plugin/merger.py.

Making a change

That's excellent! We're very happy that you'd like to contribute. We are very welcoming to any contributions. It is important to note a few things before you do so:

  • Consider opening an issue first. It's easy to fall into the trap to create a bug for something that isn't agreed upon. GitHub issues is a great way to act as a validator for your contribution ideas. We try our best to engage in these as much as possible to make this as painless as possible, as it's easier to write the code than discuss it. It also significantly reduces the chances of us rejecting it.

  • Write tests. Of course, shipping stuff is pretty cool. Especially when it's a really nice improvement. In this case, there will have many others depending on our source code. It is a small ask for ask you to test your code in a basic capacity, so that it isn't prone to being broken or removed in the future accidentally. Adding complete test coverage is something we will suggest on a case-by-case basis, depending on the type of change it is.

  • Not every contribution will be approved. Of course, given how much volunteered time you and others spend, it is a great way of saying thank you for to accept and merge every pull request - but in reality, doing so is more harmful than valuable. We want to leverage open source to make software better for everyone rather than for a few. This means considering the long-term value of changes, as well as any impact it may have - will it break existing integrations? will it slow performance? is this a convention others will understand? As a general rule of thumb, we highly encourage you open a GitHub issue first to discuss your ideas. It will help everyone in the long run for just a little bit more time.

That out of the way, here's what you need to do:

$ git checkout -b username/branch-name
# ... make your changes
$ code ./setup.py # make sure you bump up the version on line 6
$ git add --patch # validate your changes
$ git commit -m 'changed X and Y' # ensure you write a meaningful commit message
$ git push -u origin HEAD

It might say you don't have permissions to push to our repository. That's alright, using hub fork you can fork the repository on GitHub and then replace the origin remote with your own directly from your Terminal:

$ hub fork --remote-name origin
$ git remote rm origin
$ git remote add origin git@github.com:[USERNAME]/mkdocs-monorepo-plugin.git
$ git push -u origin HEAD
$ hub pull-request -b spotify:master --message 'Pull request title' --browse # add --draft if you want to push it as a draft PR

This will create the pull request in our repository. You can of course do it through GitHub.com or their desktop clients too :)

Running tests

The command below will use Docker to run our test suites in numerous Python versions. It may take some time on first run, but should be very fast afterwards. When you're done, feel free to run docker prune to clear them from your local cache. We use the slim versions of the public python images from Docker Hub.

$ ./__tests__/test-local.sh

For faster tests, you can opt to run in Python 3.7 rather than all supported Python versions:

$ PYTHON_37_ONLY=1 ./__tests__/test-local.sh

GitHub Actions will always execute tests a little faster (due to parallelization) when you push your branch. Due to this, you can choose to opt of running them locally if you wish!

Submitting a PR

Feel free to open up a PR and share why you think this change is valuable (unless it's something obvious, like a typo or confirmed bug). Assuming it is a change that is wanted, a maintainer will take a look to see if there's any changes needed.

To make a new release, make sure to update the version in setup.py and add a new entry in the CHANGELOG.md.