Post

Version Control Your Diagrams: Automated PlantUML Rendering with GitHub Actions

Version Control Your Diagrams: Automated PlantUML Rendering with GitHub Actions

My Motivation

A few months ago I joined the Architecture Guild at work to participate in the architectural decision process as well as to educate myself further in this area. As part of this additional role, I have taken over the responsibility of certain tasks in our team. One of them is documentation — specifically, how to improve the existing documentation by following a Docs As Code approach and using established tools like AsciiDoc and PlantUML. However, for my private projects, I haven’t had the chance to utilize such tools yet.

For my private side projects, I am shifting my focus towards Swift and SwiftUI for mobile, tablet and desktop applications. To support my journey in this area, I am also working through the LeadEssentials iOS learning program. In this program, we learn best practices, tools and techniques for developing iOS applications with a focus on enterprise applications. From my experience, many of these best practices and tools can also be used for side projects to some extent.

You may have heard about my FeedReader app TwistReader, which is currently on TestFlight. The current version is a MAUI app, and the current state is still “beta”. To push it through to the App Store, I will have to rework a good amount of the existing codebase to improve and make the app run more reliably. I stopped developing it seriously some time ago because it was “good enough” for me and my few beta testers. This means there are some annoyances as well, and to iron them out, I will have to put quite a bit of effort into it again.

All of these factors led me to decide that TwistReader will be my side project to apply what I have learned. This means a complete rewrite of the application in Swift and SwiftUI! Before writing a single line of code, I applied the Docs As Code approach I learned at work and created a C4 model architecture diagram for the first three levels. The docs will be hosted on GitHub, which allows me to create a Wiki or documentation website if needed.

For creating the diagrams, I chose PlantUML, a descriptive tool that generates diagrams from code. For the documents themselves, I stayed with Markdown because it is better supported on GitHub than AsciiDoc. In this post, I will show you a basic diagram and how I automate the rendering process with a GitHub action.

Sample repository

I created a sample repository that demonstrates the whole process. You can find it here on GitHub.

I prepared a docs folder in the repo as this is a typical approach when following the Docs As Code approach, keeping documentation organized and version-controlled alongside the source code. This folder sits on the root level just as the src or tests folder.

Within this folder, I created a .puml file that demonstrates the automated diagram generation process we’ll explore in this post.

In the .github/workflows folder, I created the YAML configuration file that makes this automation work. We will go through this file next to understand how the automation works.

Automating the rendering process

Configure the triggers

Let’s start with the trigger section of the YAML file:

1
2
3
4
5
6
7
8
on:
  push:
    branches:
      - docs
    paths:
      - 'docs/*.puml'

    workflow_dispatch:  # manual trigger via GitHub UI

This configuration tells the GitHub Action runner to only execute on pushes to the docs branch. The paths tell the action to only run when a .puml has changed.

Tip: If you have sub-folders, just insert /** after the docs/.

The workflow_dispatch command entry allows us to trigger the action manually as well.

Good to know: The action must have run successfully at least once before we can trigger the action manually.

Configure the Job

1
2
3
4
5
jobs:
  plantuml:
    runs-on: ubuntu-latest
    permissions:
      contents: write  # Required to push changes back to the repository

With these lines, we are telling the runner to run our job named plantuml on a Linux VM. We are also setting up the permissions for the default GitHub secret, which will be needed to commit the generated images back into our repository.

Now we are ready to configure the steps of our action:

Checkout

The first step is - no surprise - to check out the repo. The important addition in this step is the token configuration, which will enable the action to auto-commit the generated images back to the repository.

1
2
3
4
      - name: Checkout
        uses: actions/checkout@v3
        with:
          token: $

Install Java and GraphViz

The next two steps are prerequisites for PlantUML:

1
2
3
4
5
6
7
8
      - name: Set up Java
        uses: actions/setup-java@v4
        with:
          distribution: 'temurin'
          java-version: '17'

      - name: Install GraphViz
        run: sudo apt-get update && sudo apt-get install -y graphviz

Download PlantUML

Finally, we are going to download PlantUML. I needed to use a specific version instead of the latest tagged version to get my GitHub action up and running:

1
2
3
4
5
6
      - name: Download PlantUML jar
        run: curl -L -o plantuml.jar https://github.com/plantuml/plantuml/releases/download/v1.2024.7/plantuml-1.2024.7.jar

      # Optionally check the SHA256 checksum to avoid corrupt downloads
      # - name: Verify PlantUML jar checksum
      #   run: echo "<expected_sha256_here>  plantuml.jar" | sha256sum -c -

Generate the .svg image(s)

Now that PlantUML is available on our runner, we are finally able to render the .svg images for all .puml files found in the docs folder (and sub-folders, if any):

1
2
3
      - name: Render .puml to .svg
        run: |
          find ./docs -name '*.puml' -exec java -jar plantuml.jar -tsvg -o . {} +

Commit the generated image

Of course, we want to use the image(s) in our repository. That’s why we are going to commit the generated image(s) into our repo:

1
2
3
4
5
6
7
8
9
10
11
12
      - name: Commit rendered diagrams
        run: |
          git config --global user.name "github-actions[bot]"
          git config --global user.email "github-actions[bot]@users.noreply.github.com"
          git add docs/*.svg

          if git diff --cached --quiet; then
            echo "No diagram changes to commit."
          else
            git commit -m "docs: auto-rendered PlantUML diagrams"
            git push
          fi

Conclusion

Just as we developers version control our code, we can also version control diagrams used in our documentation, wikis, or blog posts by saving them in our repositories. We can also use tools like PlantUML to describe the diagram with a markup language and use GitHub Actions to render the resulting diagram images. This process can be easily automated and ensures our diagrams are properly versioned alongside our code.

What’s your experience with Docs as Code? I’m curious which tools you’re using and whether you’ve automated diagram generation like this. Let’s discuss - drop a comment or reach out on social media!

As always, I hope this blog post is helpful for some of you.

Until the next post, happy coding, everyone!


The title image is the generated image from the sample repository for this blog post.

This post is licensed under CC BY 4.0 by the author.